UIsxclassesParser.pas 9.2 KB

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