144 lines
4.5 KiB
ObjectPascal
144 lines
4.5 KiB
ObjectPascal
unit Compiler.BuiltinPreproc;
|
|
|
|
{
|
|
Inno Setup
|
|
Copyright (C) 1997-2024 Jordan Russell
|
|
Portions by Martijn Laan
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
|
|
|
Built-in preprocessor
|
|
|
|
By default, scripts use ISPP if available, and .isl files use the built-in preprocessor
|
|
}
|
|
|
|
interface
|
|
|
|
uses
|
|
Shared.PreprocInt;
|
|
|
|
function BuiltinPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils, Classes, PathFunc,
|
|
Shared.CommonFunc, Compiler.Messages, Compiler.HelperFunc;
|
|
|
|
type
|
|
EBuiltinPreprocessScriptError = class(Exception);
|
|
|
|
function BuiltinPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
|
|
var
|
|
IncludeStack: TStringList;
|
|
|
|
procedure RaiseError(const LineFilename: String; const LineNumber: Integer;
|
|
const Msg: String);
|
|
begin
|
|
Params.ErrorProc(Params.CompilerData, PChar(Msg), PChar(LineFilename),
|
|
LineNumber, 0);
|
|
{ Note: This exception is caught and translated into ispePreprocessError }
|
|
raise EBuiltinPreprocessScriptError.Create('BuiltinPreprocessScript error');
|
|
end;
|
|
|
|
procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
|
|
forward;
|
|
|
|
procedure ProcessLinesFromFile(const LineFilename: String;
|
|
const LineNumber: Integer; const IncludeFilename: String);
|
|
var
|
|
I: Integer;
|
|
FileHandle: TPreprocFileHandle;
|
|
begin
|
|
{ Check if it's a recursive include }
|
|
for I := 0 to IncludeStack.Count-1 do
|
|
if PathCompare(IncludeStack[I], IncludeFilename) = 0 then
|
|
RaiseError(LineFilename, LineNumber, Format(SCompilerRecursiveInclude,
|
|
[IncludeFilename]));
|
|
|
|
FileHandle := Params.LoadFileProc(Params.CompilerData,
|
|
PChar(IncludeFilename), PChar(LineFilename), LineNumber, 0);
|
|
if FileHandle < 0 then begin
|
|
{ Note: The message here shouldn't be seen as LoadFileProc should have
|
|
already called ErrorProc itself }
|
|
RaiseError(LineFilename, LineNumber, 'LoadFileProc failed');
|
|
end;
|
|
ProcessLines(IncludeFilename, FileHandle);
|
|
end;
|
|
|
|
procedure ProcessDirective(const LineFilename: String; const LineNumber: Integer;
|
|
D: String);
|
|
var
|
|
Dir, IncludeFilename: String;
|
|
begin
|
|
if Copy(D, 1, Length('include')) = 'include' then begin
|
|
Delete(D, 1, Length('include'));
|
|
if (D = '') or (D[1] > ' ') then
|
|
RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
|
|
D := TrimLeft(D);
|
|
if (Length(D) < 3) or (D[1] <> '"') or (PathLastChar(D)^ <> '"') then
|
|
RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
|
|
if LineFilename = '' then
|
|
Dir := Params.SourcePath
|
|
else
|
|
Dir := PathExtractPath(LineFilename);
|
|
IncludeFilename := Params.PrependDirNameProc(Params.CompilerData,
|
|
PChar(RemoveQuotes(D)), PChar(Dir), PChar(LineFilename), LineNumber, 0);
|
|
if IncludeFilename = '' then begin
|
|
{ Note: The message here shouldn't be seen as PrependDirNameProc
|
|
should have already called ErrorProc itself }
|
|
RaiseError(LineFilename, LineNumber, 'PrependDirNameProc failed');
|
|
end;
|
|
Params.StatusProc(Params.CompilerData,
|
|
PChar(Format(SBuiltinPreprocessStatusIncludingFile, [IncludeFilename])), False);
|
|
ProcessLinesFromFile(LineFilename, LineNumber, PathExpand(IncludeFilename));
|
|
end
|
|
else
|
|
RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
|
|
end;
|
|
|
|
procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
|
|
var
|
|
I: Integer;
|
|
LineText, L: PChar;
|
|
begin
|
|
IncludeStack.Add(Filename);
|
|
I := 0;
|
|
while True do begin
|
|
LineText := Params.LineInProc(Params.CompilerData, FileHandle, I);
|
|
if LineText = nil then
|
|
Break;
|
|
L := LineText;
|
|
SkipWhitespace(L);
|
|
if L^ = '#' then
|
|
ProcessDirective(Filename, I + 1, L + 1)
|
|
else
|
|
Params.LineOutProc(Params.CompilerData, PChar(Filename), I + 1,
|
|
LineText);
|
|
Inc(I);
|
|
end;
|
|
IncludeStack.Delete(IncludeStack.Count-1);
|
|
end;
|
|
|
|
begin
|
|
if (Params.Size <> SizeOf(Params)) or
|
|
(Params.InterfaceVersion <> 3) then begin
|
|
Result := ispeInvalidParam;
|
|
Exit;
|
|
end;
|
|
|
|
try
|
|
IncludeStack := TStringList.Create;
|
|
try
|
|
ProcessLines(Params.Filename, 0);
|
|
finally
|
|
IncludeStack.Free;
|
|
end;
|
|
Result := ispeSuccess;
|
|
except
|
|
Result := ispePreprocessError;
|
|
if not(ExceptObject is EBuiltinPreprocessScriptError) then
|
|
raise;
|
|
end;
|
|
end;
|
|
|
|
end. |