UIsxclassesParser.pas 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. unit UIsxclassesParser;
  2. interface
  3. uses
  4. Classes;
  5. type
  6. TIsxclassesParserStoredString = (ssLine, ssType, ssEnumValue, ssConstant, ssMemberName, ssMember, ssProperty);
  7. TIsxclassesParserStrings = array [TIsxclassesParserStoredString] of TStringList;
  8. TIsxclassesParser = class
  9. private
  10. FStrings: TIsxclassesParserStrings;
  11. public
  12. constructor Create;
  13. destructor Destroy; override;
  14. procedure Parse(const FileName: String);
  15. procedure SaveXML(const HeaderFileName, HeaderFileName2, FooterFileName, OutputFileName: String);
  16. procedure SaveWordLists(const OutputFileName: String);
  17. end;
  18. implementation
  19. uses
  20. Windows, SysUtils,
  21. PathFunc;
  22. constructor TIsxclassesParser.Create;
  23. begin
  24. inherited;
  25. for var I := Low(TIsxClassesParserStoredString) to High(TIsxClassesParserStoredString) do
  26. FStrings[I] := TStringList.Create;
  27. { Sorted for speed of IndexOf used below }
  28. FStrings[ssType].Duplicates := dupError;
  29. FStrings[ssType].Sorted := True;
  30. { Sorted for sanity checking of duplicates }
  31. FStrings[ssEnumValue].Duplicates := dupError;
  32. FStrings[ssEnumValue].Sorted := True;
  33. FStrings[ssConstant].Duplicates := dupError;
  34. FStrings[ssConstant].Sorted := True;
  35. { Sorted for ignoring duplicates }
  36. FStrings[ssMemberName].Duplicates := dupIgnore;
  37. FStrings[ssMemberName].Sorted := True;
  38. FStrings[ssMember].Duplicates := dupIgnore;
  39. FStrings[ssMember].Sorted := True;
  40. FStrings[ssProperty].Duplicates := dupIgnore;
  41. FStrings[ssProperty].Sorted := True;
  42. end;
  43. destructor TIsxclassesParser.Destroy;
  44. begin
  45. for var I := Low(TIsxClassesParserStoredString) to High(TIsxClassesParserStoredString) do
  46. FStrings[I].Free;
  47. inherited;
  48. end;
  49. procedure TIsxclassesParser.Parse(const FileName: String);
  50. { Also presents in ScriptFunc.pas - changed from AnsiString to String + check for [ added }
  51. function ExtractScriptFuncWithoutHeaderName(const ScriptFuncWithoutHeader: String): String;
  52. begin
  53. Result := ScriptFuncWithoutHeader;
  54. const C0: String = '[';
  55. const C1: String = '(';
  56. const C2: String = ':';
  57. const C3: String = ';';
  58. var P := Pos(C0, Result);
  59. if P = 0 then
  60. P := Pos(C1, Result);
  61. if P = 0 then
  62. P := Pos(C2, Result);
  63. if P = 0 then
  64. P := Pos(C3, Result);
  65. if P = 0 then
  66. raise Exception.CreateFmt('Invalid ScriptFuncWithoutHeader: %s', [Result]);
  67. Delete(Result, P, Maxint);
  68. end;
  69. begin
  70. var F: TextFile;
  71. AssignFile(F, FileName);
  72. Reset(F);
  73. try
  74. while not Eof(F) do begin
  75. var S: String;
  76. ReadLn(F, S);
  77. FStrings[ssLine].Add(S);
  78. var P := Pos('=', S);
  79. if P > 1 then begin
  80. { Remember type and if it's an enum also remember the enum values }
  81. FStrings[ssType].Add(Trim(Copy(S, 1, P-1)));
  82. Delete(S, 1, P+1);
  83. var N := Length(S);
  84. if (N > 3) and (S[1] = '(') and (S[N-1] = ')') and (S[N] = ';') then
  85. FStrings[ssEnumValue].Add(Copy(S, 2, N-3));
  86. Continue;
  87. end;
  88. P := Pos('{', S);
  89. if P <> 0 then begin
  90. { Remember constants }
  91. P := Pos(': ', S);
  92. if P <> 0 then begin
  93. Delete(S, 1, P+1);
  94. var N := Length(S);
  95. if (N > 2) and (S[N-1] = ' ') and (S[N] = '}') then
  96. FStrings[ssConstant].Add(Copy(S, 1, N-2));
  97. end;
  98. Continue;
  99. end;
  100. var Typ := ssMemberName;
  101. P := Pos('procedure ', S);
  102. if P = 0 then
  103. P := Pos('function ', S);
  104. if P = 0 then begin
  105. Typ := ssProperty;
  106. P := Pos('property ', S);
  107. end;
  108. if P <> 0 then begin
  109. if Typ = ssMemberName then
  110. FStrings[ssMember].Add(StringReplace(S.TrimLeft, 'const ', '', [rfReplaceAll]));
  111. Delete(S, 1, P-1);
  112. P := Pos(' ', S);
  113. Delete(S, 1, P);
  114. FStrings[Typ].Add(ExtractScriptFuncWithoutHeaderName(S));
  115. Continue;
  116. end;
  117. end;
  118. finally
  119. CloseFile(F);
  120. end;
  121. end;
  122. procedure TIsxclassesParser.SaveXML(const HeaderFileName, HeaderFileName2, FooterFileName, OutputFileName: String);
  123. procedure FCopyFile(const SourceFileName, DestFileName: String; AppendToDestFile: Boolean);
  124. begin
  125. var F1: TextFile;
  126. AssignFile(F1, SourceFileName);
  127. Reset(F1);
  128. try
  129. var F2: TextFile;
  130. AssignFile(F2, DestFileName);
  131. if AppendToDestFile then begin
  132. if FileExists(DestFileName) then
  133. Append(F2)
  134. else
  135. Reset(F2);
  136. end else
  137. Rewrite(F2);
  138. try
  139. while not Eof(F1) do begin
  140. var S: String;
  141. ReadLn(F1, S);
  142. WriteLn(F2, S);
  143. end;
  144. finally
  145. CloseFile(F2);
  146. end;
  147. finally
  148. CloseFile(F1);
  149. end;
  150. end;
  151. function FGetNextPart(var Text: PChar): String;
  152. begin
  153. case Text^ of
  154. #0:
  155. begin
  156. Result := '';
  157. end;
  158. #1..#32:
  159. begin
  160. var P := Text;
  161. Inc(Text);
  162. while CharInSet(Text^ , [#1..#32]) do
  163. Inc(Text);
  164. SetString(Result, P, Text - P);
  165. end;
  166. '(', ')', ',', '=', ':', ';', '[', ']', '{', '}':
  167. begin
  168. Result := Text^;
  169. Inc(Text);
  170. end;
  171. '0'..'9', 'A'..'Z', 'a'..'z', '_', '.':
  172. begin
  173. var P := Text;
  174. Inc(Text);
  175. while CharInSet(Text^ , ['0'..'9', 'A'..'Z', 'a'..'z', '_', '.']) do
  176. Inc(Text);
  177. SetString(Result, P, Text - P);
  178. end;
  179. else
  180. raise Exception.CreateFmt('Invalid symbol ''%s'' found', [Text^]);
  181. end;
  182. end;
  183. function FLinkTypes(const S: String): String;
  184. begin
  185. Result := '';
  186. var Text := PChar(S);
  187. var NextPart := FGetNextPart(Text);
  188. while NextPart <> '' do begin
  189. if FStrings[ssType].IndexOf(NextPart) >= 0 then begin
  190. if Result = '' then //start of line = object definition
  191. NextPart := '<a name="' + NextPart + '">' + NextPart + '</a>'
  192. else
  193. NextPart := '<anchorlink name="' + NextPart + '">' + NextPart + '</anchorlink>';
  194. end;
  195. Result := Result + NextPart;
  196. NextPart := FGetNextPart(Text);
  197. end;
  198. end;
  199. function FConvertLeadingSpacesToNbsp(const S: String): String;
  200. begin
  201. Result := S;
  202. var I := 1;
  203. while (I <= Length(Result)) and (Result[I] = ' ') do begin
  204. Delete(Result, I, 1);
  205. Insert('&nbsp;', Result, I);
  206. Inc(I, Length('&nbsp;'));
  207. end;
  208. end;
  209. begin
  210. FCopyFile(HeaderFileName, OutputFileName, False);
  211. var F: TextFile;
  212. AssignFile(F, OutputFileName);
  213. Append(F);
  214. try
  215. for var Typ in [ssType, ssEnumValue, ssConstant, ssMemberName, ssProperty] do begin
  216. for var S in FStrings[Typ] do begin
  217. var A := S.Split([', ']);
  218. for var S2 in A do begin
  219. if Typ = ssType then
  220. WriteLn(F, '<keyword value="' + S2 + '" anchor="' + S2 + '" />')
  221. else
  222. WriteLn(F, '<keyword value="' + S2 + '" />')
  223. end;
  224. end;
  225. end;
  226. WriteLn(F, '<keyword value="WizardForm" />');
  227. WriteLn(F, '<keyword value="UninstallProgressForm" />');
  228. finally
  229. CloseFile(F);
  230. end;
  231. FCopyFile(HeaderFileName2, OutputFileName, True);
  232. AssignFile(F, OutputFileName);
  233. Append(F);
  234. try
  235. WriteLn(F, '<p><br/><tt>');
  236. for var Line in FStrings[ssLine] do begin
  237. var S := FLinkTypes(Line);
  238. S := FConvertLeadingSpacesToNbsp(S);
  239. WriteLn(F, S, '<br/>');
  240. end;
  241. WriteLn(F, '</tt></p>');
  242. finally
  243. CloseFile(F);
  244. end;
  245. FCopyFile(FooterFileName, OutputFileName, True);
  246. end;
  247. procedure TIsxclassesParser.SaveWordLists(const OutputFileName: String);
  248. procedure WriteStringArray(const F: TextFile; const Name, Indent: String;
  249. const Values: TStrings; const NewLineLength: Integer;
  250. const AddQuotesAroundCommas: Boolean = True;
  251. const ArrayType: String = 'array of AnsiString');
  252. begin
  253. WriteLn(F, Indent + Name + ': ' + ArrayType + ' = [');
  254. var S: String;
  255. for var I := 0 to Values.Count-1 do begin
  256. if S <> '' then
  257. S := S + ', ';
  258. var V := Values[I];
  259. if AddQuotesAroundCommas then begin
  260. V := StringReplace(V, ', ', ',', [rfReplaceAll]);
  261. V := StringReplace(V, ',', ''', ''', [rfReplaceAll]);
  262. end;
  263. S := S + '''' + V + '''';
  264. if Length(S) > NewLineLength then begin
  265. if I <> Values.Count-1 then
  266. S := S + ',';
  267. WriteLn(F, Indent + Indent + S);
  268. S := '';
  269. end;
  270. end;
  271. if S <> '' then
  272. WriteLn(F, Indent + Indent + S);
  273. WriteLn(F, Indent + '];');
  274. end;
  275. begin
  276. var F: TextFile;
  277. AssignFile(F, OutputFileName);
  278. Rewrite(F);
  279. try
  280. const Indent = ' ';
  281. WriteLn(F, 'unit ' + PathChangeExt(PathExtractName(OutputFileName), '') + ';');
  282. WriteLn(F);
  283. WriteLn(F, '{ This file is automatically generated by ISHelpGen. Do not edit. }');
  284. WriteLn(F);
  285. WriteLn(F, 'interface');
  286. WriteLn(F);
  287. WriteLn(F, 'uses');
  288. WriteLn(F, Indent + 'Shared.ScriptFunc;');
  289. WriteLn(F);
  290. WriteLn(F, 'var');
  291. WriteStringArray(F, 'PascalConstants_Isxclasses', Indent, FStrings[ssConstant], 0);
  292. WriteLn(F);
  293. WriteStringArray(F, 'PascalTypes_Isxclasses', Indent, FStrings[ssType], 80);
  294. WriteLn(F);
  295. WriteStringArray(F, 'PascalEnumValues_Isxclasses', Indent, FStrings[ssEnumValue], 0);
  296. WriteLn(F);
  297. WriteStringArray(F, 'PascalMembers_Isxclasses', Indent, FStrings[ssMember], 0, False, 'TScriptTable');
  298. WriteLn(F);
  299. WriteStringArray(F, 'PascalProperties_Isxclasses', Indent, FStrings[ssProperty], 80);
  300. WriteLn(F);
  301. WriteLN(F, 'implementation');
  302. WriteLn(F);
  303. Write(F, 'end.');
  304. finally
  305. CloseFile(F);
  306. end;
  307. end;
  308. end.