dw_htmlchm.inc 16 KB

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