dw_chm.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. unit dw_chm;
  2. interface
  3. uses Classes, DOM, DOM_HTML,
  4. dGlobals, PasTree, dwriter, dw_html, ChmWriter, chmtypes;
  5. type
  6. { TFpDocChmWriter }
  7. TFpDocChmWriter = class (TChmWriter)
  8. protected
  9. procedure FileAdded(AStream: TStream; const AEntry: TFileEntryRec); override;
  10. end;
  11. { TCHMHTMLWriter }
  12. TCHMHTMLWriter = class(THTMLWriter)
  13. private
  14. FOutChm: TStream;
  15. FChm: TFpDocChmWriter;
  16. FTempUncompressed: TStream;
  17. FTempUncompressedName: String;
  18. FChmTitle: String;
  19. FTOCName,
  20. FIndexName,
  21. FDefaultPage: String;
  22. FMakeSearchable,
  23. FNoBinToc,
  24. FNoBinIndex,
  25. FAutoTOC,
  26. FAutoIndex: Boolean;
  27. FOtherFiles: String;
  28. procedure ProcessOptions;
  29. function ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString;
  30. function RetrieveOtherFiles(const DataName: String; out PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
  31. procedure LastFileAdded(Sender: TObject);
  32. procedure GenerateTOC;
  33. procedure GenerateIndex;
  34. public
  35. procedure WriteHTMLPages; override;
  36. function InterPretOption(const Cmd,Arg : String): boolean; override;
  37. class procedure Usage(List: TStrings); override;
  38. Class Function FileNameExtension : String; override;
  39. Class procedure SplitImport(var AFilename, ALinkPrefix: String); override;
  40. end;
  41. implementation
  42. uses SysUtils, HTMWrite, chmsitemap;
  43. { TFpDocChmWriter }
  44. procedure TFpDocChmWriter.FileAdded ( AStream: TStream;
  45. const AEntry: TFileEntryRec ) ;
  46. begin
  47. // Exclude Full text index for files starting from the dot
  48. if Pos('.', AEntry.Name) <> 1 then
  49. inherited FileAdded(AStream, AEntry);
  50. end;
  51. { TCHMHTMLWriter }
  52. function TCHMHTMLWriter.ResolveLinkIDAbs(const Name: String; Level : Integer = 0): DOMString;
  53. begin
  54. Result:=UTF8Decode(FixHTMLpath(Engine.ResolveLink(Module,Name, True)));
  55. // for global index: don't make it relative to the current document.
  56. end;
  57. procedure TCHMHTMLWriter.ProcessOptions;
  58. var
  59. TempStream: TMemoryStream;
  60. begin
  61. if FDefaultPage = '' then
  62. FDefaultPage := 'index.html'
  63. else
  64. begin
  65. DoLog('Note: --index-page not assigned. Using default "index.html"');
  66. end;
  67. if FCSSFile <> '' then
  68. begin
  69. if not FileExists(FCSSFile) Then
  70. Raise Exception.CreateFmt('Can''t find CSS file "%S"',[FCSSFILE]);
  71. TempStream := TMemoryStream.Create;
  72. TempStream.LoadFromFile(FCSSFile);
  73. TempStream.Position := 0;
  74. FChm.AddStreamToArchive('fpdoc.css', '/', TempStream, True);
  75. TempStream.Free;
  76. end;
  77. FChm.DefaultPage := FDefaultPage;
  78. if FOtherFiles <> '' then
  79. begin
  80. FChm.FilesToCompress.LoadFromFile(FOtherFiles);
  81. end;
  82. FChm.FullTextSearch := FMakeSearchable;
  83. end;
  84. function TCHMHTMLWriter.RetrieveOtherFiles(const DataName: String; out
  85. PathInChm: String; out FileName: String; var Stream: TStream): Boolean;
  86. begin
  87. Result:=True;
  88. if Stream <> nil then
  89. Stream.Free;
  90. Stream := TMemoryStream.Create;
  91. TMemoryStream(Stream).LoadFromFile(DataName);
  92. FileName := ExtractFileName(DataName);
  93. if ExtractFileDir(DataName) <> '' then
  94. PathInChm := ExtractRelativepath(GetCurrentDir, ExtractFileDir(DataName))
  95. else
  96. PathInChm := '/';
  97. FixHTMLpath(PathInChm);
  98. Stream.Position := 0;
  99. end;
  100. procedure TCHMHTMLWriter.LastFileAdded(Sender: TObject);
  101. var
  102. TmpStream: TMemoryStream;
  103. begin
  104. TmpStream := TMemoryStream.Create;
  105. if FAutoTOC then
  106. GenerateTOC
  107. else
  108. if FTOCName <> '' then
  109. begin
  110. TmpStream.LoadFromFile(FTOCName);
  111. TmpStream.Position := 0;
  112. FChm.AppendTOC(TmpStream);
  113. TmpStream.Size := 0;
  114. end;
  115. if FAutoIndex then
  116. GenerateIndex
  117. else
  118. if FIndexName <> '' then
  119. begin
  120. TmpStream.LoadFromFile(FIndexName);
  121. TmpStream.Position := 0;
  122. FChm.AppendIndex(TmpStream);
  123. end;
  124. TmpStream.Free;
  125. DoLog('Finishing compressing...');
  126. end;
  127. function TOCSort(Item1, Item2: TChmSiteMapItem): Integer;
  128. begin
  129. Result := CompareText(LowerCase(Item1.Text), LowerCase(Item2.Text));
  130. end;
  131. function GetAlphaItem(AItems: TChmSiteMapItems; AName: String): TChmSiteMapItem;
  132. var
  133. x: Integer;
  134. begin
  135. Result := nil;
  136. for x := 0 to AItems.Count-1 do
  137. begin
  138. if AItems.Item[x].Text = AName then
  139. Exit(AItems.Item[x]);
  140. end;
  141. Result := AItems.NewItem;
  142. Result.Text := AName;
  143. end;
  144. procedure TCHMHTMLWriter.GenerateTOC;
  145. var
  146. TOC: TChmSiteMap;
  147. Element: TPasElement;
  148. j: Integer;
  149. i: Integer;
  150. AModule: TPasModule;
  151. Stream: TMemoryStream;
  152. TmpItem: TChmSiteMapItem;
  153. ObjByUnitItem,
  154. AlphaObjItem,
  155. ObjUnitItem,
  156. RoutinesByUnitItem,
  157. RoutinesUnitItem,
  158. AlphaRoutinesItem: TChmSiteMapItem;
  159. begin
  160. DoLog('Generating Table of contents...');
  161. if Assigned(Package) then
  162. begin
  163. Toc := TChmSiteMap.Create(stTOC);
  164. Stream := TMemoryStream.Create;
  165. ObjByUnitItem := TOC.Items.NewItem;
  166. ObjByUnitItem.Text := 'Classes and Objects, by Unit';
  167. AlphaObjItem := TOC.Items.NewItem;
  168. AlphaObjItem.Text := 'Alphabetical Classes and Objects List';
  169. RoutinesByUnitItem := TOC.Items.NewItem;
  170. RoutinesByUnitItem.Text := 'Routines, by Unit';
  171. AlphaRoutinesItem := TOC.Items.NewItem;
  172. AlphaRoutinesItem.Text := 'Alphabetical Routines List';
  173. // objects and classes
  174. for i := 0 to Package.Modules.Count - 1 do
  175. begin
  176. AModule := TPasModule(Package.Modules[i]);
  177. If not assigned(AModule.InterfaceSection) Then
  178. Continue;
  179. ObjUnitItem := ObjByUnitItem.Children.NewItem;
  180. ObjUnitItem.Text := AModule.Name;
  181. RoutinesUnitItem := RoutinesByUnitItem.Children.NewItem;
  182. RoutinesUnitItem.Text := AModule.Name;
  183. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  184. begin
  185. Element := TPasClassType(AModule.InterfaceSection.Classes[j]);
  186. // by unit
  187. TmpItem := ObjUnitItem.Children.NewItem;
  188. TmpItem.Text := Element.Name;
  189. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  190. //alpha
  191. TmpItem := GetAlphaItem(AlphaObjItem.Children, UpperCase(Copy(Element.Name, 1, 2))).Children.NewItem;
  192. TmpItem.Text := Element.Name;
  193. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  194. end;
  195. // non object procedures and functions
  196. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  197. begin
  198. Element := TPasFunctionType(AModule.InterfaceSection.Functions[j]);
  199. // by unit
  200. TmpItem := RoutinesUnitItem.Children.NewItem;
  201. TmpItem.Text := Element.Name;
  202. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  203. // alpha
  204. TmpItem := GetAlphaItem(AlphaRoutinesItem.Children, UpperCase(Element.Name[1])).Children.NewItem;
  205. TmpItem.Text := Element.Name;
  206. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(Element, 0)));
  207. end;
  208. end;
  209. end;
  210. // cleanup
  211. for i := ObjByUnitItem.Children.Count-1 downto 0 do
  212. begin
  213. if ObjByUnitItem.Children.Item[i].Children.Count = 0 then
  214. ObjByUnitItem.Children.Delete(i);
  215. end;
  216. for i := RoutinesByUnitItem.Children.Count-1 downto 0 do
  217. begin
  218. if RoutinesByUnitItem.Children.Item[i].Children.Count = 0 then
  219. RoutinesByUnitItem.Children.Delete(i);
  220. end;
  221. for i := TOC.Items.Count-1 downto 0 do
  222. begin
  223. if TOC.Items.Item[i].Children.Count = 0 then
  224. TOC.Items.Delete(i);
  225. end;
  226. // Sort
  227. for i := 0 to TOC.Items.Count-1 do
  228. begin
  229. TOC.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  230. for j := 0 to TOC.Items.Item[i].Children.Count-1 do
  231. begin
  232. TOC.Items.Item[i].Children.Item[j].Children.Sort(TListSortCompare(@TOCSort));
  233. end;
  234. end;
  235. if not fnobintoc then
  236. fchm.AppendBinaryTOCFromSiteMap(Toc);
  237. TOC.SaveToStream(Stream);
  238. TOC.Free;
  239. fchm.AppendTOC(Stream);
  240. Stream.Free;
  241. end;
  242. type
  243. TClassMemberType = (cmtProcedure, cmtFunction, cmtConstructor, cmtDestructor,
  244. cmtInterface, cmtProperty, cmtVariable, cmtUnknown);
  245. function ElementType(Element: TPasElement): TClassMemberType;
  246. var
  247. ETypeName: String;
  248. begin
  249. Result := cmtUnknown;
  250. ETypeName := Element.ElementTypeName;
  251. //overloaded we don't care
  252. if ETypeName[1] = 'o' then ETypeName := Copy(ETypeName, 11, Length(ETypeName));
  253. if ETypeName[1] = 'f' then Exit(cmtFunction);
  254. if ETypeName[1] = 'c' then Exit(cmtConstructor);
  255. if ETypeName[1] = 'v' then Exit(cmtVariable);
  256. if ETypeName[1] = 'i' then Exit(cmtInterface);
  257. // the p's
  258. if ETypeName[4] = 'c' then Exit(cmtProcedure);
  259. if ETypeName[4] = 'p' then Exit(cmtProperty);
  260. end;
  261. procedure TCHMHTMLWriter.GenerateIndex;
  262. var
  263. Index: TChmSiteMap;
  264. i, j, k: Integer;
  265. TmpItem: TChmSiteMapItem;
  266. ParentItem: TChmSiteMapItem;
  267. AModule: TPasModule;
  268. TmpElement: TPasElement;
  269. ParentElement: TPasElement;
  270. MemberItem: TChmSiteMapItem;
  271. Stream: TMemoryStream;
  272. RedirectUrl,Urls: String;
  273. begin
  274. DoLog('Generating Index...');
  275. if Assigned(Package) then
  276. begin
  277. Index := TChmSiteMap.Create(stIndex);
  278. Stream := TMemoryStream.Create;
  279. for i := 0 to Package.Modules.Count - 1 do
  280. begin
  281. AModule := TPasModule(Package.Modules[i]);
  282. if not assigned(AModule.InterfaceSection) then
  283. continue;
  284. ParentItem := Index.Items.NewItem;
  285. ParentItem.Text := AModule.Name;
  286. ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(AModule, 0)));
  287. // classes
  288. for j := 0 to AModule.InterfaceSection.Classes.Count-1 do
  289. begin
  290. ParentElement := TPasClassType(AModule.InterfaceSection.Classes[j]);
  291. ParentItem := Index.Items.NewItem;
  292. ParentItem.Text := ParentELement.Name;
  293. ParentItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  294. for k := 0 to TPasClassType(ParentElement).Members.Count-1 do
  295. begin
  296. TmpElement := TPasElement(TPasClassType(ParentElement).Members.Items[k]);
  297. if Engine.HidePrivate and(TmpElement.Visibility = visPrivate) then
  298. continue;
  299. if Engine.HideProtected and(TmpElement.Visibility = visProtected) then
  300. continue;
  301. Urls:=FixHTMLpath(Allocator.GetFilename(TmpElement, 0));
  302. RedirectUrl:='';
  303. if TmpElement is TPasEnumValue then
  304. RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.Parent.PathName))
  305. else
  306. RedirectUrl := UTF8Encode(ResolveLinkIDAbs(tmpElement.PathName));
  307. if(trim(RedirectUrl)<>'') and (RedirectUrl<>urls) then
  308. begin
  309. writeln('Hint: Index Resolved:',urls,' to ',RedirectUrl);
  310. urls:=RedirectUrl;
  311. end;
  312. TmpItem := ParentItem.Children.NewItem;
  313. case ElementType(TmpElement) of
  314. cmtProcedure : TmpItem.Text := TmpElement.Name + ' procedure';
  315. cmtFunction : TmpItem.Text := TmpElement.Name + ' function';
  316. cmtConstructor : TmpItem.Text := TmpElement.Name + ' constructor';
  317. cmtDestructor : TmpItem.Text := TmpElement.Name + ' destructor';
  318. cmtProperty : TmpItem.Text := TmpElement.Name + ' property';
  319. cmtVariable : TmpItem.Text := TmpElement.Name + ' variable';
  320. cmtInterface : TmpItem.Text := TmpElement.Name + ' interface';
  321. cmtUnknown : TmpItem.Text := TmpElement.Name;
  322. end;
  323. TmpItem.addLocal(Urls);
  324. {
  325. ParentElement = Class
  326. TmpElement = Member
  327. }
  328. MemberItem := nil;
  329. MemberItem := GetAlphaItem(Index.Items, TmpElement.Name);
  330. // ahh! if MemberItem.Local is empty MemberType is not shown!
  331. MemberItem.addLocal(Urls);
  332. TmpItem := MemberItem.Children.NewItem;
  333. TmpItem.Text := ParentElement.Name;
  334. TmpItem.AddLocal(Urls);
  335. end;
  336. end;
  337. // routines
  338. for j := 0 to AModule.InterfaceSection.Functions.Count-1 do
  339. begin
  340. ParentElement := TPasProcedureType(AModule.InterfaceSection.Functions[j]);
  341. TmpItem := Index.Items.NewItem;
  342. TmpItem.Text := ParentElement.Name + ' ' + ParentElement.ElementTypeName;
  343. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  344. end;
  345. // consts
  346. for j := 0 to AModule.InterfaceSection.Consts.Count-1 do
  347. begin
  348. ParentElement := TPasElement(AModule.InterfaceSection.Consts[j]);
  349. TmpItem := Index.Items.NewItem;
  350. TmpItem.Text := ParentElement.Name;
  351. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  352. end;
  353. // types
  354. for j := 0 to AModule.InterfaceSection.Types.Count-1 do
  355. begin
  356. ParentElement := TPasType(AModule.InterfaceSection.Types[j]);
  357. TmpItem := Index.Items.NewItem;
  358. TmpItem.Text := ParentElement.Name;
  359. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  360. // enums
  361. if ParentELement is TPasEnumType then
  362. begin
  363. ParentItem := TmpItem;
  364. for k := 0 to TPasEnumType(ParentElement).Values.Count-1 do
  365. begin
  366. TmpElement := TPasType(TPasEnumType(ParentElement).Values.Items[k]);
  367. // subitem
  368. TmpItem := ParentItem.Children.NewItem;
  369. TmpItem.Text := TmpElement.Name;
  370. TmpItem.addLocal(ParentItem.Local);
  371. // root level
  372. TmpItem := Index.Items.NewItem;
  373. TmpItem.Text := TmpElement.Name;
  374. TmpItem.addLocal(ParentItem.Local);
  375. end;
  376. end;
  377. end;
  378. // variables
  379. for j := 0 to AModule.InterfaceSection.Variables.Count-1 do
  380. begin
  381. ParentElement := TPasElement(AModule.InterfaceSection.Variables[j]);
  382. TmpItem := Index.Items.NewItem;
  383. TmpItem.Text := ParentElement.Name + ' var';
  384. TmpItem.addLocal(FixHTMLpath(Allocator.GetFilename(ParentElement, 0)));
  385. end;
  386. // declarations
  387. {
  388. for j := 0 to AModule.InterfaceSection.Declarations.Count-1 do
  389. begin
  390. ParentElement := TPasElement(AModule.InterfaceSection.Declarations[j]);
  391. TmpItem := Index.Items.NewItem;
  392. TmpItem.Text := ParentElement.Name;
  393. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  394. end;
  395. // resource strings
  396. for j := 0 to AModule.InterfaceSection.ResStrings.Count-1 do
  397. begin
  398. ParentElement := TPasElement(AModule.InterfaceSection.ResStrings[j]);
  399. TmpItem := Index.Items.NewItem;
  400. TmpItem.Text := ParentElement.Name;
  401. TmpItem.Local := FixHTMLpath(Allocator.GetFilename(ParentElement, 0));
  402. end;
  403. }
  404. end;
  405. // Sort
  406. Index.Items.Sort(TListSortCompare(@TOCSort));
  407. for i := 0 to Index.Items.Count-1 do
  408. begin
  409. Index.Items.Item[i].Children.Sort(TListSortCompare(@TOCSort));
  410. end;
  411. // save
  412. Index.SaveToStream(Stream);
  413. if not fnobinindex then
  414. fchm.AppendBinaryindexFromSitemap(index,false);
  415. Index.Free;
  416. Stream.Position :=0 ;
  417. FChm.AppendIndex(Stream);
  418. Stream.Free;
  419. end;
  420. end;
  421. procedure TCHMHTMLWriter.WriteHTMLPages;
  422. var
  423. i: Integer;
  424. PageDoc: TXMLDocument;
  425. FileStream: TMemoryStream;
  426. IFileName,FileName: String;
  427. FilePath: String;
  428. begin
  429. FileName := Engine.Output;
  430. if FileName = '' then
  431. Raise Exception.Create('Error: no --output option used.');
  432. if ExtractFileExt(FileName) <> FileNameExtension then
  433. FileName := ChangeFileExt(FileName, FileNameExtension);
  434. FOutChm := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate);
  435. FTempUncompressedName := GetTempFileName+IntToStr(GetProcessID) +'.raw';
  436. FTempUncompressed := TFileStream.Create(FTempUncompressedName, fmOpenReadWrite or fmCreate);
  437. FChm := TFpDocChmWriter.Create(FOutChm, False);
  438. FChm.Title := FChmTitle;
  439. FChm.TempRawStream := FTempUncompressed;
  440. FChm.OnGetFileData := @RetrieveOtherFiles;
  441. FChm.OnLastFile := @LastFileAdded;
  442. fchm.hasbinarytoc:=not fnobintoc;;
  443. fchm.hasbinaryindex:=not fnobinindex;
  444. ProcessOptions;
  445. FileStream := TMemoryStream.Create;
  446. for i := 0 to PageInfos.Count - 1 do
  447. with TPageInfo(PageInfos[i]) do
  448. begin
  449. PageDoc := CreateHTMLPage(Element, SubpageIndex);
  450. try
  451. FileName := ExtractFileName(Allocator.GetFilename(Element, SubpageIndex));
  452. FilePath := '/'+FixHTMLpath(ExtractFilePath(Allocator.GetFilename(Element, SubpageIndex)));
  453. try
  454. WriteHTMLFile(PageDoc, FileStream);
  455. FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
  456. except
  457. on E: Exception do
  458. DoLog(Format(SErrCouldNotCreateFile, [FileName, e.Message]));
  459. end;
  460. finally
  461. PageDoc.Free;
  462. FileStream.Size := 0;
  463. end;
  464. end;
  465. FileStream.Free;
  466. DoLog('HTML Files written. Collecting other files and compressing...this could take some time');
  467. //write any found images to CHM stream
  468. FileStream := TMemoryStream.Create;
  469. for iFilename in ImageFileList do
  470. begin
  471. {$ifdef imagetest} DoLog(' adding image: '+iFileName); {$endif}
  472. if FileExists(iFileName) then
  473. begin
  474. {$ifdef imagetest} DoLog(' - found'); {$endif}
  475. FileName := ExtractFileName(iFileName);
  476. FilePath := '/'+FixHTMLpath(ExtractFilePath(iFileName));
  477. FileStream.LoadFromFile(iFileName);
  478. FChm.AddStreamToArchive(FileName, FilePath, FileStream, True);
  479. FileStream.Size := 0;
  480. end
  481. else
  482. {$ifdef imagetest} DoLog(' - not found'){$endif};
  483. end;
  484. FileStream.Free;
  485. FChm.Execute;
  486. FChm.Free;
  487. // we don't need to free FTempUncompressed
  488. // FTempUncompressed.Free;
  489. FOutChm.Free;
  490. DeleteFile(FTempUncompressedName);
  491. end;
  492. function TCHMHTMLWriter.InterPretOption(const Cmd, Arg: String): boolean;
  493. begin
  494. Result:=True;
  495. FNoBinToc:=False;
  496. FnoBinIndex:=False;
  497. if Cmd = '--toc-file' then
  498. FTOCName := arg
  499. else if Cmd = '--index-file' then
  500. FIndexName := arg
  501. else if Cmd = '--default-page' then
  502. FDefaultPage := arg
  503. else if Cmd = '--other-files' then
  504. FOtherFiles := arg
  505. else if Cmd = '--auto-index' then
  506. FAutoIndex := True
  507. else if Cmd = '--auto-toc' then
  508. FAutoTOC := True
  509. else if Cmd = '--no-bintoc' then
  510. FNoBinToc := True
  511. else if Cmd = '--no-binindex' then
  512. FNoBinIndex := True
  513. else if Cmd = '--make-searchable' then
  514. FMakeSearchable := True
  515. else if Cmd = '--chm-title' then
  516. FChmTitle := arg
  517. else
  518. Result:=inherited InterPretOption(Cmd, Arg);
  519. if Length(FChmTitle) = 0 then
  520. FChmTitle := Copy(Package.Name, 2, Length(Package.Name));
  521. end;
  522. class procedure TCHMHTMLWriter.Usage(List: TStrings);
  523. begin
  524. THTMLWriter.Usage(List);
  525. List.add('--default-page');
  526. List.Add(SCHMUsageDefPage);
  527. List.add('--toc-file');
  528. List.Add(SCHMUsageTOC);
  529. List.add('--index-file');
  530. List.Add(SCHMUsageIndex);
  531. List.add('--other-files');
  532. List.Add(SCHMUsageOtrFiles);
  533. List.add('--css-file');
  534. List.Add(SCHMUsageCSSFile);
  535. List.add('--auto-index');
  536. List.Add(SCHMUsageAutoIDX);
  537. List.add('--auto-toc');
  538. List.Add(SCHMUsageAutoTOC);
  539. List.add('--make-searchable');
  540. List.Add(SCHMUsageMakeSearch);
  541. List.Add('--chm-title');
  542. List.Add(SCHMUsageChmTitle);
  543. end;
  544. Class Function TCHMHTMLWriter.FileNameExtension : String;
  545. begin
  546. result:='.chm';
  547. end;
  548. class procedure TCHMHTMLWriter.SplitImport(var AFilename, ALinkPrefix: String);
  549. var
  550. i: integer;
  551. begin
  552. i := Pos(',', AFilename);
  553. if i > 0 then
  554. begin //split into filename and prefix
  555. ALinkPrefix := Copy(AFilename,i+1,Length(AFilename));
  556. SetLength(AFilename, i-1);
  557. if copy(ALinkPrefix,1,2)='..' then // workaround for project files.
  558. begin
  559. ALinkPrefix := 'ms-its:' + ChangeFileExt(ExtractFileName(AFilename), '.chm') + '::/';
  560. AFilename := ChangeFileExt(AFilename, '.xct');
  561. end;
  562. end
  563. else if ALinkPrefix = '' then
  564. begin //synthesize outdir\pgk.xct, ms-its:pkg.chm::/
  565. ALinkPrefix := 'ms-its:' + ChangeFileExt(ExtractFileName(AFilename), '.chm') + '::/';
  566. AFilename := ChangeFileExt(AFilename, '.xct');
  567. end;
  568. end;
  569. initialization
  570. RegisterWriter(TCHMHTMLWriter,'chm','Compressed HTML file output using fpdoc.css stylesheet.');
  571. finalization
  572. UnRegisterWriter('chm');
  573. end.