PageRenderTime 27ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/src/freebsd/contrib/groff/src/devices/grohtml/html-table.cpp

https://bitbucket.org/killerpenguinassassins/open_distrib_devel
C++ | 783 lines | 498 code | 122 blank | 163 comment | 177 complexity | e3381285d093ea25655dc6d1079a5561 MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. // -*- C++ -*-
  2. /* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
  3. *
  4. * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cpp
  5. *
  6. * html-table.h
  7. *
  8. * provides the methods necessary to handle indentation and tab
  9. * positions using html tables.
  10. */
  11. /*
  12. This file is part of groff.
  13. groff is free software; you can redistribute it and/or modify it under
  14. the terms of the GNU General Public License as published by the Free
  15. Software Foundation; either version 2, or (at your option) any later
  16. version.
  17. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  18. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  19. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  20. for more details.
  21. You should have received a copy of the GNU General Public License along
  22. with groff; see the file COPYING. If not, write to the Free Software
  23. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  24. #include "driver.h"
  25. #include "stringclass.h"
  26. #include "cset.h"
  27. #include "html-table.h"
  28. #include "ctype.h"
  29. #include "html.h"
  30. #include "html-text.h"
  31. #if !defined(TRUE)
  32. # define TRUE (1==1)
  33. #endif
  34. #if !defined(FALSE)
  35. # define FALSE (1==0)
  36. #endif
  37. tabs::tabs ()
  38. : tab(NULL)
  39. {
  40. }
  41. tabs::~tabs ()
  42. {
  43. delete_list();
  44. }
  45. /*
  46. * delete_list - frees the tab list and sets tab to NULL.
  47. */
  48. void tabs::delete_list (void)
  49. {
  50. tab_position *p = tab;
  51. tab_position *q;
  52. while (p != NULL) {
  53. q = p;
  54. p = p->next;
  55. delete q;
  56. }
  57. tab = NULL;
  58. }
  59. void tabs::clear (void)
  60. {
  61. delete_list();
  62. }
  63. /*
  64. * compatible - returns TRUE if the tab stops in, s, do
  65. * not conflict with the current tab stops.
  66. * The new tab stops are _not_ placed into
  67. * this class.
  68. */
  69. int tabs::compatible (const char *s)
  70. {
  71. char align;
  72. int total=0;
  73. tab_position *last = tab;
  74. if (last == NULL)
  75. return FALSE; // no tab stops defined
  76. // move over tag name
  77. while ((*s != (char)0) && !isspace(*s))
  78. s++;
  79. while (*s != (char)0 && last != NULL) {
  80. // move over white space
  81. while ((*s != (char)0) && isspace(*s))
  82. s++;
  83. // collect alignment
  84. align = *s;
  85. // move over alignment
  86. s++;
  87. // move over white space
  88. while ((*s != (char)0) && isspace(*s))
  89. s++;
  90. // collect tab position
  91. total = atoi(s);
  92. // move over tab position
  93. while ((*s != (char)0) && !isspace(*s))
  94. s++;
  95. if (last->alignment != align || last->position != total)
  96. return FALSE;
  97. last = last->next;
  98. }
  99. return TRUE;
  100. }
  101. /*
  102. * init - scans the string, s, and initializes the tab stops.
  103. */
  104. void tabs::init (const char *s)
  105. {
  106. char align;
  107. int total=0;
  108. tab_position *last = NULL;
  109. clear(); // remove any tab stops
  110. // move over tag name
  111. while ((*s != (char)0) && !isspace(*s))
  112. s++;
  113. while (*s != (char)0) {
  114. // move over white space
  115. while ((*s != (char)0) && isspace(*s))
  116. s++;
  117. // collect alignment
  118. align = *s;
  119. // move over alignment
  120. s++;
  121. // move over white space
  122. while ((*s != (char)0) && isspace(*s))
  123. s++;
  124. // collect tab position
  125. total = atoi(s);
  126. // move over tab position
  127. while ((*s != (char)0) && !isspace(*s))
  128. s++;
  129. if (last == NULL) {
  130. tab = new tab_position;
  131. last = tab;
  132. } else {
  133. last->next = new tab_position;
  134. last = last->next;
  135. }
  136. last->alignment = align;
  137. last->position = total;
  138. last->next = NULL;
  139. }
  140. }
  141. /*
  142. * check_init - define tab stops using, s, providing none already exist.
  143. */
  144. void tabs::check_init (const char *s)
  145. {
  146. if (tab == NULL)
  147. init(s);
  148. }
  149. /*
  150. * find_tab - returns the tab number corresponding to the position, pos.
  151. */
  152. int tabs::find_tab (int pos)
  153. {
  154. tab_position *p;
  155. int i=0;
  156. for (p = tab; p != NULL; p = p->next) {
  157. i++;
  158. if (p->position == pos)
  159. return i;
  160. }
  161. return 0;
  162. }
  163. /*
  164. * get_tab_pos - returns the, nth, tab position
  165. */
  166. int tabs::get_tab_pos (int n)
  167. {
  168. tab_position *p;
  169. n--;
  170. for (p = tab; (p != NULL) && (n>0); p = p->next) {
  171. n--;
  172. if (n == 0)
  173. return p->position;
  174. }
  175. return 0;
  176. }
  177. char tabs::get_tab_align (int n)
  178. {
  179. tab_position *p;
  180. n--;
  181. for (p = tab; (p != NULL) && (n>0); p = p->next) {
  182. n--;
  183. if (n == 0)
  184. return p->alignment;
  185. }
  186. return 'L';
  187. }
  188. /*
  189. * dump_tab - display tab positions
  190. */
  191. void tabs::dump_tabs (void)
  192. {
  193. int i=1;
  194. tab_position *p;
  195. for (p = tab; p != NULL; p = p->next) {
  196. printf("tab %d is %d\n", i, p->position);
  197. i++;
  198. }
  199. }
  200. /*
  201. * html_table - methods
  202. */
  203. html_table::html_table (simple_output *op, int linelen)
  204. : out(op), columns(NULL), linelength(linelen), last_col(NULL), start_space(FALSE)
  205. {
  206. tab_stops = new tabs();
  207. }
  208. html_table::~html_table ()
  209. {
  210. cols *c;
  211. if (tab_stops != NULL)
  212. delete tab_stops;
  213. c = columns;
  214. while (columns != NULL) {
  215. columns = columns->next;
  216. delete c;
  217. c = columns;
  218. }
  219. }
  220. /*
  221. * remove_cols - remove a list of columns as defined by, c.
  222. */
  223. void html_table::remove_cols (cols *c)
  224. {
  225. cols *p;
  226. while (c != NULL) {
  227. p = c;
  228. c = c->next;
  229. delete p;
  230. }
  231. }
  232. /*
  233. * set_linelength - sets the line length value in this table.
  234. * It also adds an extra blank column to the
  235. * table should linelen exceed the last column.
  236. */
  237. void html_table::set_linelength (int linelen)
  238. {
  239. cols *p = NULL;
  240. cols *c;
  241. linelength = linelen;
  242. for (c = columns; c != NULL; c = c->next) {
  243. if (c->right > linelength) {
  244. c->right = linelength;
  245. remove_cols(c->next);
  246. c->next = NULL;
  247. return;
  248. }
  249. p = c;
  250. }
  251. if (p != NULL && p->right > 0)
  252. add_column(p->no+1, p->right, linelength, 'L');
  253. }
  254. /*
  255. * get_effective_linelength -
  256. */
  257. int html_table::get_effective_linelength (void)
  258. {
  259. if (columns != NULL)
  260. return linelength - columns->left;
  261. else
  262. return linelength;
  263. }
  264. /*
  265. * add_indent - adds the indent to a table.
  266. */
  267. void html_table::add_indent (int indent)
  268. {
  269. if (columns != NULL && columns->left > indent)
  270. add_column(0, indent, columns->left, 'L');
  271. }
  272. /*
  273. * emit_table_header - emits the html header for this table.
  274. */
  275. void html_table::emit_table_header (int space)
  276. {
  277. if (columns == NULL)
  278. return;
  279. // dump_table();
  280. last_col = NULL;
  281. if (linelength > 0) {
  282. out->nl();
  283. out->nl();
  284. out->put_string("<table width=\"100%\"")
  285. .put_string(" border=0 rules=\"none\" frame=\"void\"\n")
  286. .put_string(" cellspacing=\"0\" cellpadding=\"0\"");
  287. out->put_string(">")
  288. .nl();
  289. out->put_string("<tr valign=\"top\" align=\"left\"");
  290. if (space) {
  291. out->put_string(" style=\"margin-top: ");
  292. out->put_string(STYLE_VERTICAL_SPACE);
  293. out->put_string("\"");
  294. }
  295. out->put_string(">").nl();
  296. }
  297. }
  298. /*
  299. * get_right - returns the right most position of this column.
  300. */
  301. int html_table::get_right (cols *c)
  302. {
  303. if (c != NULL && c->right > 0)
  304. return c->right;
  305. if (c->next != NULL)
  306. return c->left;
  307. return linelength;
  308. }
  309. /*
  310. * set_space - assigns start_space. Used to determine the
  311. * vertical alignment when generating the next table row.
  312. */
  313. void html_table::set_space (int space)
  314. {
  315. start_space = space;
  316. }
  317. /*
  318. * emit_col - moves onto column, n.
  319. */
  320. void html_table::emit_col (int n)
  321. {
  322. cols *c = columns;
  323. cols *b = columns;
  324. int width = 0;
  325. // must be a different row
  326. if (last_col != NULL && n <= last_col->no)
  327. emit_new_row();
  328. while (c != NULL && c->no < n)
  329. c = c->next;
  330. // can we find column, n?
  331. if (c != NULL && c->no == n) {
  332. // shutdown previous column
  333. if (last_col != NULL)
  334. out->put_string("</td>").nl();
  335. // find previous column
  336. if (last_col == NULL)
  337. b = columns;
  338. else
  339. b = last_col;
  340. // have we a gap?
  341. if (last_col != NULL) {
  342. if (is_gap(b))
  343. out->put_string("<td width=\"")
  344. .put_number(is_gap(b))
  345. .put_string("%\"></td>")
  346. .nl();
  347. b = b->next;
  348. }
  349. // move across to column n
  350. while (b != c) {
  351. // we compute the difference after converting positions
  352. // to avoid rounding errors
  353. width = (get_right(b)*100 + get_effective_linelength()/2)
  354. / get_effective_linelength()
  355. - (b->left*100 + get_effective_linelength()/2)
  356. /get_effective_linelength();
  357. if (width)
  358. out->put_string("<td width=\"")
  359. .put_number(width)
  360. .put_string("%\"></td>")
  361. .nl();
  362. // have we a gap?
  363. if (is_gap(b))
  364. out->put_string("<td width=\"")
  365. .put_number(is_gap(b))
  366. .put_string("%\"></td>")
  367. .nl();
  368. b = b->next;
  369. }
  370. width = (get_right(b)*100 + get_effective_linelength()/2)
  371. / get_effective_linelength()
  372. - (b->left*100 + get_effective_linelength()/2)
  373. /get_effective_linelength();
  374. switch (b->alignment) {
  375. case 'C':
  376. out->put_string("<td width=\"")
  377. .put_number(width)
  378. .put_string("%\" align=center>")
  379. .nl();
  380. break;
  381. case 'R':
  382. out->put_string("<td width=\"")
  383. .put_number(width)
  384. .put_string("%\" align=right>")
  385. .nl();
  386. break;
  387. default:
  388. out->put_string("<td width=\"")
  389. .put_number(width)
  390. .put_string("%\">")
  391. .nl();
  392. }
  393. // remember column, b
  394. last_col = b;
  395. }
  396. }
  397. /*
  398. * finish_row -
  399. */
  400. void html_table::finish_row (void)
  401. {
  402. int n = 0;
  403. cols *c;
  404. if (last_col != NULL) {
  405. for (c = last_col->next; c != NULL; c = c->next)
  406. n = c->no;
  407. if (n > 0)
  408. emit_col(n);
  409. out->put_string("</td>").nl();
  410. }
  411. }
  412. /*
  413. * emit_new_row - move to the next row.
  414. */
  415. void html_table::emit_new_row (void)
  416. {
  417. finish_row();
  418. out->put_string("<tr valign=\"top\" align=\"left\"");
  419. if (start_space) {
  420. out->put_string(" style=\"margin-top: ");
  421. out->put_string(STYLE_VERTICAL_SPACE);
  422. out->put_string("\"");
  423. }
  424. out->put_string(">").nl();
  425. start_space = FALSE;
  426. last_col = NULL;
  427. }
  428. void html_table::emit_finish_table (void)
  429. {
  430. finish_row();
  431. out->put_string("</table>");
  432. }
  433. /*
  434. * add_column - adds a column. It returns FALSE if hstart..hend
  435. * crosses into a different columns.
  436. */
  437. int html_table::add_column (int coln, int hstart, int hend, char align)
  438. {
  439. cols *c = get_column(coln);
  440. if (c == NULL)
  441. return insert_column(coln, hstart, hend, align);
  442. else
  443. return modify_column(c, hstart, hend, align);
  444. }
  445. /*
  446. * get_column - returns the column, coln.
  447. */
  448. cols *html_table::get_column (int coln)
  449. {
  450. cols *c = columns;
  451. while (c != NULL && coln != c->no)
  452. c = c->next;
  453. if (c != NULL && coln == c->no)
  454. return c;
  455. else
  456. return NULL;
  457. }
  458. /*
  459. * insert_column - inserts a column, coln.
  460. * It returns TRUE if it does not bump into
  461. * another column.
  462. */
  463. int html_table::insert_column (int coln, int hstart, int hend, char align)
  464. {
  465. cols *c = columns;
  466. cols *l = columns;
  467. cols *n = NULL;
  468. while (c != NULL && c->no < coln) {
  469. l = c;
  470. c = c->next;
  471. }
  472. if (l != NULL && l->no>coln && hend > l->left)
  473. return FALSE; // new column bumps into previous one
  474. l = NULL;
  475. c = columns;
  476. while (c != NULL && c->no < coln) {
  477. l = c;
  478. c = c->next;
  479. }
  480. if ((l != NULL) && (hstart < l->right))
  481. return FALSE; // new column bumps into previous one
  482. if ((l != NULL) && (l->next != NULL) &&
  483. (l->next->left < hend))
  484. return FALSE; // new column bumps into next one
  485. n = new cols;
  486. if (l == NULL) {
  487. n->next = columns;
  488. columns = n;
  489. } else {
  490. n->next = l->next;
  491. l->next = n;
  492. }
  493. n->left = hstart;
  494. n->right = hend;
  495. n->no = coln;
  496. n->alignment = align;
  497. return TRUE;
  498. }
  499. /*
  500. * modify_column - given a column, c, modify the width to
  501. * contain hstart..hend.
  502. * It returns TRUE if it does not clash with
  503. * the next or previous column.
  504. */
  505. int html_table::modify_column (cols *c, int hstart, int hend, char align)
  506. {
  507. cols *l = columns;
  508. while (l != NULL && l->next != c)
  509. l = l->next;
  510. if ((l != NULL) && (hstart < l->right))
  511. return FALSE; // new column bumps into previous one
  512. if ((c->next != NULL) && (c->next->left < hend))
  513. return FALSE; // new column bumps into next one
  514. if (c->left > hstart)
  515. c->left = hstart;
  516. if (c->right < hend)
  517. c->right = hend;
  518. c->alignment = align;
  519. return TRUE;
  520. }
  521. /*
  522. * find_tab_column - finds the column number for position, pos.
  523. * It searches through the list tab stops.
  524. */
  525. int html_table::find_tab_column (int pos)
  526. {
  527. // remember the first column is reserved for untabbed glyphs
  528. return tab_stops->find_tab(pos)+1;
  529. }
  530. /*
  531. * find_column - find the column number for position, pos.
  532. * It searches through the list of columns.
  533. */
  534. int html_table::find_column (int pos)
  535. {
  536. int p=0;
  537. cols *c;
  538. for (c = columns; c != NULL; c = c->next) {
  539. if (c->left > pos)
  540. return p;
  541. p = c->no;
  542. }
  543. return p;
  544. }
  545. /*
  546. * no_columns - returns the number of table columns (rather than tabs)
  547. */
  548. int html_table::no_columns (void)
  549. {
  550. int n=0;
  551. cols *c;
  552. for (c = columns; c != NULL; c = c->next)
  553. n++;
  554. return n;
  555. }
  556. /*
  557. * is_gap - returns the gap between column, c, and the next column.
  558. */
  559. int html_table::is_gap (cols *c)
  560. {
  561. if (c == NULL || c->right <= 0 || c->next == NULL)
  562. return 0;
  563. else
  564. // we compute the difference after converting positions
  565. // to avoid rounding errors
  566. return (c->next->left*100 + get_effective_linelength()/2)
  567. / get_effective_linelength()
  568. - (c->right*100 + get_effective_linelength()/2)
  569. / get_effective_linelength();
  570. }
  571. /*
  572. * no_gaps - returns the number of table gaps between the columns
  573. */
  574. int html_table::no_gaps (void)
  575. {
  576. int n=0;
  577. cols *c;
  578. for (c = columns; c != NULL; c = c->next)
  579. if (is_gap(c))
  580. n++;
  581. return n;
  582. }
  583. /*
  584. * get_tab_pos - returns the, nth, tab position
  585. */
  586. int html_table::get_tab_pos (int n)
  587. {
  588. return tab_stops->get_tab_pos(n);
  589. }
  590. char html_table::get_tab_align (int n)
  591. {
  592. return tab_stops->get_tab_align(n);
  593. }
  594. void html_table::dump_table (void)
  595. {
  596. if (columns != NULL) {
  597. cols *c;
  598. for (c = columns; c != NULL; c = c->next) {
  599. printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment);
  600. }
  601. } else
  602. tab_stops->dump_tabs();
  603. }
  604. /*
  605. * html_indent - creates an indent with indentation, ind, given
  606. * a line length of linelength.
  607. */
  608. html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength)
  609. {
  610. table = new html_table(op, linelength);
  611. table->add_column(1, ind+pageoffset, linelength, 'L');
  612. table->add_indent(pageoffset);
  613. in = ind;
  614. pg = pageoffset;
  615. ll = linelength;
  616. }
  617. html_indent::~html_indent (void)
  618. {
  619. end();
  620. delete table;
  621. }
  622. void html_indent::begin (int space)
  623. {
  624. if (in + pg == 0) {
  625. if (space) {
  626. table->out->put_string(" style=\"margin-top: ");
  627. table->out->put_string(STYLE_VERTICAL_SPACE);
  628. table->out->put_string("\"");
  629. }
  630. }
  631. else {
  632. //
  633. // we use exactly the same mechanism for calculating
  634. // indentation as html_table::emit_col
  635. //
  636. table->out->put_string(" style=\"margin-left:")
  637. .put_number(((in + pg) * 100 + ll/2) / ll -
  638. (ll/2)/ll)
  639. .put_string("%;");
  640. if (space) {
  641. table->out->put_string(" margin-top: ");
  642. table->out->put_string(STYLE_VERTICAL_SPACE);
  643. }
  644. table->out->put_string("\"");
  645. }
  646. }
  647. void html_indent::end (void)
  648. {
  649. }
  650. /*
  651. * get_reg - collects the registers as supplied during initialization.
  652. */
  653. void html_indent::get_reg (int *ind, int *pageoffset, int *linelength)
  654. {
  655. *ind = in;
  656. *pageoffset = pg;
  657. *linelength = ll;
  658. }