Inno-Setup-issrc/Projects/Src/ISPP.Preprocess.pas

308 lines
8.3 KiB
ObjectPascal
Raw Permalink Normal View History

2012-05-09 16:52:22 +02:00
{
Inno Setup Preprocessor
Copyright (C) 2001-2002 Alex Yackimoff
2020-08-29 16:34:04 +02:00
Inno Setup
Copyright (C) 1997-2024 Jordan Russell
2020-08-29 16:34:04 +02:00
Portions by Martijn Laan
For conditions of distribution and use, see LICENSE.TXT.
2012-05-09 16:52:22 +02:00
}
unit ISPP.Preprocess;
2012-05-09 16:52:22 +02:00
interface
uses
2024-08-04 19:59:25 +02:00
Shared.PreprocInt;
2012-05-09 16:52:22 +02:00
function ISPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
implementation
uses
2024-08-04 19:59:25 +02:00
SysUtils, Shared.CommonFunc, PathFunc,
ISPP.Base, ISPP.Preprocessor, ISPP.Sessions, ISPP.Intf,
ISPP.IdentMan, ISPP.VarUtils, ISPP.Consts;
2012-05-09 16:52:22 +02:00
2016-03-01 17:41:15 +01:00
procedure ReadScript(const Params: TPreprocessScriptParams;
2012-05-09 16:52:22 +02:00
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;
2012-05-09 16:52:22 +02:00
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
2012-05-09 16:52:22 +02:00
else if OptName = 'ISPP:InlineEnd' then
ISPPOptions.InlineEnd := OptValue
2012-05-09 16:52:22 +02:00
else if OptName = 'ISPP:Definitions' then
Definitions := OptValue
else if OptName = 'ISPP:IncludePath' then
IncludePath := OptValue
else if OptName = 'ISPP:IncludeFiles' then
IncludeFiles := OptValue
2012-05-09 16:52:22 +02:00
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;
2012-05-09 16:52:22 +02:00
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;
2012-05-09 16:52:22 +02:00
begin
Result := True;
while Definitions^ <> #0 do begin
DelimPos := StrScan(Definitions, #1);
if DelimPos = nil then begin
Result := False;
Break;
2012-05-09 16:52:22 +02:00
end;
N := DelimPos - Definitions;
if N > 0 then begin
SetString(Definition, Definitions, N);
ParseDefinition(Definition);
end;
Inc(Definitions, N + 1);
2012-05-09 16:52:22 +02:00
end;
end;
2020-08-28 14:39:30 +02:00
function IncludeBuiltinsAndParseIncludeFiles(BuiltinsDir: String; IncludeFiles: PChar; Options: TOptions): Boolean;
2016-03-01 17:41:15 +01:00
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;
2020-08-09 01:49:07 +02:00
procedure Include(FileName: String; Builtins: Boolean);
2016-03-01 17:41:15 +01:00
begin
if not GetOption(Options, 'P') then
FileName := Escape(FileName);
2020-08-09 01:49:07 +02:00
Preprocessor.IncludeFile(FileName, Builtins, False, True);
2016-03-01 17:41:15 +01:00
end;
const
SBuiltins = {$IFDEF DEBUG} '..\..\Files\ISPPBuiltins.iss' {$ELSE} 'ISPPBuiltins.iss' {$ENDIF};
2016-03-01 17:41:15 +01:00
var
DelimPos: PChar;
N: Integer;
IncludeFile: String;
begin
Result := True;
IncludeFile := BuiltinsDir + SBuiltins;
if FileExists(IncludeFile) then
2020-08-09 01:49:07 +02:00
Include(IncludeFile, True)
2016-03-01 17:41:15 +01:00
else
2020-08-09 01:49:07 +02:00
Preprocessor.WarningMsg(SFileNotFound, [SBuiltins]);
2016-03-01 17:41:15 +01:00
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);
2020-08-09 01:49:07 +02:00
Include(IncludeFile, False);
2016-03-01 17:41:15 +01:00
end;
Inc(IncludeFiles, N + 1);
end;
end;
2012-05-09 16:52:22 +02:00
var
SourcePath, CompilerPath, LineFilename, LineText: string;
LineNumber: Integer;
begin
if (Params.Size <> SizeOf(Params)) or
(Params.InterfaceVersion <> 3) then
2012-05-09 16:52:22 +02:00
begin
Result := ispeInvalidParam;
Exit;
end;
SourcePath := Params.SourcePath;
CompilerPath := Params.CompilerPath;
ISPPOptions := DefaultOptions;
Definitions := '';
IncludePath := RemoveBackslashUnlessRoot(CompilerPath);
IncludeFiles := '';
2012-05-09 16:52:22 +02:00
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
2020-08-28 14:39:30 +02:00
not IncludeBuiltinsAndParseIncludeFiles(Params.CompilerPath, PChar(IncludeFiles),
Preprocessor.FOptions.ParserOptions.Options) then
2016-03-01 17:41:15 +01:00
begin
Result := ispeInvalidParam;
Exit;
end;
ReadScript(Params, Preprocessor);
2012-05-09 16:52:22 +02:00
Preprocessor.Stack.Resolved;
if not GetOption(Preprocessor.FOptions.Options, 'C') then
Result := ispeSilentAbort
else
begin
Preprocessor.GetNextOutputLineReset;
2020-08-29 16:34:04 +02:00
while Preprocessor.GetNextOutputLine(LineFilename, LineNumber, LineText) do
2012-05-09 16:52:22 +02:00
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
2020-08-09 02:12:29 +02:00
Params.ErrorProc(Params.CompilerData, PChar(E.Message),
2012-05-09 16:52:22 +02:00
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.