308 lines
8.3 KiB
ObjectPascal
308 lines
8.3 KiB
ObjectPascal
{
|
|
Inno Setup Preprocessor
|
|
Copyright (C) 2001-2002 Alex Yackimoff
|
|
|
|
Inno Setup
|
|
Copyright (C) 1997-2024 Jordan Russell
|
|
Portions by Martijn Laan
|
|
For conditions of distribution and use, see LICENSE.TXT.
|
|
}
|
|
|
|
unit ISPP.Preprocess;
|
|
|
|
interface
|
|
|
|
uses
|
|
Shared.PreprocInt;
|
|
|
|
function ISPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils, Shared.CommonFunc, PathFunc,
|
|
ISPP.Base, ISPP.Preprocessor, ISPP.Sessions, ISPP.Intf,
|
|
ISPP.IdentMan, ISPP.VarUtils, ISPP.Consts;
|
|
|
|
procedure ReadScript(const Params: TPreprocessScriptParams;
|
|
const Preprocessor: TPreprocessor);
|
|
var
|
|
I: Integer;
|
|
LineText: PChar;
|
|
LineTextStr: String;
|
|
begin
|
|
I := 0;
|
|
while True do
|
|
begin
|
|
LineText := Params.LineInProc(Params.CompilerData, 0, I);
|
|
if LineText = nil then
|
|
Break;
|
|
LineTextStr := LineText;
|
|
Preprocessor.QueueLine(LineTextStr);
|
|
Inc(I);
|
|
end;
|
|
end;
|
|
|
|
function CleanupProc(CleanupProcData: Pointer): Integer; stdcall;
|
|
begin
|
|
if PopPreproc = nil then
|
|
Result := 0
|
|
else
|
|
Result := 1; { should never get here }
|
|
end;
|
|
|
|
function DecodeStringOptions(const S: String; var Options: TOptions): Boolean;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Options := [];
|
|
Result := True;
|
|
for I := 1 to Length(S) do begin
|
|
case S[I] of
|
|
'a'..'z': Include(Options, Ord(S[I]) - Ord('a'));
|
|
else
|
|
Result := False;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function ISPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
|
|
const
|
|
Delta = Ord('a');
|
|
DefaultOptions: TIsppOptions =
|
|
(ParserOptions: (Options: [Ord('b') - Delta, Ord('p') - Delta]);
|
|
Options: [Ord('c') - Delta, Ord('e') - Delta]; VerboseLevel: 0;
|
|
InlineStart: '{#'; InlineEnd: '}'; SpanSymbol: #0);
|
|
var
|
|
ISPPOptions: TIsppOptions;
|
|
Definitions, IncludePath, IncludeFiles: String;
|
|
Preprocessor: TPreprocessor;
|
|
V: TIsppVariant;
|
|
|
|
function ParseOption(const OptName, OptValue: String): Boolean;
|
|
begin
|
|
Result := True;
|
|
if OptName = 'ISPP:ParserOptions' then
|
|
Result := DecodeStringOptions(OptValue, ISPPOptions.ParserOptions.Options)
|
|
else if OptName = 'ISPP:Options' then
|
|
Result := DecodeStringOptions(OptValue, ISPPOptions.Options)
|
|
else if OptName = 'ISPP:VerboseLevel' then
|
|
ISPPOptions.VerboseLevel := StrToIntDef(OptValue, 0)
|
|
else if OptName = 'ISPP:InlineStart' then
|
|
ISPPOptions.InlineStart := OptValue
|
|
else if OptName = 'ISPP:InlineEnd' then
|
|
ISPPOptions.InlineEnd := OptValue
|
|
else if OptName = 'ISPP:Definitions' then
|
|
Definitions := OptValue
|
|
else if OptName = 'ISPP:IncludePath' then
|
|
IncludePath := OptValue
|
|
else if OptName = 'ISPP:IncludeFiles' then
|
|
IncludeFiles := OptValue
|
|
else
|
|
Result := False;
|
|
end;
|
|
|
|
function ParseOptions(P: PChar): Boolean;
|
|
var
|
|
EqPos: PChar;
|
|
OptName: String;
|
|
begin
|
|
Result := True;
|
|
if P = nil then
|
|
Exit;
|
|
while P^ <> #0 do begin
|
|
EqPos := StrScan(P, '=');
|
|
if EqPos = nil then begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
SetString(OptName, P, EqPos - P);
|
|
P := EqPos + 1;
|
|
if not ParseOption(OptName, P) then begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
Inc(P, StrLen(P) + 1);
|
|
end;
|
|
end;
|
|
|
|
function ParseDefinitions(Definitions: PChar; VarMan: TIdentManager): Boolean;
|
|
|
|
procedure ParseDefinition(const S: string);
|
|
var
|
|
I: Integer;
|
|
Name, V: string;
|
|
Value: TIsppVariant;
|
|
begin
|
|
Value := NULL;
|
|
I := Pos('=', S);
|
|
if I > 0 then
|
|
begin
|
|
Name := Copy(S, 1, I - 1);
|
|
V := Copy(S, I + 1, MaxInt);
|
|
if V <> '' then
|
|
MakeStr(Value, V)
|
|
end
|
|
else
|
|
Name := Trim(S);
|
|
VarMan.DefineVariable(Name, -1, Value, dsPublic);
|
|
end;
|
|
|
|
var
|
|
DelimPos: PChar;
|
|
N: Integer;
|
|
Definition: string;
|
|
begin
|
|
Result := True;
|
|
while Definitions^ <> #0 do begin
|
|
DelimPos := StrScan(Definitions, #1);
|
|
if DelimPos = nil then begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
N := DelimPos - Definitions;
|
|
if N > 0 then begin
|
|
SetString(Definition, Definitions, N);
|
|
ParseDefinition(Definition);
|
|
end;
|
|
Inc(Definitions, N + 1);
|
|
end;
|
|
end;
|
|
|
|
function IncludeBuiltinsAndParseIncludeFiles(BuiltinsDir: String; IncludeFiles: PChar; Options: TOptions): Boolean;
|
|
|
|
function Escape(const S: string): string;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := '';
|
|
for I := 1 to Length(S) do
|
|
begin
|
|
Result := Result + S[I];
|
|
if S[I] = '\' then Result := Result + '\';
|
|
end;
|
|
end;
|
|
|
|
procedure Include(FileName: String; Builtins: Boolean);
|
|
begin
|
|
if not GetOption(Options, 'P') then
|
|
FileName := Escape(FileName);
|
|
Preprocessor.IncludeFile(FileName, Builtins, False, True);
|
|
end;
|
|
|
|
const
|
|
SBuiltins = {$IFDEF DEBUG} '..\..\Files\ISPPBuiltins.iss' {$ELSE} 'ISPPBuiltins.iss' {$ENDIF};
|
|
var
|
|
DelimPos: PChar;
|
|
N: Integer;
|
|
IncludeFile: String;
|
|
begin
|
|
Result := True;
|
|
IncludeFile := BuiltinsDir + SBuiltins;
|
|
if FileExists(IncludeFile) then
|
|
Include(IncludeFile, True)
|
|
else
|
|
Preprocessor.WarningMsg(SFileNotFound, [SBuiltins]);
|
|
while IncludeFiles^ <> #0 do begin
|
|
DelimPos := StrScan(IncludeFiles, #1);
|
|
if DelimPos = nil then begin
|
|
Result := False;
|
|
Break;
|
|
end;
|
|
N := DelimPos - IncludeFiles;
|
|
if N > 0 then begin
|
|
SetString(IncludeFile, IncludeFiles, N);
|
|
Include(IncludeFile, False);
|
|
end;
|
|
Inc(IncludeFiles, N + 1);
|
|
end;
|
|
end;
|
|
|
|
var
|
|
SourcePath, CompilerPath, LineFilename, LineText: string;
|
|
LineNumber: Integer;
|
|
begin
|
|
if (Params.Size <> SizeOf(Params)) or
|
|
(Params.InterfaceVersion <> 3) then
|
|
begin
|
|
Result := ispeInvalidParam;
|
|
Exit;
|
|
end;
|
|
|
|
SourcePath := Params.SourcePath;
|
|
CompilerPath := Params.CompilerPath;
|
|
|
|
ISPPOptions := DefaultOptions;
|
|
Definitions := '';
|
|
IncludePath := RemoveBackslashUnlessRoot(CompilerPath);
|
|
IncludeFiles := '';
|
|
if not ParseOptions(Params.Options) then
|
|
begin
|
|
Result := ispeInvalidParam;
|
|
Exit;
|
|
end;
|
|
|
|
{ Hack: push a dummy item onto the stack to defer deletion of temp. files }
|
|
PushPreproc(nil);
|
|
try
|
|
Preprocessor := TPreprocessor.Create(Params, nil, ISPPOptions, SourcePath,
|
|
CompilerPath, Params.Filename);
|
|
try
|
|
Preprocessor.IncludePath := IncludePath;
|
|
|
|
MakeStr(V, SourcePath);
|
|
Preprocessor.VarMan.DefineVariable('SourcePath', -1, V, dsPublic);
|
|
|
|
MakeStr(V, CompilerPath);
|
|
Preprocessor.VarMan.DefineVariable('CompilerPath', -1, V, dsPublic);
|
|
|
|
MakeInt(V, Params.CompilerBinVersion);
|
|
Preprocessor.VarMan.DefineVariable('Ver', -1, V, dsPublic);
|
|
|
|
if not ParseDefinitions(PChar(Definitions), Preprocessor.VarMan) or
|
|
not IncludeBuiltinsAndParseIncludeFiles(Params.CompilerPath, PChar(IncludeFiles),
|
|
Preprocessor.FOptions.ParserOptions.Options) then
|
|
begin
|
|
Result := ispeInvalidParam;
|
|
Exit;
|
|
end;
|
|
|
|
ReadScript(Params, Preprocessor);
|
|
Preprocessor.Stack.Resolved;
|
|
|
|
if not GetOption(Preprocessor.FOptions.Options, 'C') then
|
|
Result := ispeSilentAbort
|
|
else
|
|
begin
|
|
Preprocessor.GetNextOutputLineReset;
|
|
while Preprocessor.GetNextOutputLine(LineFilename, LineNumber, LineText) do
|
|
Params.LineOutProc(Params.CompilerData, PChar(LineFilename),
|
|
LineNumber, PChar(LineText));
|
|
Result := ispeSuccess;
|
|
end;
|
|
finally
|
|
Preprocessor.Free;
|
|
end;
|
|
except
|
|
on E: EPreprocError do {preprocessor (syntax most likely) error}
|
|
begin
|
|
Params.ErrorProc(Params.CompilerData, PChar(E.Message),
|
|
PChar(E.FileName), E.LineNumber, E.ColumnNumber);
|
|
Result := ispePreprocessError;
|
|
end;
|
|
on E: Exception do
|
|
begin
|
|
Params.ErrorProc(Params.CompilerData,
|
|
PChar(Format('Unexpected exception of class %s in ISPP.' +
|
|
#13#10#13#10'%s.', [E.ClassName, E.Message])), nil, 0, 0);
|
|
Result := ispePreprocessError;
|
|
end;
|
|
end;
|
|
if Result = ispeSuccess then
|
|
Params.PreprocCleanupProc := CleanupProc
|
|
else
|
|
PopPreproc;
|
|
end;
|
|
|
|
end.
|