dwriter.pp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. {
  2. $Id$
  3. FPDoc - Free Pascal Documentation Tool
  4. Copyright (C) 2000 - 2003 by
  5. Areca Systems GmbH / Sebastian Guenther, [email protected]
  6. * Output string definitions
  7. * Basic writer (output generator) class
  8. See the file COPYING, included in this distribution,
  9. for details about the copyright.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  13. }
  14. unit dWriter;
  15. {$MODE objfpc}
  16. {$H+}
  17. interface
  18. uses Classes, DOM, dGlobals, PasTree;
  19. resourcestring
  20. SErrFileWriting = 'An error occured during writing of file "%s": %s';
  21. SErrInvalidShortDescr = 'Invalid short description';
  22. SErrInvalidDescr = 'Invalid description (illegal XML element: "%s")';
  23. SErrInvalidParaContent = 'Invalid paragraph content';
  24. SErrInvalidElementInList = 'Invalid element in list - only "li" allowed';
  25. SErrInvalidListContent = 'Invalid list content';
  26. SErrInvalidRemarkContent = 'Invalid <remark> content (illegal XML element: "%s")';
  27. SErrListIsEmpty = 'List is empty - need at least one "li" element';
  28. SErrInvalidDefinitionTermContent = 'Invalid content in definition term';
  29. SErrDefinitionEntryMissing = 'Definition entry after definition term is missing';
  30. SErrInvalidBorderValue = 'Invalid "border" value for %s';
  31. SErrInvalidTableContent = 'Invalid table content';
  32. SErrTableRowEmpty = 'Table row is empty (no "td" elements found)';
  33. SErrInvalidContentBeforeSectionTitle = 'Invalid content before section title';
  34. SErrSectionTitleExpected = 'Section title ("title" element) expected';
  35. SErrDescrTagUnknown = 'Warning: Unknown tag "%s" in description';
  36. SErrUnknownEntityReference = 'Warning: Unknown entity reference "&%s;" found';
  37. SErrUnknownLinkID = 'Warning: Target ID of <link> is unknown: "%s"';
  38. SErrUnknownPrintShortID = 'Warning: Target ID of <printshort> is unknown: "%s"';
  39. SErrUnknownLink = 'Could not resolve link to "%s"';
  40. type
  41. // Phony element for pas pages.
  42. TTopicElement = Class(TPaselement)
  43. Constructor Create(const AName: String; AParent: TPasElement); override;
  44. Destructor Destroy; override;
  45. TopicNode : TDocNode;
  46. Previous,
  47. Next : TPasElement;
  48. Subtopics : TList;
  49. end;
  50. TFPDocWriter = class
  51. private
  52. FEngine : TFPDocEngine;
  53. FTopics : TList;
  54. protected
  55. procedure Warning(AContext: TPasElement; const AMsg: String);
  56. procedure Warning(AContext: TPasElement; const AMsg: String;
  57. const Args: array of const);
  58. // function FindShortDescr(const Name: String): TDOMElement;
  59. // Description conversion
  60. function IsDescrNodeEmpty(Node: TDOMNode): Boolean;
  61. function IsExtShort(Node: TDOMNode): Boolean;
  62. function ConvertShort(AContext: TPasElement; El: TDOMElement): Boolean;
  63. function ConvertBaseShort(AContext: TPasElement; Node: TDOMNode): Boolean;
  64. procedure ConvertBaseShortList(AContext: TPasElement; Node: TDOMNode;
  65. MayBeEmpty: Boolean);
  66. procedure ConvertLink(AContext: TPasElement; El: TDOMElement);
  67. function ConvertExtShort(AContext: TPasElement; Node: TDOMNode): Boolean;
  68. procedure ConvertDescr(AContext: TPasElement; El: TDOMElement;
  69. AutoInsertBlock: Boolean);
  70. function ConvertNonSectionBlock(AContext: TPasElement;
  71. Node: TDOMNode): Boolean;
  72. procedure ConvertExtShortOrNonSectionBlocks(AContext: TPasElement;
  73. Node: TDOMNode);
  74. function ConvertSimpleBlock(AContext: TPasElement; Node: TDOMNode): Boolean;
  75. Function FindTopicElement(Node : TDocNode): TTopicElement;
  76. procedure DescrWriteText(const AText: DOMString); virtual; abstract;
  77. procedure DescrBeginBold; virtual; abstract;
  78. procedure DescrEndBold; virtual; abstract;
  79. procedure DescrBeginItalic; virtual; abstract;
  80. procedure DescrEndItalic; virtual; abstract;
  81. procedure DescrBeginEmph; virtual; abstract;
  82. procedure DescrEndEmph; virtual; abstract;
  83. procedure DescrWriteFileEl(const AText: DOMString); virtual; abstract;
  84. procedure DescrWriteKeywordEl(const AText: DOMString); virtual; abstract;
  85. procedure DescrWriteVarEl(const AText: DOMString); virtual; abstract;
  86. procedure DescrBeginLink(const AId: DOMString); virtual; abstract;
  87. procedure DescrEndLink; virtual; abstract;
  88. procedure DescrWriteLinebreak; virtual; abstract;
  89. procedure DescrBeginParagraph; virtual; abstract;
  90. procedure DescrEndParagraph; virtual; abstract;
  91. procedure DescrBeginCode(HasBorder: Boolean; const AHighlighterName: String); virtual; abstract;
  92. procedure DescrWriteCodeLine(const ALine: String); virtual; abstract;
  93. procedure DescrEndCode; virtual; abstract;
  94. procedure DescrBeginOrderedList; virtual; abstract;
  95. procedure DescrEndOrderedList; virtual; abstract;
  96. procedure DescrBeginUnorderedList; virtual; abstract;
  97. procedure DescrEndUnorderedList; virtual; abstract;
  98. procedure DescrBeginDefinitionList; virtual; abstract;
  99. procedure DescrEndDefinitionList; virtual; abstract;
  100. procedure DescrBeginListItem; virtual; abstract;
  101. procedure DescrEndListItem; virtual; abstract;
  102. procedure DescrBeginDefinitionTerm; virtual; abstract;
  103. procedure DescrEndDefinitionTerm; virtual; abstract;
  104. procedure DescrBeginDefinitionEntry; virtual; abstract;
  105. procedure DescrEndDefinitionEntry; virtual; abstract;
  106. procedure DescrBeginSectionTitle; virtual; abstract;
  107. procedure DescrBeginSectionBody; virtual; abstract;
  108. procedure DescrEndSection; virtual; abstract;
  109. procedure DescrBeginRemark; virtual; abstract;
  110. procedure DescrEndRemark; virtual; abstract;
  111. procedure DescrBeginTable(ColCount: Integer; HasBorder: Boolean); virtual; abstract;
  112. procedure DescrEndTable; virtual; abstract;
  113. procedure DescrBeginTableCaption; virtual; abstract;
  114. procedure DescrEndTableCaption; virtual; abstract;
  115. procedure DescrBeginTableHeadRow; virtual; abstract;
  116. procedure DescrEndTableHeadRow; virtual; abstract;
  117. procedure DescrBeginTableRow; virtual; abstract;
  118. procedure DescrEndTableRow; virtual; abstract;
  119. procedure DescrBeginTableCell; virtual; abstract;
  120. procedure DescrEndTableCell; virtual; abstract;
  121. public
  122. constructor Create(AEngine: TFPDocEngine);
  123. destructor Destroy; override;
  124. property Engine : TFPDocEngine read FEngine;
  125. Property Topics : TList Read FTopics;
  126. end;
  127. implementation
  128. uses SysUtils;
  129. constructor TFPDocWriter.Create(AEngine: TFPDocEngine);
  130. begin
  131. inherited Create;
  132. FEngine := AEngine;
  133. FTopics:=Tlist.Create;
  134. end;
  135. destructor TFPDocWriter.Destroy;
  136. Var
  137. i : integer;
  138. begin
  139. For I:=0 to FTopics.Count-1 do
  140. TTopicElement(FTopics[i]).Free;
  141. FTopics.Free;
  142. Inherited;
  143. end;
  144. Function TFPDocWriter.FindTopicElement(Node : TDocNode): TTopicElement;
  145. Var
  146. I : Integer;
  147. begin
  148. Result:=Nil;
  149. I:=FTopics.Count-1;
  150. While (I>=0) and (Result=Nil) do
  151. begin
  152. If (TTopicElement(FTopics[i]).TopicNode=Node) Then
  153. Result:=TTopicElement(FTopics[i]);
  154. Dec(I);
  155. end;
  156. end;
  157. // ===================================================================
  158. // Generic documentation node conversion
  159. // ===================================================================
  160. function IsContentNodeType(Node: TDOMNode): Boolean;
  161. begin
  162. Result := (Node.NodeType = ELEMENT_NODE) or (Node.NodeType = TEXT_NODE) or
  163. (Node.NodeType = ENTITY_REFERENCE_NODE);
  164. end;
  165. procedure TFPDocWriter.Warning(AContext: TPasElement; const AMsg: String);
  166. begin
  167. WriteLn('[', AContext.PathName, '] ', AMsg);
  168. end;
  169. procedure TFPDocWriter.Warning(AContext: TPasElement; const AMsg: String;
  170. const Args: array of const);
  171. begin
  172. Warning(AContext, Format(AMsg, Args));
  173. end;
  174. function TFPDocWriter.IsDescrNodeEmpty(Node: TDOMNode): Boolean;
  175. var
  176. Child: TDOMNode;
  177. begin
  178. if (not Assigned(Node)) or (not Assigned(Node.FirstChild)) then
  179. Result := True
  180. else
  181. begin
  182. Child := Node.FirstChild;
  183. while Assigned(Child) do
  184. begin
  185. if (Child.NodeType = ELEMENT_NODE) or (Child.NodeType = TEXT_NODE) or
  186. (Child.NodeType = ENTITY_REFERENCE_NODE) then
  187. begin
  188. Result := False;
  189. exit;
  190. end;
  191. Child := Child.NextSibling;
  192. end;
  193. end;
  194. Result := True;
  195. end;
  196. { Check wether the nodes starting with the node given as argument make up an
  197. 'extshort' production. }
  198. function TFPDocWriter.IsExtShort(Node: TDOMNode): Boolean;
  199. begin
  200. while Assigned(Node) do
  201. begin
  202. if Node.NodeType = ELEMENT_NODE then
  203. if (Node.NodeName <> 'br') and
  204. (Node.NodeName <> 'link') and
  205. (Node.NodeName <> 'b') and
  206. (Node.NodeName <> 'file') and
  207. (Node.NodeName <> 'i') and
  208. (Node.NodeName <> 'kw') and
  209. (Node.NodeName <> 'printshort') and
  210. (Node.NodeName <> 'var') then
  211. begin
  212. Result := False;
  213. exit;
  214. end;
  215. Node := Node.NextSibling;
  216. end;
  217. Result := True;
  218. end;
  219. function TFPDocWriter.ConvertShort(AContext: TPasElement;
  220. El: TDOMElement): Boolean;
  221. var
  222. Node: TDOMNode;
  223. begin
  224. Result := False;
  225. if not Assigned(El) then
  226. exit;
  227. Node := El.FirstChild;
  228. while Assigned(Node) do
  229. begin
  230. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link') then
  231. ConvertLink(AContext, TDOMElement(Node))
  232. else
  233. if not ConvertBaseShort(AContext, Node) then
  234. exit;
  235. Node := Node.NextSibling;
  236. end;
  237. Result := True;
  238. end;
  239. function TFPDocWriter.ConvertBaseShort(AContext: TPasElement;
  240. Node: TDOMNode): Boolean;
  241. function ConvertText: DOMString;
  242. var
  243. s: String;
  244. i: Integer;
  245. begin
  246. if Node.NodeType = TEXT_NODE then
  247. begin
  248. s := Node.NodeValue;
  249. i := 1;
  250. SetLength(Result, 0);
  251. while i <= Length(s) do
  252. if s[i] = #13 then
  253. begin
  254. Result := Result + ' ';
  255. Inc(i);
  256. if s[i] = #10 then
  257. Inc(i);
  258. end else if s[i] = #10 then
  259. begin
  260. Result := Result + ' ';
  261. Inc(i);
  262. end else
  263. begin
  264. Result := Result + s[i];
  265. Inc(i);
  266. end;
  267. end else if Node.NodeType = ENTITY_REFERENCE_NODE then
  268. if Node.NodeName = 'fpc' then
  269. Result := 'Free Pascal'
  270. else if Node.NodeName = 'delphi' then
  271. Result := 'Delphi'
  272. else
  273. begin
  274. Warning(AContext, Format(SErrUnknownEntityReference, [Node.NodeName]));
  275. Result := Node.NodeName;
  276. end
  277. else if Node.NodeType = ELEMENT_NODE then
  278. SetLength(Result, 0);
  279. end;
  280. function ConvertTextContent: DOMString;
  281. begin
  282. SetLength(Result, 0);
  283. Node := Node.FirstChild;
  284. while Assigned(Node) do
  285. begin
  286. Result := Result + ConvertText;
  287. Node := Node.NextSibling;
  288. end;
  289. end;
  290. var
  291. El, DescrEl: TDOMElement;
  292. FPEl: TPasElement;
  293. begin
  294. Result := True;
  295. if Node.NodeType = ELEMENT_NODE then
  296. if Node.NodeName = 'b' then
  297. begin
  298. DescrBeginBold;
  299. ConvertBaseShortList(AContext, Node, False);
  300. DescrEndBold;
  301. end else
  302. if Node.NodeName = 'i' then
  303. begin
  304. DescrBeginItalic;
  305. ConvertBaseShortList(AContext, Node, False);
  306. DescrEndItalic;
  307. end else
  308. if Node.NodeName = 'em' then
  309. begin
  310. DescrBeginEmph;
  311. ConvertBaseShortList(AContext, Node, False);
  312. DescrEndEmph;
  313. end else
  314. if Node.NodeName = 'file' then
  315. DescrWriteFileEl(ConvertTextContent)
  316. else if Node.NodeName = 'kw' then
  317. DescrWriteKeywordEl(ConvertTextContent)
  318. else if Node.NodeName = 'printshort' then
  319. begin
  320. El := TDOMElement(Node);
  321. DescrEl := Engine.FindShortDescr(AContext.GetModule, El['id']);
  322. if Assigned(DescrEl) then
  323. ConvertShort(AContext, DescrEl)
  324. else
  325. begin
  326. Warning(AContext, Format(SErrUnknownPrintShortID, [El['id']]));
  327. DescrBeginBold;
  328. DescrWriteText('#ShortDescr:' + El['id']);
  329. DescrEndBold;
  330. end;
  331. end else if Node.NodeName = 'var' then
  332. DescrWriteVarEl(ConvertTextContent)
  333. else
  334. Result := False
  335. else
  336. DescrWriteText(ConvertText);
  337. end;
  338. procedure TFPDocWriter.ConvertBaseShortList(AContext: TPasElement;
  339. Node: TDOMNode; MayBeEmpty: Boolean);
  340. var
  341. Child: TDOMNode;
  342. begin
  343. Child := Node.FirstChild;
  344. while Assigned(Child) do
  345. begin
  346. if not ConvertBaseShort(AContext, Child) then
  347. Warning(AContext, SErrInvalidShortDescr)
  348. else
  349. MayBeEmpty := True;
  350. Child := Child.NextSibling;
  351. end;
  352. if not MayBeEmpty then
  353. Warning(AContext, SErrInvalidShortDescr)
  354. end;
  355. procedure TFPDocWriter.ConvertLink(AContext: TPasElement; El: TDOMElement);
  356. begin
  357. DescrBeginLink(El['id']);
  358. if not IsDescrNodeEmpty(El) then
  359. ConvertBaseShortList(AContext, El, True)
  360. else
  361. DescrWriteText(El['id']);
  362. DescrEndLink;
  363. end;
  364. function TFPDocWriter.ConvertExtShort(AContext: TPasElement;
  365. Node: TDOMNode): Boolean;
  366. begin
  367. Result := False;
  368. while Assigned(Node) do
  369. begin
  370. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'link') then
  371. ConvertLink(AContext, TDOMElement(Node))
  372. else if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'br') then
  373. DescrWriteLinebreak
  374. else
  375. if not ConvertBaseShort(AContext, Node) then
  376. exit;
  377. Node := Node.NextSibling;
  378. end;
  379. Result := True;
  380. end;
  381. procedure TFPDocWriter.ConvertDescr(AContext: TPasElement; El: TDOMElement;
  382. AutoInsertBlock: Boolean);
  383. var
  384. Node, Child: TDOMNode;
  385. ParaCreated: Boolean;
  386. begin
  387. if AutoInsertBlock then
  388. if IsExtShort(El.FirstChild) then
  389. DescrBeginParagraph
  390. else
  391. AutoInsertBlock := False;
  392. Node := El.FirstChild;
  393. if not ConvertExtShort(AContext, Node) then
  394. begin
  395. while Assigned(Node) do
  396. begin
  397. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'section') then
  398. begin
  399. DescrBeginSectionTitle;
  400. Child := Node.FirstChild;
  401. while Assigned(Child) and (Child.NodeType <> ELEMENT_NODE) do
  402. begin
  403. if not IsDescrNodeEmpty(Child) then
  404. Warning(AContext, SErrInvalidContentBeforeSectionTitle);
  405. Child := Child.NextSibling;
  406. end;
  407. if not Assigned(Child) or (Child.NodeName <> 'title') then
  408. Warning(AContext, SErrSectionTitleExpected)
  409. else
  410. ConvertShort(AContext, TDOMElement(Child));
  411. DescrBeginSectionBody;
  412. if IsExtShort(Child) then
  413. begin
  414. DescrBeginParagraph;
  415. ParaCreated := True;
  416. end else
  417. ParaCreated := False;
  418. ConvertExtShortOrNonSectionBlocks(AContext, Child.NextSibling);
  419. if ParaCreated then
  420. DescrEndParagraph;
  421. DescrEndSection;
  422. end else if not ConvertNonSectionBlock(AContext, Node) then
  423. Warning(AContext, SErrInvalidDescr, [Node.NodeName]);
  424. Node := Node.NextSibling;
  425. end;
  426. end else
  427. if AutoInsertBlock then
  428. DescrEndParagraph;
  429. end;
  430. procedure TFPDocWriter.ConvertExtShortOrNonSectionBlocks(AContext: TPasElement;
  431. Node: TDOMNode);
  432. begin
  433. if not ConvertExtShort(AContext, Node) then
  434. while Assigned(Node) do
  435. begin
  436. if not ConvertNonSectionBlock(AContext, Node) then
  437. Warning(AContext, SErrInvalidDescr, [Node.NodeName]);
  438. Node := Node.NextSibling;
  439. end;
  440. end;
  441. function TFPDocWriter.ConvertNonSectionBlock(AContext: TPasElement;
  442. Node: TDOMNode): Boolean;
  443. procedure ConvertCells(Node: TDOMNode);
  444. var
  445. Child: TDOMNode;
  446. IsEmpty: Boolean;
  447. begin
  448. Node := Node.FirstChild;
  449. IsEmpty := True;
  450. while Assigned(Node) do
  451. begin
  452. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'td') then
  453. begin
  454. DescrBeginTableCell;
  455. Child := Node.FirstChild;
  456. if not ConvertExtShort(AContext, Child) then
  457. while Assigned(Child) do
  458. begin
  459. if not ConvertSimpleBlock(AContext, Child) then
  460. Warning(AContext, SErrInvalidTableContent);
  461. Child := Child.NextSibling;
  462. end;
  463. DescrEndTableCell;
  464. IsEmpty := False;
  465. end else
  466. if IsContentNodeType(Node) then
  467. Warning(AContext, SErrInvalidTableContent);
  468. Node := Node.NextSibling;
  469. end;
  470. if IsEmpty then
  471. Warning(AContext, SErrTableRowEmpty);
  472. end;
  473. procedure ConvertTable;
  474. function GetColCount(Node: TDOMNode): Integer;
  475. begin
  476. Result := 0;
  477. Node := Node.FirstChild;
  478. while Assigned(Node) do
  479. begin
  480. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'td') then
  481. Inc(Result);
  482. Node := Node.NextSibling;
  483. end;
  484. end;
  485. var
  486. s: String;
  487. HasBorder, CaptionPossible, HeadRowPossible: Boolean;
  488. ColCount, ThisRowColCount: Integer;
  489. Subnode: TDOMNode;
  490. begin
  491. s := TDOMElement(Node)['border'];
  492. if s = '1' then
  493. HasBorder := True
  494. else
  495. begin
  496. HasBorder := False;
  497. if (Length(s) <> 0) and (s <> '0') then
  498. Warning(AContext, SErrInvalidBorderValue, ['<table>']);
  499. end;
  500. // Determine the number of columns
  501. ColCount := 0;
  502. Subnode := Node.FirstChild;
  503. while Assigned(Subnode) do
  504. begin
  505. if Subnode.NodeType = ELEMENT_NODE then
  506. if (Subnode.NodeName = 'caption') or (Subnode.NodeName = 'th') or
  507. (Subnode.NodeName = 'tr') then
  508. begin
  509. ThisRowColCount := GetColCount(Subnode);
  510. if ThisRowColCount > ColCount then
  511. ColCount := ThisRowColCount;
  512. end;
  513. Subnode := Subnode.NextSibling;
  514. end;
  515. DescrBeginTable(ColCount, HasBorder);
  516. Node := Node.FirstChild;
  517. CaptionPossible := True;
  518. HeadRowPossible := True;
  519. while Assigned(Node) do
  520. begin
  521. if Node.NodeType = ELEMENT_NODE then
  522. if CaptionPossible and (Node.NodeName = 'caption') then
  523. begin
  524. DescrBeginTableCaption;
  525. if not ConvertExtShort(AContext, Node.FirstChild) then
  526. Warning(AContext, SErrInvalidTableContent);
  527. DescrEndTableCaption;
  528. CaptionPossible := False;
  529. end else if HeadRowPossible and (Node.NodeName = 'th') then
  530. begin
  531. DescrBeginTableHeadRow;
  532. ConvertCells(Node);
  533. DescrEndTableHeadRow;
  534. CaptionPossible := False;
  535. HeadRowPossible := False;
  536. end else if Node.NodeName = 'tr' then
  537. begin
  538. DescrBeginTableRow;
  539. ConvertCells(Node);
  540. DescrEndTableRow;
  541. end else
  542. Warning(AContext, SErrInvalidTableContent)
  543. else if IsContentNodeType(Node) then
  544. Warning(AContext, SErrInvalidTableContent);
  545. Node := Node.NextSibling;
  546. end;
  547. DescrEndTable;
  548. end;
  549. begin
  550. if Node.NodeType <> ELEMENT_NODE then
  551. begin
  552. Result := Node.NodeType = COMMENT_NODE;
  553. exit;
  554. end;
  555. if Node.NodeName = 'remark' then
  556. begin
  557. DescrBeginRemark;
  558. Node := Node.FirstChild;
  559. if not ConvertExtShort(AContext, Node) then
  560. while Assigned(Node) do
  561. begin
  562. if (Node.NodeType = ELEMENT_NODE) and (Node.NodeName = 'table') then
  563. ConvertTable
  564. else
  565. if not ConvertSimpleBlock(AContext, Node) then
  566. Warning(AContext, SErrInvalidRemarkContent, [Node.NodeName]);
  567. Node := Node.NextSibling;
  568. end;
  569. DescrEndRemark;
  570. Result := True;
  571. end else if Node.NodeName = 'table' then
  572. begin
  573. ConvertTable;
  574. Result := True;
  575. end else
  576. Result := ConvertSimpleBlock(AContext, Node);
  577. end;
  578. function TFPDocWriter.ConvertSimpleBlock(AContext: TPasElement;
  579. Node: TDOMNode): Boolean;
  580. procedure ConvertListItems;
  581. var
  582. Empty: Boolean;
  583. begin
  584. Node := Node.FirstChild;
  585. Empty := True;
  586. while Assigned(Node) do
  587. begin
  588. if (Node.NodeType = TEXT_NODE) or (Node.NodeType = ENTITY_REFERENCE_NODE)
  589. then
  590. Warning(AContext, SErrInvalidListContent)
  591. else if Node.NodeType = ELEMENT_NODE then
  592. if Node.NodeName = 'li' then
  593. begin
  594. DescrBeginListItem;
  595. ConvertExtShortOrNonSectionBlocks(AContext, Node.FirstChild);
  596. DescrEndListItem;
  597. Empty := False;
  598. end else
  599. Warning(AContext, SErrInvalidElementInList);
  600. Node := Node.NextSibling;
  601. end;
  602. if Empty then
  603. Warning(AContext, SErrListIsEmpty);
  604. end;
  605. procedure ConvertDefinitionList;
  606. var
  607. Empty, ExpectDTNext: Boolean;
  608. begin
  609. Node := Node.FirstChild;
  610. Empty := True;
  611. ExpectDTNext := True;
  612. while Assigned(Node) do
  613. begin
  614. if (Node.NodeType = TEXT_NODE) or (Node.NodeType = ENTITY_REFERENCE_NODE)
  615. then
  616. Warning(AContext, SErrInvalidListContent)
  617. else if Node.NodeType = ELEMENT_NODE then
  618. if ExpectDTNext and (Node.NodeName = 'dt') then
  619. begin
  620. DescrBeginDefinitionTerm;
  621. if not ConvertShort(AContext, TDOMElement(Node)) then
  622. Warning(AContext, SErrInvalidDefinitionTermContent);
  623. DescrEndDefinitionTerm;
  624. Empty := False;
  625. ExpectDTNext := False;
  626. end else if not ExpectDTNext and (Node.NodeName = 'dd') then
  627. begin
  628. DescrBeginDefinitionEntry;
  629. ConvertExtShortOrNonSectionBlocks(AContext, Node.FirstChild);
  630. DescrEndDefinitionEntry;
  631. ExpectDTNext := True;
  632. end else
  633. Warning(AContext, SErrInvalidElementInList);
  634. Node := Node.NextSibling;
  635. end;
  636. if Empty then
  637. Warning(AContext, SErrListIsEmpty)
  638. else if not ExpectDTNext then
  639. Warning(AContext, SErrDefinitionEntryMissing);
  640. end;
  641. procedure ProcessCodeBody(Node: TDOMNode);
  642. var
  643. s: String;
  644. i, j: Integer;
  645. begin
  646. Node := Node.FirstChild;
  647. SetLength(s, 0);
  648. while Assigned(Node) do
  649. begin
  650. if Node.NodeType = TEXT_NODE then
  651. begin
  652. s := s + Node.NodeValue;
  653. j := 1;
  654. for i := 1 to Length(s) do
  655. // In XML, linefeeds are normalized to #10 by the parser!
  656. if s[i] = #10 then
  657. begin
  658. DescrWriteCodeLine(Copy(s, j, i - j));
  659. j := i + 1;
  660. end;
  661. if j > 1 then
  662. s := Copy(s, j, Length(s));
  663. end;
  664. Node := Node.NextSibling;
  665. end;
  666. if Length(s) > 0 then
  667. DescrWriteCodeLine(s);
  668. end;
  669. var
  670. s: String;
  671. HasBorder: Boolean;
  672. begin
  673. if Node.NodeType <> ELEMENT_NODE then
  674. begin
  675. Result := False;
  676. exit;
  677. end;
  678. if Node.NodeName = 'p' then
  679. begin
  680. DescrBeginParagraph;
  681. if not ConvertExtShort(AContext, Node.FirstChild) then
  682. Warning(AContext, SErrInvalidParaContent);
  683. DescrEndParagraph;
  684. Result := True;
  685. end else if Node.NodeName = 'code' then
  686. begin
  687. s := TDOMElement(Node)['border'];
  688. if s = '1' then
  689. HasBorder := True
  690. else
  691. begin
  692. if (Length(s) > 0) and (s <> '0') then
  693. Warning(AContext, SErrInvalidBorderValue, ['<code>']);
  694. end;
  695. DescrBeginCode(HasBorder, TDOMElement(Node)['highlighter']);
  696. ProcessCodeBody(Node);
  697. DescrEndCode;
  698. Result := True;
  699. end else if Node.NodeName = 'pre' then
  700. begin
  701. DescrBeginCode(False, 'none');
  702. ProcessCodeBody(Node);
  703. DescrEndCode;
  704. Result := True;
  705. end else if Node.NodeName = 'ul' then
  706. begin
  707. DescrBeginUnorderedList;
  708. ConvertListItems;
  709. DescrEndUnorderedList;
  710. Result := True;
  711. end else if Node.NodeName = 'ol' then
  712. begin
  713. DescrBeginOrderedList;
  714. ConvertListItems;
  715. DescrEndOrderedList;
  716. Result := True;
  717. end else if Node.NodeName = 'dl' then
  718. begin
  719. DescrBeginDefinitionList;
  720. ConvertDefinitionList;
  721. DescrEndDefinitionList;
  722. Result := True;
  723. end else
  724. Result := False;
  725. end;
  726. Constructor TTopicElement.Create(const AName: String; AParent: TPasElement);
  727. begin
  728. Inherited Create(AName,AParent);
  729. SubTopics:=TList.Create;
  730. end;
  731. Destructor TTopicElement.Destroy;
  732. begin
  733. // Actual subtopics are freed by TFPDocWriter Topics list.
  734. SubTopics.Free;
  735. Inherited;
  736. end;
  737. end.
  738. {
  739. $Log$
  740. Revision 1.2 2004-06-06 10:53:02 michael
  741. + Added Topic support
  742. Revision 1.1 2003/03/17 23:03:20 michael
  743. + Initial import in CVS
  744. Revision 1.9 2003/03/13 22:02:13 sg
  745. * New version with many bugfixes and our own parser (now independent of the
  746. compiler source)
  747. Revision 1.8 2002/05/24 00:13:22 sg
  748. * much improved new version, including many linking and output fixes
  749. Revision 1.7 2002/03/12 10:58:36 sg
  750. * reworked linking engine and internal structure
  751. Revision 1.6 2001/07/27 10:21:42 sg
  752. * Just a new, improved version ;)
  753. (detailed changelogs will be provided again with the next commits)
  754. Revision 1.5 2000/11/13 00:18:42 sg
  755. * Comments within descriptions should be ignored now in all cases
  756. Revision 1.4 2000/11/11 23:53:56 sg
  757. * Added <pre> tag (with unified handling of <pre> and <code>)
  758. Revision 1.3 2000/10/30 21:19:59 sg
  759. * Changed syntax highlighting attribute in 'code' element from
  760. 'highlight' to 'highlighter'
  761. }