2
0

UIsxclassesParser.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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
  105. P := Pos('constructor ', S);
  106. if P = 0 then begin
  107. Typ := ssProperty;
  108. P := Pos('property ', S);
  109. end;
  110. if P <> 0 then begin
  111. if Typ = ssMemberName then
  112. FStrings[ssMember].Add(StringReplace(S.TrimLeft, 'const ', '', [rfReplaceAll]));
  113. Delete(S, 1, P-1);
  114. P := Pos(' ', S);
  115. Delete(S, 1, P);
  116. FStrings[Typ].Add(ExtractScriptFuncWithoutHeaderName(S));
  117. Continue;
  118. end;
  119. end;
  120. finally
  121. CloseFile(F);
  122. end;
  123. end;
  124. procedure TIsxclassesParser.SaveXML(const HeaderFileName, HeaderFileName2, FooterFileName, OutputFileName: String);
  125. procedure FCopyFile(const SourceFileName, DestFileName: String; AppendToDestFile: Boolean);
  126. begin
  127. var F1: TextFile;
  128. AssignFile(F1, SourceFileName);
  129. Reset(F1);
  130. try
  131. var F2: TextFile;
  132. AssignFile(F2, DestFileName);
  133. if AppendToDestFile then begin
  134. if FileExists(DestFileName) then
  135. Append(F2)
  136. else
  137. Reset(F2);
  138. end else
  139. Rewrite(F2);
  140. try
  141. while not Eof(F1) do begin
  142. var S: String;
  143. ReadLn(F1, S);
  144. WriteLn(F2, S);
  145. end;
  146. finally
  147. CloseFile(F2);
  148. end;
  149. finally
  150. CloseFile(F1);
  151. end;
  152. end;
  153. function FGetNextPart(var Text: PChar): String;
  154. begin
  155. case Text^ of
  156. #0:
  157. begin
  158. Result := '';
  159. end;
  160. #1..#32:
  161. begin
  162. var P := Text;
  163. Inc(Text);
  164. while CharInSet(Text^ , [#1..#32]) do
  165. Inc(Text);
  166. SetString(Result, P, Text - P);
  167. end;
  168. '(', ')', ',', '=', ':', ';', '[', ']', '{', '}':
  169. begin
  170. Result := Text^;
  171. Inc(Text);
  172. end;
  173. '0'..'9', 'A'..'Z', 'a'..'z', '_', '.':
  174. begin
  175. var P := Text;
  176. Inc(Text);
  177. while CharInSet(Text^ , ['0'..'9', 'A'..'Z', 'a'..'z', '_', '.']) do
  178. Inc(Text);
  179. SetString(Result, P, Text - P);
  180. end;
  181. else
  182. raise Exception.CreateFmt('Invalid symbol ''%s'' found', [Text^]);
  183. end;
  184. end;
  185. function FLinkTypes(const S: String): String;
  186. begin
  187. Result := '';
  188. var Text := PChar(S);
  189. var NextPart := FGetNextPart(Text);
  190. while NextPart <> '' do begin
  191. if FStrings[ssType].IndexOf(NextPart) >= 0 then begin
  192. if Result = '' then //start of line = object definition
  193. NextPart := '<a name="' + NextPart + '">' + NextPart + '</a>'
  194. else
  195. NextPart := '<anchorlink name="' + NextPart + '">' + NextPart + '</anchorlink>';
  196. end;
  197. Result := Result + NextPart;
  198. NextPart := FGetNextPart(Text);
  199. end;
  200. end;
  201. function FConvertLeadingSpacesToNbsp(const S: String): String;
  202. begin
  203. Result := S;
  204. var I := 1;
  205. while (I <= Length(Result)) and (Result[I] = ' ') do begin
  206. Delete(Result, I, 1);
  207. Insert('&nbsp;', Result, I);
  208. Inc(I, Length('&nbsp;'));
  209. end;
  210. end;
  211. begin
  212. FCopyFile(HeaderFileName, OutputFileName, False);
  213. var F: TextFile;
  214. AssignFile(F, OutputFileName);
  215. Append(F);
  216. try
  217. for var Typ in [ssType, ssEnumValue, ssConstant, ssMemberName, ssProperty] do begin
  218. for var S in FStrings[Typ] do begin
  219. var A := S.Split([', ']);
  220. for var S2 in A do begin
  221. if Typ = ssType then
  222. WriteLn(F, '<keyword value="' + S2 + '" anchor="' + S2 + '" />')
  223. else
  224. WriteLn(F, '<keyword value="' + S2 + '" />')
  225. end;
  226. end;
  227. end;
  228. WriteLn(F, '<keyword value="WizardForm" />');
  229. WriteLn(F, '<keyword value="UninstallProgressForm" />');
  230. finally
  231. CloseFile(F);
  232. end;
  233. FCopyFile(HeaderFileName2, OutputFileName, True);
  234. AssignFile(F, OutputFileName);
  235. Append(F);
  236. try
  237. WriteLn(F, '<p><br/><tt>');
  238. for var Line in FStrings[ssLine] do begin
  239. var S := FLinkTypes(Line);
  240. S := FConvertLeadingSpacesToNbsp(S);
  241. WriteLn(F, S, '<br/>');
  242. end;
  243. WriteLn(F, '</tt></p>');
  244. finally
  245. CloseFile(F);
  246. end;
  247. FCopyFile(FooterFileName, OutputFileName, True);
  248. end;
  249. procedure TIsxclassesParser.SaveWordLists(const OutputFileName: String);
  250. procedure WriteStringArray(const F: TextFile; const Name, Indent: String;
  251. const Values: TStrings; const NewLineLength: Integer;
  252. const AddQuotesAroundCommas: Boolean = True;
  253. const ArrayType: String = 'array of AnsiString');
  254. begin
  255. WriteLn(F, Indent + Name + ': ' + ArrayType + ' = [');
  256. var S: String;
  257. for var I := 0 to Values.Count-1 do begin
  258. if S <> '' then
  259. S := S + ', ';
  260. var V := Values[I];
  261. if AddQuotesAroundCommas then begin
  262. V := StringReplace(V, ', ', ',', [rfReplaceAll]);
  263. V := StringReplace(V, ',', ''', ''', [rfReplaceAll]);
  264. end;
  265. S := S + '''' + V + '''';
  266. if Length(S) > NewLineLength then begin
  267. if I <> Values.Count-1 then
  268. S := S + ',';
  269. WriteLn(F, Indent + Indent + S);
  270. S := '';
  271. end;
  272. end;
  273. if S <> '' then
  274. WriteLn(F, Indent + Indent + S);
  275. WriteLn(F, Indent + '];');
  276. end;
  277. begin
  278. var F: TextFile;
  279. AssignFile(F, OutputFileName);
  280. Rewrite(F);
  281. try
  282. const Indent = ' ';
  283. WriteLn(F, 'unit ' + PathChangeExt(PathExtractName(OutputFileName), '') + ';');
  284. WriteLn(F);
  285. WriteLn(F, '{ This file is automatically generated by ISHelpGen. Do not edit. }');
  286. WriteLn(F);
  287. WriteLn(F, 'interface');
  288. WriteLn(F);
  289. WriteLn(F, 'uses');
  290. WriteLn(F, Indent + 'Shared.ScriptFunc;');
  291. WriteLn(F);
  292. WriteLn(F, 'var');
  293. WriteStringArray(F, 'PascalConstants_Isxclasses', Indent, FStrings[ssConstant], 0);
  294. WriteLn(F);
  295. WriteStringArray(F, 'PascalTypes_Isxclasses', Indent, FStrings[ssType], 80);
  296. WriteLn(F);
  297. WriteStringArray(F, 'PascalEnumValues_Isxclasses', Indent, FStrings[ssEnumValue], 0);
  298. WriteLn(F);
  299. WriteStringArray(F, 'PascalMembers_Isxclasses', Indent, FStrings[ssMember], 0, False, 'TScriptTable');
  300. WriteLn(F);
  301. WriteStringArray(F, 'PascalProperties_Isxclasses', Indent, FStrings[ssProperty], 80);
  302. WriteLn(F);
  303. WriteLN(F, 'implementation');
  304. WriteLn(F);
  305. Write(F, 'end.');
  306. finally
  307. CloseFile(F);
  308. end;
  309. end;
  310. end.