dwriter.pp 22 KB

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