ISCC.dpr 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. program ISCC;
  2. {$APPTYPE CONSOLE}
  3. {
  4. Inno Setup
  5. Copyright (C) 1997-2025 Jordan Russell
  6. Portions by Martijn Laan
  7. For conditions of distribution and use, see LICENSE.TXT.
  8. Command-line compiler
  9. }
  10. {x$DEFINE STATICCOMPILER}
  11. { For debugging purposes, remove the 'x' to have it link the compiler code
  12. into this program and not depend on ISCmplr.dll. You will also need to add the
  13. ..\Components and Src folders to the Delphi Compiler Search path in the project
  14. options. Also see IDE.MainForm's STATICCOMPILER and Compiler.Compile's STATICPREPROC. }
  15. uses
  16. SafeDLLPath in '..\Components\SafeDLLPath.pas',
  17. Windows,
  18. SysUtils,
  19. Classes,
  20. {$IFDEF STATICCOMPILER} Compiler.Compile, {$ENDIF}
  21. PathFunc in '..\Components\PathFunc.pas',
  22. TrustFunc in '..\Components\TrustFunc.pas',
  23. Shared.CommonFunc in 'Src\Shared.CommonFunc.pas',
  24. Shared.CompilerInt in 'Src\Shared.CompilerInt.pas',
  25. Shared.CompilerInt.Struct in 'Src\Shared.CompilerInt.Struct.pas',
  26. Shared.FileClass in 'Src\Shared.FileClass.pas',
  27. Shared.ConfigIniFile in 'Src\Shared.ConfigIniFile.pas',
  28. Shared.SignToolsFunc in 'Src\Shared.SignToolsFunc.pas',
  29. Shared.LicenseFunc in 'Src\Shared.LicenseFunc.pas',
  30. Shared.Int64Em in 'Src\Shared.Int64Em.pas',
  31. SHA256 in '..\Components\SHA256.pas',
  32. ECDSA in '..\Components\ECDSA.pas',
  33. ISSigFunc in '..\Components\ISSigFunc.pas',
  34. StringScanner in '..\Components\StringScanner.pas';
  35. {$SETPEOSVERSION 6.1}
  36. {$SETPESUBSYSVERSION 6.1}
  37. {$WEAKLINKRTTI ON}
  38. {$R Res\ISCC.manifest.res}
  39. {$R Res\ISCC.versionandicon.res}
  40. type
  41. PScriptLine = ^TScriptLine;
  42. TScriptLine = record
  43. LineText: String;
  44. Next: PScriptLine;
  45. end;
  46. TOptionID = 0..25;
  47. TOptions = packed set of TOptionID;
  48. TIsppOptions = packed record
  49. ParserOptions: TOptions;
  50. Options: TOptions;
  51. VerboseLevel: Byte;
  52. InlineStart: string[7];
  53. InlineEnd: string[7];
  54. SpanSymbol: AnsiChar;
  55. end;
  56. var
  57. StdOutHandle, StdErrHandle: THandle;
  58. StdOutHandleIsConsole, StdErrHandleIsConsole: Boolean;
  59. ScriptFilename: String;
  60. Definitions, IncludePath, IncludeFiles, Output, OutputPath, OutputFilename: String;
  61. SignTools: TStringList;
  62. ScriptLines, NextScriptLine: PScriptLine;
  63. CurLine: String;
  64. StartTime, EndTime: DWORD;
  65. Quiet, ShowProgress, WantAbort: Boolean;
  66. ProgressPoint: TPoint;
  67. LastProgress: String;
  68. IsppOptions: TIsppOptions;
  69. IsppMode: Boolean;
  70. procedure WriteToStdHandle(const Handle: THandle; const HandleIsConsole: Boolean; S: String);
  71. begin
  72. if Copy(S, 1, 1) <> #13 then
  73. S := S + #13#10;
  74. if HandleIsConsole then begin
  75. var CharsWritten: DWORD;
  76. WriteConsole(Handle, @S[1], Length(S), CharsWritten, nil);
  77. end else begin
  78. var Utf8S := Utf8Encode(S);
  79. var BytesWritten: DWORD;
  80. WriteFile(Handle, Utf8S[1], Length(Utf8S), BytesWritten, nil);
  81. end;
  82. end;
  83. procedure WriteStdOut(const S: String; const Warning: Boolean = False);
  84. var
  85. CSBI: TConsoleScreenBufferInfo;
  86. DidSetColor: Boolean;
  87. begin
  88. DidSetColor := Warning and StdOutHandleIsConsole and GetConsoleScreenBufferInfo(StdOutHandle, CSBI) and
  89. SetConsoleTextAttribute(StdOutHandle, FOREGROUND_INTENSITY or FOREGROUND_RED or FOREGROUND_GREEN);
  90. try
  91. WriteToStdHandle(StdOutHandle, StdOutHandleIsConsole, S);
  92. finally
  93. if DidSetColor then
  94. SetConsoleTextAttribute(StdOutHandle, CSBI.wAttributes);
  95. end;
  96. end;
  97. procedure WriteStdErr(const S: String; const Error: Boolean = False);
  98. var
  99. CSBI: TConsoleScreenBufferInfo;
  100. DidSetColor: Boolean;
  101. begin
  102. DidSetColor := Error and StdErrHandleIsConsole and GetConsoleScreenBufferInfo(StdErrHandle, CSBI) and
  103. SetConsoleTextAttribute(StdErrHandle, FOREGROUND_INTENSITY or FOREGROUND_RED);
  104. try
  105. WriteToStdHandle(StdErrHandle, StdErrHandleIsConsole, S);
  106. finally
  107. if DidSetColor then
  108. SetConsoleTextAttribute(StdErrHandle, CSBI.wAttributes);
  109. end;
  110. end;
  111. function GetCursorPos: TPoint;
  112. var
  113. CSBI: TConsoleScreenBufferInfo;
  114. begin
  115. if not StdOutHandleIsConsole or not GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then
  116. Exit;
  117. Result.X := CSBI.dwCursorPosition.X;
  118. Result.Y := CSBI.dwCursorPosition.Y;
  119. end;
  120. procedure SetCursorPos(const P: TPoint);
  121. var
  122. Coords: TCoord;
  123. CSBI: TConsoleScreenBufferInfo;
  124. begin
  125. if not StdOutHandleIsConsole or not GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then
  126. Exit;
  127. if P.X < 0 then Exit;
  128. if P.Y < 0 then Exit;
  129. if P.X > CSBI.dwSize.X then Exit;
  130. if P.Y > CSBI.dwSize.Y then Exit;
  131. Coords.X := P.X;
  132. Coords.Y := P.Y;
  133. SetConsoleCursorPosition(StdOutHandle, Coords);
  134. end;
  135. procedure WriteProgress(const S: String);
  136. var
  137. CSBI: TConsoleScreenBufferInfo;
  138. Str: String;
  139. begin
  140. if StdOutHandleIsConsole and GetConsoleScreenBufferInfo(StdOutHandle, CSBI) then begin
  141. if Length(S) > CSBI.dwSize.X then
  142. Str := Copy(S, 1, CSBI.dwSize.X)
  143. else
  144. Str := Format('%-' + IntToStr(CSBI.dwSize.X) + 's', [S]);
  145. end else
  146. Str := S;
  147. WriteToStdHandle(StdOutHandle, StdOutHandleIsConsole, Str);
  148. end;
  149. function ConsoleCtrlHandler(dwCtrlType: DWORD): BOOL; stdcall;
  150. begin
  151. { Abort gracefully when Ctrl+C/Break is pressed }
  152. WantAbort := True;
  153. Result := True;
  154. end;
  155. procedure ReadScriptLines(const F: TTextFileReader);
  156. var
  157. LineNumber: Integer;
  158. PrevLine, L: PScriptLine;
  159. begin
  160. LineNumber := 1;
  161. PrevLine := nil;
  162. while not F.Eof do begin
  163. New(L);
  164. try
  165. L.LineText := F.ReadLine;
  166. if Pos(#0, L.LineText) <> 0 then
  167. raise Exception.CreateFmt('Illegal null character on line %d', [LineNumber]);
  168. L.Next := nil;
  169. except
  170. Dispose(L);
  171. raise;
  172. end;
  173. if Assigned(PrevLine) then
  174. PrevLine.Next := L
  175. else begin
  176. ScriptLines := L;
  177. NextScriptLine := L;
  178. end;
  179. PrevLine := L;
  180. Inc(LineNumber);
  181. end;
  182. end;
  183. procedure FreeScriptLines;
  184. var
  185. L, NextLine: PScriptLine;
  186. begin
  187. L := ScriptLines;
  188. ScriptLines := nil;
  189. NextScriptLine := nil;
  190. while Assigned(L) do begin
  191. NextLine := L.Next;
  192. Dispose(L);
  193. L := NextLine;
  194. end;
  195. end;
  196. function CompilerCallbackProc(Code: Integer; var Data: TCompilerCallbackData;
  197. AppData: Longint): Integer; stdcall;
  198. procedure PrintProgress(Progress: String);
  199. var
  200. Pt: TPoint;
  201. begin
  202. if (Progress = '') or (LastProgress = Progress) then
  203. Exit;
  204. Pt := GetCursorPos;
  205. if Pt.Y <= ProgressPoint.Y then
  206. Exit
  207. else if ProgressPoint.X < 0 then begin
  208. ProgressPoint := Pt;
  209. WriteStdOut('');
  210. Pt := GetCursorPos;
  211. end;
  212. SetCursorPos(ProgressPoint);
  213. WriteProgress(#13 + Progress);
  214. LastProgress := Progress;
  215. SetCursorPos(Pt);
  216. end;
  217. var
  218. S, BytesCompressedPerSecond, SecondsRemaining: String;
  219. begin
  220. if WantAbort then begin
  221. Result := iscrRequestAbort;
  222. Exit;
  223. end;
  224. Result := iscrSuccess;
  225. case Code of
  226. iscbReadScript: begin
  227. { Note: In Inno Setup 3.0.1 and later we can ignore Data.Reset since
  228. it is only True once (when reading the first line). }
  229. if Assigned(NextScriptLine) then begin
  230. CurLine := NextScriptLine.LineText;
  231. NextScriptLine := NextScriptLine.Next;
  232. Data.LineRead := PChar(CurLine);
  233. end;
  234. end;
  235. iscbNotifyStatus:
  236. if not Quiet then
  237. WriteStdOut(Data.StatusMsg, Data.Warning)
  238. else if ShowProgress then
  239. PrintProgress(Trim(Data.StatusMsg));
  240. iscbNotifySuccess: begin
  241. EndTime := GetTickCount;
  242. if not Quiet then begin
  243. WriteStdOut('');
  244. if Data.OutputExeFilename <> '' then begin
  245. WriteStdOut(Format('Successful compile (%.3f sec). ' +
  246. 'Resulting Setup program filename is:',
  247. [(EndTime - StartTime) / 1000]));
  248. WriteStdOut(Data.OutputExeFilename);
  249. end else
  250. WriteStdOut(Format('Successful compile (%.3f sec). ' +
  251. 'Output was disabled.',
  252. [(EndTime - StartTime) / 1000]));
  253. end;
  254. end;
  255. iscbNotifyError:
  256. if Assigned(Data.ErrorMsg) then begin
  257. S := 'Error';
  258. if Data.ErrorLine <> 0 then
  259. S := S + Format(' on line %d', [Data.ErrorLine]);
  260. if Assigned(Data.ErrorFilename) then
  261. S := S + ' in ' + Data.ErrorFilename
  262. else if ScriptFilename <> '' then
  263. S := S + ' in ' + ScriptFilename;
  264. S := S + ': ' + Data.ErrorMsg;
  265. WriteStdErr(S, True);
  266. end;
  267. iscbNotifyIdle:
  268. if ShowProgress and (Data.CompressProgress <> 0) then begin
  269. if Data.BytesCompressedPerSecond <> 0 then
  270. BytesCompressedPerSecond := Format(' at %.2f kb/s', [Data.BytesCompressedPerSecond / 1024])
  271. else
  272. BytesCompressedPerSecond := '';
  273. if Data.SecondsRemaining <> -1 then
  274. SecondsRemaining := Format(', %d seconds remaining', [Data.SecondsRemaining])
  275. else
  276. SecondsRemaining := '';
  277. PrintProgress(Format('Compressing: %.2f%% done%s%s', [Data.CompressProgress / Data.CompressProgressMax * 100, BytesCompressedPerSecond, SecondsRemaining]));
  278. end;
  279. end;
  280. end;
  281. procedure ProcessCommandLine;
  282. procedure SetOption(var Options: TOptions; Option: Char; Value: Boolean);
  283. begin
  284. if Value then
  285. Include(Options, Ord(UpCase(Option)) - Ord('A'))
  286. else
  287. Exclude(Options, Ord(UpCase(Option)) - Ord('A'))
  288. end;
  289. procedure InitIsppOptions(var Opt: TIsppOptions; var Definitions, IncludePath, IncludeFiles: String);
  290. begin
  291. with Opt do begin
  292. SetOption(Options, 'C', True);
  293. SetOption(ParserOptions, 'B', True);
  294. SetOption(ParserOptions, 'P', True);
  295. VerboseLevel := 0;
  296. InlineStart := '{#';
  297. InlineEnd := '}';
  298. end;
  299. Definitions := 'ISCC_INVOKED'#1'ISPPCC_INVOKED'#1;
  300. IncludePath := ExtractFileDir(NewParamStr(0));
  301. IncludeFiles := '';
  302. end;
  303. procedure ReadOptionsParam(var Options: TOptions; Symbol: Char);
  304. var
  305. I: Integer;
  306. S: String;
  307. begin
  308. for I := 1 to NewParamCount do
  309. begin
  310. S := NewParamStr(I);
  311. if Length(S) = 4 then
  312. if ((S[1] = '/') or (S[1] = '-')) and (UpCase(S[2]) = Symbol) then
  313. case S[4] of
  314. '-': SetOption(Options, S[3], False);
  315. '+': SetOption(Options, S[3], True)
  316. else
  317. raise Exception.CreateFmt('Invalid command line option: %s', [S]);
  318. end;
  319. end;
  320. end;
  321. function IsParam(const S: String): Boolean;
  322. begin
  323. Result := (Length(S) >= 2) and ((S[1] = '/') or (S[1] = '-'));
  324. end;
  325. function GetParam(var S: String; Symbols: String): Boolean;
  326. begin
  327. Result := IsParam(S) and
  328. (CompareText(Copy(S, 2, Length(Symbols)), Symbols) = 0);
  329. if Result then
  330. S := Copy(S, 2 + Length(Symbols), MaxInt);
  331. end;
  332. function FindParam(var Index: Integer; Symbols: String): String;
  333. var
  334. I: Integer;
  335. S: String;
  336. begin
  337. for I := Index to NewParamCount do
  338. begin
  339. S := NewParamStr(I);
  340. if IsParam(S) and (CompareText(Copy(S, 2, Length(Symbols)), Symbols) = 0) then
  341. begin
  342. Result := Copy(S, 2 + Length(Symbols), MaxInt);
  343. Index := I + 1;
  344. Exit;
  345. end;
  346. end;
  347. Index := MaxInt;
  348. Result := '';
  349. end;
  350. procedure ShowBanner;
  351. begin
  352. WriteStdOut('Inno Setup 6 Command-Line Compiler');
  353. WriteStdOut('Copyright (C) 1997-2025 Jordan Russell. All rights reserved.');
  354. WriteStdOut('Portions Copyright (C) 2000-2025 Martijn Laan. All rights reserved.');
  355. if IsppMode then
  356. WriteStdOut('Portions Copyright (C) 2001-2004 Alex Yackimoff. All rights reserved.');
  357. WriteStdOut('https://www.innosetup.com');
  358. WriteStdOut('');
  359. end;
  360. procedure ShowUsage;
  361. begin
  362. WriteStdErr('Usage: iscc [options] scriptfile.iss');
  363. WriteStdErr('or to read from standard input: iscc [options] -');
  364. WriteStdErr('Options:');
  365. WriteStdErr(' /O(+|-) Enable or disable output (overrides Output)');
  366. WriteStdErr(' /O<path> Output files to specified path (overrides OutputDir)');
  367. WriteStdErr(' /F<filename> Specifies an output filename (overrides OutputBaseFilename)');
  368. WriteStdErr(' /S<name>=<command> Sets a SignTool with the specified name and command');
  369. WriteStdErr(' (Any Sign Tools configured using the Compiler IDE will be specified automatically)');
  370. WriteStdErr(' /Q Quiet compile (print error messages only)');
  371. WriteStdErr(' /Qp Enable quiet compile while still displaying progress');
  372. if IsppMode then begin
  373. WriteStdErr(' /D<name>[=<value>] Emulate #define public <name> <value>');
  374. WriteStdErr(' /$<letter>(+|-) Emulate #pragma option -<letter>(+|-)');
  375. WriteStdErr(' /P<letter>(+|-) Emulate #pragma parseroption -<letter>(+|-)');
  376. WriteStdErr(' /I<paths> Emulate #pragma include <paths>');
  377. WriteStdErr(' /J<filename> Emulate #include <filename>');
  378. WriteStdErr(' /{#<string> Emulate #pragma inlinestart <string>');
  379. WriteStdErr(' /}<string> Emulate #pragma inlineend <string>');
  380. WriteStdErr(' /V<number> Emulate #pragma verboselevel <number>');
  381. end;
  382. WriteStdErr(' /? Show this help screen');
  383. WriteStdErr('');
  384. WriteStdErr('Examples: iscc "c:\isetup\samples\my script.iss"');
  385. WriteStdErr(' iscc /Qp /O"My Output" /F"MyProgram-1.0" /Sbyparam=$p "c:\isetup\samples\my script.iss"');
  386. if IsppMode then begin
  387. WriteStdErr(' iscc /$c- /Pu+ "/DLic=Trial Lic.txt" /IC:\INC;D:\INC scriptfile.iss');
  388. WriteStdErr('');
  389. end;
  390. end;
  391. var
  392. I: Integer;
  393. S: String;
  394. begin
  395. if IsppMode then begin
  396. InitIsppOptions(IsppOptions, Definitions, IncludePath, IncludeFiles);
  397. { Also see below }
  398. ReadOptionsParam(IsppOptions.Options, '$');
  399. ReadOptionsParam(IsppOptions.ParserOptions, 'P');
  400. end;
  401. for I := 1 to NewParamCount do begin
  402. S := NewParamStr(I);
  403. if (S = '') or IsParam(S) then begin
  404. if GetParam(S, 'Q') then begin
  405. Quiet := True;
  406. ShowProgress := CompareText(S, 'P') = 0;
  407. end
  408. else if GetParam(S, 'O') then begin
  409. if S = '-' then Output := 'no'
  410. else if S = '+' then Output := 'yes'
  411. else OutputPath := S;
  412. end
  413. else if GetParam(S, 'F') then
  414. OutputFilename := S
  415. else if GetParam(S, 'S') then begin
  416. if Pos('=', S) = 0 then begin
  417. ShowBanner;
  418. WriteStdErr('Invalid option: ' + S, True);
  419. Halt(1);
  420. end;
  421. SignTools.Add(S);
  422. end else if IsppMode and GetParam(S, 'D') then begin
  423. Definitions := Definitions + S + #1;
  424. end
  425. else if IsppMode and GetParam(S, 'I') then begin
  426. IncludePath := IncludePath + ';' + S;
  427. end
  428. else if IsppMode and GetParam(S, 'J') then begin
  429. IncludeFiles := IncludeFiles + S + #1;
  430. end
  431. else if IsppMode and GetParam(S, '{#') then begin
  432. if S <> '' then IsppOptions.InlineStart := AnsiString(S);
  433. end
  434. else if IsppMode and GetParam(S, '}') then begin
  435. if S <> '' then IsppOptions.InlineEnd := AnsiString(S);
  436. end
  437. else if IsppMode and GetParam(S, 'V') then begin
  438. if S <> '' then IsppOptions.VerboseLevel := StrToIntDef(S, 0);
  439. end
  440. else if IsppMode and (GetParam(S, '$') or GetParam(S, 'P')) then begin
  441. { Already handled above }
  442. end
  443. else if S = '/?' then begin
  444. ShowBanner;
  445. ShowUsage;
  446. Halt(1);
  447. end
  448. else begin
  449. ShowBanner;
  450. WriteStdErr('Unknown option: ' + S, True);
  451. Halt(1);
  452. end;
  453. end
  454. else begin
  455. { Not a switch; must be the script filename }
  456. if ScriptFilename <> '' then begin
  457. ShowBanner;
  458. WriteStdErr('You may not specify more than one script filename.', True);
  459. Halt(1);
  460. end;
  461. ScriptFilename := S;
  462. end;
  463. end;
  464. if ScriptFilename = '' then begin
  465. ShowBanner;
  466. ShowUsage;
  467. Halt(1);
  468. end;
  469. if not Quiet then
  470. ShowBanner;
  471. end;
  472. procedure Go;
  473. procedure AppendOption(var Opts: String; const OptName, OptValue: String);
  474. begin
  475. Opts := Opts + OptName + '=' + OptValue + #0;
  476. end;
  477. function ConvertOptionsToString(const Options: TOptions): String;
  478. var
  479. I: TOptionID;
  480. begin
  481. Result := '';
  482. for I := 0 to 25 do
  483. if I in Options then
  484. Result := Result + Chr(Ord('a') + I);
  485. end;
  486. procedure IsppOptionsToString(var S: String; Opt: TIsppOptions; Definitions, IncludePath, IncludeFiles: String);
  487. begin
  488. with Opt do begin
  489. AppendOption(S, 'ISPP:ParserOptions', ConvertOptionsToString(ParserOptions));
  490. AppendOption(S, 'ISPP:Options', ConvertOptionsToString(Options));
  491. AppendOption(S, 'ISPP:VerboseLevel', IntToStr(VerboseLevel));
  492. AppendOption(S, 'ISPP:InlineStart', String(InlineStart));
  493. AppendOption(S, 'ISPP:InlineEnd', String(InlineEnd));
  494. end;
  495. AppendOption(S, 'ISPP:Definitions', Definitions);
  496. AppendOption(S, 'ISPP:IncludePath', IncludePath);
  497. AppendOption(S, 'ISPP:IncludeFiles', IncludeFiles);
  498. end;
  499. var
  500. ScriptPath: String;
  501. ExitCode: Integer;
  502. Ver: PCompilerVersionInfo;
  503. F: TTextFileReader;
  504. Params: TCompileScriptParamsEx;
  505. Options: String;
  506. Res: Integer;
  507. I: Integer;
  508. IDESignTools: TStringList;
  509. begin
  510. if ScriptFilename <> '-' then begin
  511. ScriptFilename := PathExpand(ScriptFilename);
  512. ScriptPath := PathExtractPath(ScriptFilename);
  513. end
  514. else begin
  515. { Read from standard input }
  516. ScriptFilename := '<stdin>';
  517. ScriptPath := GetCurrentDir;
  518. end;
  519. {$IFNDEF STATICCOMPILER}
  520. try
  521. InitISCmplrLibrary;
  522. except
  523. begin
  524. WriteStdErr(Format('Could not load %s: %s', [ISCmplrDLL, GetExceptMessage]), True);
  525. Halt(1);
  526. end;
  527. end;
  528. Ver := ISDllGetVersion;
  529. {$ELSE}
  530. Ver := ISGetVersion;
  531. {$ENDIF}
  532. if Ver.BinVersion < $05000500 then begin
  533. { 5.0.5 or later is required since we use TCompileScriptParamsEx }
  534. WriteStdErr('Incompatible compiler engine version.', True);
  535. Halt(1);
  536. end;
  537. ProgressPoint.X := -1;
  538. ExitCode := 0;
  539. try
  540. if ScriptFilename <> '<stdin>' then
  541. F := TTextFileReader.Create(ScriptFilename, fdOpenExisting, faRead, fsRead)
  542. else
  543. F := TTextFileReader.CreateWithExistingHandle(GetStdHandle(STD_INPUT_HANDLE));
  544. try
  545. ReadScriptLines(F);
  546. finally
  547. F.Free;
  548. end;
  549. if not Quiet then begin
  550. WriteStdOut('Compiler engine version: ' + String(Ver.Title) + ' ' + String(Ver.Version));
  551. if IsLicensed then
  552. WriteStdOut('Licensee name: ' + GetLicenseeDescription)
  553. else
  554. WriteStdOut(GetLicenseeDescription);
  555. WriteStdOut('');
  556. end;
  557. FillChar(Params, SizeOf(Params), 0);
  558. Params.Size := SizeOf(Params);
  559. Params.SourcePath := PChar(ScriptPath);
  560. Params.CallbackProc := CompilerCallbackProc;
  561. Options := '';
  562. if Output <> '' then
  563. AppendOption(Options, 'Output', Output);
  564. if OutputPath <> '' then
  565. AppendOption(Options, 'OutputDir', OutputPath);
  566. if OutputFilename <> '' then
  567. AppendOption(Options, 'OutputBaseFilename', OutputFilename);
  568. for I := 0 to SignTools.Count-1 do
  569. Options := Options + AddSignToolParam(SignTools[I]);
  570. IDESignTools := TStringList.Create;
  571. try
  572. { Also automatically read and add SignTools defined using the IDE. Adding
  573. these after the command line SignTools so that the latter are always
  574. found first by the compiler. }
  575. ReadSignTools(IDESignTools);
  576. for I := 0 to IDESignTools.Count-1 do
  577. Options := Options + AddSignToolParam(IDESignTools[I]);
  578. finally
  579. IDESignTools.Free;
  580. end;
  581. if IsppMode then
  582. IsppOptionsToString(Options, IsppOptions, Definitions, IncludePath, IncludeFiles);
  583. Params.Options := PChar(Options);
  584. StartTime := GetTickCount;
  585. {$IFNDEF STATICCOMPILER}
  586. Res := ISDllCompileScript(Params);
  587. {$ELSE}
  588. Res := ISCompileScript(Params, False);
  589. {$ENDIF}
  590. case Res of
  591. isceNoError: ;
  592. isceCompileFailure: begin
  593. ExitCode := 2;
  594. WriteStdErr('Compile aborted.', True);
  595. end;
  596. else
  597. ExitCode := 1;
  598. WriteStdErr(Format('Internal error: ISDllCompileScript returned ' +
  599. 'unexpected result (%d).', [Res]), True);
  600. end;
  601. finally
  602. FreeScriptLines;
  603. end;
  604. if ExitCode <> 0 then
  605. Halt(ExitCode);
  606. end;
  607. function ISPPInstalled: Boolean;
  608. begin
  609. Result := NewFileExists(PathExtractPath(NewParamStr(0)) + 'ISPP.dll');
  610. end;
  611. begin
  612. SignTools := TStringList.Create;
  613. try
  614. StdOutHandle := GetStdHandle(STD_OUTPUT_HANDLE);
  615. StdErrHandle := GetStdHandle(STD_ERROR_HANDLE);
  616. var Mode: DWORD;
  617. StdOutHandleIsConsole := GetConsoleMode(StdOutHandle, Mode);
  618. StdErrHandleIsConsole := GetConsoleMode(StdErrHandle, Mode);
  619. SetConsoleCtrlHandler(@ConsoleCtrlHandler, True);
  620. try
  621. ReadLicense;
  622. IsppMode := ISPPInstalled;
  623. ProcessCommandLine;
  624. Go;
  625. except
  626. { Show a friendlier exception message. (By default, Delphi prints out
  627. the exception class and address.) }
  628. WriteStdErr(GetExceptMessage, True);
  629. Halt(2);
  630. end;
  631. finally
  632. SignTools.Free;
  633. end;
  634. end.