Compiler.BuiltinPreproc.pas 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. unit Compiler.BuiltinPreproc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2024 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Built-in preprocessor
  8. By default, scripts use ISPP if available, and .isl files use the built-in preprocessor
  9. }
  10. interface
  11. uses
  12. Shared.PreprocInt;
  13. function BuiltinPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
  14. implementation
  15. uses
  16. SysUtils, Classes, PathFunc,
  17. Shared.CommonFunc, Compiler.Messages, Compiler.HelperFunc;
  18. type
  19. EBuiltinPreprocessScriptError = class(Exception);
  20. function BuiltinPreprocessScript(var Params: TPreprocessScriptParams): Integer; stdcall;
  21. var
  22. IncludeStack: TStringList;
  23. procedure RaiseError(const LineFilename: String; const LineNumber: Integer;
  24. const Msg: String);
  25. begin
  26. Params.ErrorProc(Params.CompilerData, PChar(Msg), PChar(LineFilename),
  27. LineNumber, 0);
  28. { Note: This exception is caught and translated into ispePreprocessError }
  29. raise EBuiltinPreprocessScriptError.Create('BuiltinPreprocessScript error');
  30. end;
  31. procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
  32. forward;
  33. procedure ProcessLinesFromFile(const LineFilename: String;
  34. const LineNumber: Integer; const IncludeFilename: String);
  35. var
  36. I: Integer;
  37. FileHandle: TPreprocFileHandle;
  38. begin
  39. { Check if it's a recursive include }
  40. for I := 0 to IncludeStack.Count-1 do
  41. if PathCompare(IncludeStack[I], IncludeFilename) = 0 then
  42. RaiseError(LineFilename, LineNumber, Format(SCompilerRecursiveInclude,
  43. [IncludeFilename]));
  44. FileHandle := Params.LoadFileProc(Params.CompilerData,
  45. PChar(IncludeFilename), PChar(LineFilename), LineNumber, 0);
  46. if FileHandle < 0 then begin
  47. { Note: The message here shouldn't be seen as LoadFileProc should have
  48. already called ErrorProc itself }
  49. RaiseError(LineFilename, LineNumber, 'LoadFileProc failed');
  50. end;
  51. ProcessLines(IncludeFilename, FileHandle);
  52. end;
  53. procedure ProcessDirective(const LineFilename: String; const LineNumber: Integer;
  54. D: String);
  55. var
  56. Dir, IncludeFilename: String;
  57. begin
  58. if Copy(D, 1, Length('include')) = 'include' then begin
  59. Delete(D, 1, Length('include'));
  60. if (D = '') or (D[1] > ' ') then
  61. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  62. D := TrimLeft(D);
  63. if (Length(D) < 3) or (D[1] <> '"') or (PathLastChar(D)^ <> '"') then
  64. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  65. if LineFilename = '' then
  66. Dir := Params.SourcePath
  67. else
  68. Dir := PathExtractPath(LineFilename);
  69. IncludeFilename := Params.PrependDirNameProc(Params.CompilerData,
  70. PChar(RemoveQuotes(D)), PChar(Dir), PChar(LineFilename), LineNumber, 0);
  71. if IncludeFilename = '' then begin
  72. { Note: The message here shouldn't be seen as PrependDirNameProc
  73. should have already called ErrorProc itself }
  74. RaiseError(LineFilename, LineNumber, 'PrependDirNameProc failed');
  75. end;
  76. Params.StatusProc(Params.CompilerData,
  77. PChar(Format(SBuiltinPreprocessStatusIncludingFile, [IncludeFilename])), False);
  78. ProcessLinesFromFile(LineFilename, LineNumber, PathExpand(IncludeFilename));
  79. end
  80. else
  81. RaiseError(LineFilename, LineNumber, SCompilerInvalidDirective);
  82. end;
  83. procedure ProcessLines(const Filename: String; const FileHandle: TPreprocFileHandle);
  84. var
  85. I: Integer;
  86. LineText, L: PChar;
  87. begin
  88. IncludeStack.Add(Filename);
  89. I := 0;
  90. while True do begin
  91. LineText := Params.LineInProc(Params.CompilerData, FileHandle, I);
  92. if LineText = nil then
  93. Break;
  94. L := LineText;
  95. SkipWhitespace(L);
  96. if L^ = '#' then
  97. ProcessDirective(Filename, I + 1, L + 1)
  98. else
  99. Params.LineOutProc(Params.CompilerData, PChar(Filename), I + 1,
  100. LineText);
  101. Inc(I);
  102. end;
  103. IncludeStack.Delete(IncludeStack.Count-1);
  104. end;
  105. begin
  106. if (Params.Size <> SizeOf(Params)) or
  107. (Params.InterfaceVersion <> 3) then begin
  108. Result := ispeInvalidParam;
  109. Exit;
  110. end;
  111. try
  112. IncludeStack := TStringList.Create;
  113. try
  114. ProcessLines(Params.Filename, 0);
  115. finally
  116. IncludeStack.Free;
  117. end;
  118. Result := ispeSuccess;
  119. except
  120. Result := ispePreprocessError;
  121. if not(ExceptObject is EBuiltinPreprocessScriptError) then
  122. raise;
  123. end;
  124. end;
  125. end.