dw_htmlchm.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. {%mainunit dw_html}
  2. {$IFDEF chmInterface}
  3. type
  4. { TCHMHTMLWriter }
  5. TCHMHTMLWriter = class(THTMLWriter)
  6. private
  7. FOutChm: TStream;
  8. FChm: TChmWriter;
  9. FTempUncompressed: TStream;
  10. FTempUncompressedName: String;
  11. FTOCName,
  12. FIndexName,
  13. FDefaultPage: String;
  14. FCSSFile: String;
  15. FMakeSearchable,
  16. FAutoTOC,
  17. FAutoIndex: Boolean;
  18. FOtherFiles: String;
  19. procedure ProcessOptions;
  20. function RetrieveOtherFiles(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
  21. procedure LastFileAdded(Sender: TObject);
  22. procedure GenerateTOC;
  23. procedure GenerateIndex;
  24. public
  25. procedure WriteHTMLPages; override;
  26. function InterPretOption(const Cmd,Arg : String): boolean; override;
  27. class procedure Usage(List: TStrings); override;
  28. end;
  29. {$ELSE} // implementation
  30. { TCHMHTMLWriter }
  31. procedure TCHMHTMLWriter.ProcessOptions;
  32. var
  33. TempStream: TMemoryStream;
  34. begin
  35. if FDefaultPage = '' then
  36. FDefaultPage := 'index.html'
  37. else
  38. begin
  39. WriteLn('Note: --index-page not assigned. Using default "index.html"');
  40. end;
  41. if FCSSFile <> '' then
  42. begin
  43. TempStream := TMemoryStream.Create;
  44. TempStream.LoadFromFile(FCSSFile);
  45. TempStream.Position := 0;
  46. FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True);
  47. TempStream.Free;
  48. end;
  49. FChm.DefaultPage := FDefaultPage;
  50. if FOtherFiles <> '' then
  51. begin
  52. FChm.FilesToCompress.LoadFromFile(FOtherFiles);
  53. end;
  54. FChm.FullTextSearch := FMakeSearchable;
  55. end;
  56. function TCHMHTMLWriter.RetrieveOtherFiles(const DataName: String; out
  57. PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
  58. var
  59. Dir: String;
  60. begin
  61. if Stream <> nil then
  62. Stream.Free;
  63. Stream := TMemoryStream.Create;
  64. TMemoryStream(Stream).LoadFromFile(DataName);
  65. FileName := ExtractFileName(DataName);
  66. if ExtractFileDir(DataName) <> '' then
  67. PathInChm := ExtractRelativepath(GetCurrentDir, ExtractFileDir(DataName))
  68. else
  69. PathInChm := '/';
  70. FixHTMLpath(PathInChm);
  71. Stream.Position := 0;
  72. end;
  73. procedure TCHMHTMLWriter.LastFileAdded(Sender: TObject);
  74. var
  75. TmpStream: TMemoryStream;
  76. begin
  77. TmpStream := TMemoryStream.Create;
  78. if FAutoTOC then
  79. GenerateTOC
  80. else
  81. if FTOCName <> '' then
  82. begin
  83. TmpStream.LoadFromFile(FTOCName);
  84. TmpStream.Position := 0;
  85. FChm.AppendTOC(TmpStream);
  86. TmpStream.Size := 0;
  87. end;
  88. if FAutoIndex then
  89. GenerateIndex
  90. else
  91. if FIndexName <> '' then
  92. begin
  93. TmpStream.LoadFromFile(FIndexName);
  94. TmpStream.Position := 0;
  95. FChm.AppendIndex(TmpStream);
  96. end;
  97. TmpStream.Free;
  98. WriteLn('Finishing compressing...');
  99. end;
  100. function TOCSort(Item1, Item2: TChmSiteMapItem): Integer;
  101. begin
  102. Result := CompareText(LowerCase(Item1.Text), LowerCase(Item2.Text));
  103. end;
  104. function GetAlphaItem(AItems: TChmSiteMapItems; AName: String): TChmSiteMapItem;
  105. var
  106. x: Integer;
  107. begin
  108. Result := nil;
  109. for x := 0 to AItems.Count-1 do
  110. begin
  111. if AItems.Item[x].Text = AName then
  112. Exit(AItems.Item[x]);
  113. end;
  114. Result := AItems.NewItem;
  115. Result.Text := AName;
  116. end;
  117. procedure TCHMHTMLWriter.GenerateTOC;
  118. var
  119. TOC: TChmSiteMap;
  120. Element: TPasElement;
  121. k: Integer;
  122. j: Integer;
  123. i: Integer;
  124. AModule: TPasModule;
  125. Member: TPasElement;
  126. Stream: TMemoryStream;
  127. TmpItem: TChmSiteMapItem;
  128. ObjByUnitItem,
  129. AlphaObjItem,
  130. ObjUnitItem,
  131. RoutinesByUnitItem,
  132. RoutinesUnitItem,
  133. AlphaRoutinesItem: TChmSiteMapItem;
  134. begin
  135. WriteLn('Generating Table of contents...');
  136. if Assigned(Package) then
  137. begin
  138. Toc := TChmSiteMap.Create(stTOC);
  139. Stream := TMemoryStream.Create;
  140. ObjByUnitItem := TOC.Items.NewItem;
  141. ObjByUnitItem.Text := 'Classes and Objects, by Unit';
  142. AlphaObjItem := TOC.Items.NewItem;
  143. AlphaObjItem.Text := 'Alphabetical Classes and Objects List';
  144. RoutinesByUnitItem := TOC.Items.NewItem;
  145. RoutinesByUnitItem.Text := 'Routines, by Unit';
  146. AlphaRoutinesItem := TOC.Items.NewItem;
  147. AlphaRoutinesItem.Text := 'Alphabetical Routines List';
  148. // objects and classes
  149. for i := 0 to Package.Modules.Count - 1 do
  150. begin
  151. AModule := TPasModule(Package.Modules[i]);
  152. ObjUnitItem := ObjByUnitItem.Children.NewItem;
  153. ObjUnitItem.Text := AModule.Name;
  154. RoutinesUnitItem := RoutinesByUnitItem.Children.NewItem;
  155. RoutinesUnitItem.Text := AModule.Name;
  156. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  157. begin
  158. Element := TPasClassType(AModule.InterfaceSection.Classes[j]);
  159. // by unit
  160. TmpItem := ObjUnitItem.Children.NewItem;
  161. TmpItem.Text := Element.Name;
  162. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
  163. //alpha
  164. TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
  165. TmpItem.Text := Element.Name;
  166. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
  167. end;
  168. // non object procedures and functions
  169. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  170. begin
  171. Element := TPasFunctionType(AModule.InterfaceSection.Functions[j]);
  172. // by unit
  173. TmpItem := RoutinesUnitItem.Children.NewItem;
  174. TmpItem.Text := Element.Name;
  175. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
  176. // alpha
  177. TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
  178. TmpItem.Text := Element.Name;
  179. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(Element, 0));
  180. end;
  181. end;
  182. end;
  183. // cleanup
  184. for i := ObjByUnitItem.Children.Count-1 downto 0 do
  185. begin
  186. if ObjByUnitItem.Children.Item[i].Children.Count = 0 then
  187. ObjByUnitItem.Children.Delete(i);
  188. end;
  189. for i := RoutinesByUnitItem.Children.Count-1 downto 0 do
  190. begin
  191. if RoutinesByUnitItem.Children.Item[i].Children.Count = 0 then
  192. RoutinesByUnitItem.Children.Delete(i);
  193. end;
  194. for i := TOC.Items.Count-1 downto 0 do
  195. begin
  196. if TOC.Items.Item[i].Children.Count = 0 then
  197. TOC.Items.Delete(i);
  198. end;
  199. // Sort
  200. for i := 0 to TOC.Items.Count-1 do
  201. begin
  202. TOC.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  203. for j := 0 to TOC.Items.Item[i].Children.Count-1 do
  204. begin
  205. TOC.Items.Item[i].Children.Item[j].Children.Sort(TListSortCompare(@TOCSort));
  206. end;
  207. end;
  208. fchm.AppendBinaryTOCFromSiteMap(Toc);
  209. TOC.SaveToStream(Stream);
  210. TOC.Free;
  211. fchm.AppendTOC(Stream);
  212. Stream.Free;
  213. end;
  214. type
  215. TClassMemberType = (cmtProcedure, cmtFunction, cmtConstructor, cmtDestructor,
  216. cmtInterface, cmtProperty, cmtVariable, cmtUnknown);
  217. function ElementType(Element: TPasElement): TClassMemberType;
  218. var
  219. ETypeName: String;
  220. begin
  221. Result := cmtUnknown;
  222. ETypeName := Element.ElementTypeName;
  223. //overloaded we don't care
  224. if ETypeName[1] = 'o' then ETypeName := Copy(ETypeName, 11, Length(ETypeName));
  225. if ETypeName[1] = 'f' then Exit(cmtFunction);
  226. if ETypeName[1] = 'c' then Exit(cmtConstructor);
  227. if ETypeName[1] = 'v' then Exit(cmtVariable);
  228. if ETypeName[1] = 'i' then Exit(cmtInterface);
  229. // the p's
  230. if ETypeName[4] = 'c' then Exit(cmtProcedure);
  231. if ETypeName[4] = 'p' then Exit(cmtProperty);
  232. end;
  233. procedure TCHMHTMLWriter.GenerateIndex;
  234. var
  235. Index: TChmSiteMap;
  236. i, j, k: Integer;
  237. TmpItem: TChmSiteMapItem;
  238. ParentItem: TChmSiteMapItem;
  239. AModule: TPasModule;
  240. TmpElement: TPasElement;
  241. ParentElement: TPasElement;
  242. MemberItem: TChmSiteMapItem;
  243. Stream: TMemoryStream;
  244. begin
  245. WriteLn('Generating Index...');
  246. if Assigned(Package) then
  247. begin
  248. try
  249. Index := TChmSiteMap.Create(stIndex);
  250. Stream := TMemoryStream.Create;
  251. for i := 0 to Package.Modules.Count - 1 do
  252. begin
  253. AModule := TPasModule(Package.Modules[i]);
  254. ParentItem := Index.Items.NewItem;
  255. ParentItem.Text := AModule.Name;
  256. ParentItem.Local := FixHTMLpath(Allocator.GetFilename(AModule, 0));
  257. // classes
  258. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  259. begin
  260. ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
  261. ParentItem := Index.Items.NewItem;
  262. ParentItem.Text := ParentELement.Name;
  263. ParentItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  264. for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
  265. begin
  266. TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
  267. if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
  268. continue;
  269. if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
  270. continue;
  271. TmpItem := ParentItem.Children.NewItem;
  272. case ElementType(TmpElement) of
  273. cmtProcedure : TmpItem.Text := TmpElement.Name + ' procedure';
  274. cmtFunction : TmpItem.Text := TmpElement.Name + ' function';
  275. cmtConstructor : TmpItem.Text := TmpElement.Name + ' constructor';
  276. cmtDestructor : TmpItem.Text := TmpElement.Name + ' destructor';
  277. cmtProperty : TmpItem.Text := TmpElement.Name + ' property';
  278. cmtVariable : TmpItem.Text := TmpElement.Name + ' variable';
  279. cmtInterface : TmpItem.Text := TmpElement.Name + ' interface';
  280. cmtUnknown : TmpItem.Text := TmpElement.Name;
  281. end;
  282. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
  283. {
  284. ParentElement = Class
  285. TmpElement = Member
  286. }
  287. MemberItem := nil;
  288. MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
  289. // ahh! if MemberItem.Local is empty MemberType is not shown!
  290. MemberItem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
  291. TmpItem := MemberItem.Children.NewItem;
  292. TmpItem.Text := ParentElement.Name;
  293. TmpITem.Local := FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
  294. end;
  295. end;
  296. // routines
  297. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  298. begin
  299. ParentElement := TPasProcedureType(AModule.InterfaceSection.Functions[j]);
  300. TmpItem := Index.Items.NewItem;
  301. TmpItem.Text := ParentElement.Name + ' ' + TPasFunction(ParentElement).ElementTypeName;
  302. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  303. end;
  304. // consts
  305. for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
  306. begin
  307. ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
  308. TmpItem := Index.Items.NewItem;
  309. TmpItem.Text := ParentElement.Name;
  310. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  311. end;
  312. // types
  313. for j := 0 to AModule.InterfaceSection.Types.Count-1 do
  314. begin
  315. ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
  316. TmpItem := Index.Items.NewItem;
  317. TmpItem.Text := ParentElement.Name;
  318. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  319. // enums
  320. if ParentELement is TPasEnumType then
  321. begin
  322. ParentItem := TmpItem;
  323. for k := 0 to TPasEnumType(ParentElement).Values.Count-1 do
  324. begin
  325. TmpElement := TPasType(TPasEnumType(ParentElement).Values.Items[k]);
  326. // subitem
  327. TmpItem := ParentItem.Children.NewItem;
  328. TmpItem.Text := TmpElement.Name;
  329. TmpItem.Local := ParentItem.Local;
  330. // root level
  331. TmpItem := Index.Items.NewItem;
  332. TmpItem.Text := TmpElement.Name;
  333. TmpItem.Local := ParentItem.Local;
  334. end;
  335. end;
  336. end;
  337. // variables
  338. for j := 0 to AModule.InterfaceSection.Variables.Count-1 do
  339. begin
  340. ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
  341. TmpItem := Index.Items.NewItem;
  342. TmpItem.Text := ParentElement.Name + ' var';
  343. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  344. end;
  345. // declarations
  346. {
  347. for j := 0 to AModule.InterfaceSection.Declarations.Count-1 do
  348. begin
  349. ParentElement := TPasElement(AModule.InterfaceSection.Declarations[j]);
  350. TmpItem := Index.Items.NewItem;
  351. TmpItem.Text := ParentElement.Name;
  352. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  353. end;
  354. // resource strings
  355. for j := 0 to AModule.InterfaceSection.ResStrings.Count-1 do
  356. begin
  357. ParentElement := TPasElement(AModule.InterfaceSection.ResStrings[j]);
  358. TmpItem := Index.Items.NewItem;
  359. TmpItem.Text := ParentElement.Name;
  360. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  361. end;
  362. }
  363. end;
  364. // Sort
  365. Index.Items.Sort(TListSortCompare(@TOCSort));
  366. for i := 0 to Index.Items.Count-1 do
  367. begin
  368. Index.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  369. end;
  370. // save
  371. Index.SaveToStream(Stream);
  372. Index.Free;
  373. Stream.Position :=0 ;
  374. FChm.AppendIndex(Stream);
  375. Stream.Free;
  376. except
  377. Dump_Stack(StdOut, get_frame);
  378. Halt(1);
  379. end;
  380. end;
  381. end;
  382. procedure TCHMHTMLWriter.WriteHTMLPages;
  383. var
  384. i: Integer;
  385. PageDoc: TXMLDocument;
  386. FileStream: TMemoryStream;
  387. FileName: String;
  388. FilePath: String;
  389. begin
  390. if Engine.Output = '' then
  391. begin
  392. WriteLn('Error: no --output option used.');
  393. Exit;
  394. end;
  395. if ExtractFileExt(Engine.Output) <> '.chm' then
  396. ChangeFileExt(Engine.OutPut, '.chm');
  397. FOutChm := TFileStream.Create(Engine.Output, fmOpenReadWrite or fmCreate);
  398. FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
  399. FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite or fmCreate);
  400. FChm := TChmWriter.Create(FOutChm, False);
  401. FChm.Title := Copy(Package.Name, 2, Length(Package.Name));
  402. FChm.TempRawStream := FTempUncompressed;
  403. FChm.OnGetFileData := @RetrieveOtherFiles;
  404. FChm.OnLastFile := @LastFileAdded;
  405. fchm.hasbinarytoc:=true;
  406. ProcessOptions;
  407. FileStream := TMemoryStream.Create;
  408. for i := 0 to PageInfos.Count - 1 do
  409. with TPageInfo(PageInfos[i]) do
  410. begin
  411. PageDoc := CreateHTMLPage(Element, SubpageIndex);
  412. try
  413. FileName := ExtractFileName(Allocator.GetFilename(Element, SubpageIndex));
  414. FilePath := '/'+FixHTMLpath(ExtractFilePath(Allocator.GetFilename(Element, SubpageIndex)));
  415. try
  416. WriteHTMLFile(PageDoc, FileStream);
  417. FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
  418. except
  419. on E: Exception do
  420. WriteLn(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
  421. end;
  422. finally
  423. PageDoc.Free;
  424. FileStream.Size := 0;
  425. end;
  426. end;
  427. FileStream.Free;
  428. WriteLn('HTML Files written. Collecting other files and compressing...this could take some time');
  429. FChm.Execute;
  430. FChm.Free;
  431. // we don't need to free FTempUncompressed
  432. // FTempUncompressed.Free;
  433. FOutChm.Free;
  434. DeleteFile(FTempUncompressedName);
  435. end;
  436. function TCHMHTMLWriter.InterPretOption(const Cmd, Arg: String): boolean;
  437. begin
  438. Result:=True;
  439. if Cmd = '--toc-file' then
  440. FTOCName := arg
  441. else if Cmd = '--index-file' then
  442. FIndexName := arg
  443. else if Cmd = '--default-page' then
  444. FDefaultPage := arg
  445. else if Cmd = '--other-files' then
  446. FOtherFiles := arg
  447. else if Cmd = '--css-file' then
  448. FCSSFile := arg
  449. else if Cmd = '--auto-index' then
  450. FAutoIndex := True
  451. else if Cmd = '--auto-toc' then
  452. FAutoTOC := True
  453. else if Cmd = '--make-searchable' then
  454. FMakeSearchable := True
  455. else
  456. Result:=inherited InterPretOption(Cmd, Arg);
  457. end;
  458. class procedure TCHMHTMLWriter.Usage(List: TStrings);
  459. begin
  460. THTMLWriter.Usage(List);
  461. List.add('--default-page');
  462. List.Add(SCHMUsageDefPage);
  463. List.add('--toc-file');
  464. List.Add(SCHMUsageTOC);
  465. List.add('--index-file');
  466. List.Add(SCHMUsageIndex);
  467. List.add('--other-files');
  468. List.Add(SCHMUsageOtrFiles);
  469. List.add('--css-file');
  470. List.Add(SCHMUsageCSSFile);
  471. List.add('--auto-index');
  472. List.Add(SCHMUsageAutoIDX);
  473. List.add('--auto-toc');
  474. List.Add(SCHMUsageAutoTOC);
  475. List.add('--make-searchable');
  476. List.Add(SCHMUsageMakeSearch);
  477. end;
  478. {$ENDIF}