Sync-to-go: update copyright for 2015
[s-roff.git] / src / dev-html / html-table.cpp
blob9313ed46efc26f284e7e70618a9ea375b5f9102b
1 /*@ Implementation of html_table.h.
3 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
5 * Copyright (C) 2002 - 2005, 2007 Free Software Foundation, Inc.
6 * Written by Gaius Mulley (gaius@glam.ac.uk)
7 */
8 /*
9 * This is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2, or (at your option) any later
12 * version.
14 * This is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with groff; see the file COPYING. If not, write to the Free Software
21 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "config.h"
25 #include "html-config.h"
27 #include <ctype.h>
29 #include "cset.h"
30 #include "driver.h"
31 #include "stringclass.h"
33 #include "html.h"
34 #include "html-table.h"
35 #include "html-text.h"
37 extern html_dialect dialect;
39 tabs::tabs ()
40 : tab(NULL)
44 tabs::~tabs ()
46 delete_list();
50 * delete_list - frees the tab list and sets tab to NULL.
53 void tabs::delete_list (void)
55 tab_position *p = tab;
56 tab_position *q;
58 while (p != NULL) {
59 q = p;
60 p = p->next;
61 delete q;
63 tab = NULL;
66 void tabs::clear (void)
68 delete_list();
72 * compatible - returns true if the tab stops in, s, do
73 * not conflict with the current tab stops.
74 * The new tab stops are _not_ placed into
75 * this class.
78 int tabs::compatible (const char *s)
80 char align;
81 int total=0;
82 tab_position *last = tab;
84 if (last == NULL)
85 return false; // no tab stops defined
87 // move over tag name
88 while ((*s != (char)0) && !isspace(*s))
89 s++;
91 while (*s != (char)0 && last != NULL) {
92 // move over white space
93 while ((*s != (char)0) && isspace(*s))
94 s++;
95 // collect alignment
96 align = *s;
97 // move over alignment
98 s++;
99 // move over white space
100 while ((*s != (char)0) && isspace(*s))
101 s++;
102 // collect tab position
103 total = atoi(s);
104 // move over tab position
105 while ((*s != (char)0) && !isspace(*s))
106 s++;
107 if (last->alignment != align || last->position != total)
108 return false;
110 last = last->next;
112 return true;
116 * init - scans the string, s, and initializes the tab stops.
119 void tabs::init (const char *s)
121 char align;
122 int total=0;
123 tab_position *last = NULL;
125 clear(); // remove any tab stops
127 // move over tag name
128 while ((*s != (char)0) && !isspace(*s))
129 s++;
131 while (*s != (char)0) {
132 // move over white space
133 while ((*s != (char)0) && isspace(*s))
134 s++;
135 // collect alignment
136 align = *s;
137 // move over alignment
138 s++;
139 // move over white space
140 while ((*s != (char)0) && isspace(*s))
141 s++;
142 // collect tab position
143 total = atoi(s);
144 // move over tab position
145 while ((*s != (char)0) && !isspace(*s))
146 s++;
147 if (last == NULL) {
148 tab = new tab_position;
149 last = tab;
150 } else {
151 last->next = new tab_position;
152 last = last->next;
154 last->alignment = align;
155 last->position = total;
156 last->next = NULL;
161 * check_init - define tab stops using, s, providing none already exist.
164 void tabs::check_init (const char *s)
166 if (tab == NULL)
167 init(s);
171 * find_tab - returns the tab number corresponding to the position, pos.
174 int tabs::find_tab (int pos)
176 tab_position *p;
177 int i=0;
179 for (p = tab; p != NULL; p = p->next) {
180 i++;
181 if (p->position == pos)
182 return i;
184 return 0;
188 * get_tab_pos - returns the, nth, tab position
191 int tabs::get_tab_pos (int n)
193 tab_position *p;
195 n--;
196 for (p = tab; (p != NULL) && (n>0); p = p->next) {
197 n--;
198 if (n == 0)
199 return p->position;
201 return 0;
204 char tabs::get_tab_align (int n)
206 tab_position *p;
208 n--;
209 for (p = tab; (p != NULL) && (n>0); p = p->next) {
210 n--;
211 if (n == 0)
212 return p->alignment;
214 return 'L';
218 * dump_tab - display tab positions
221 void tabs::dump_tabs (void)
223 int i=1;
224 tab_position *p;
226 for (p = tab; p != NULL; p = p->next) {
227 printf("tab %d is %d\n", i, p->position);
228 i++;
233 * html_table - methods
236 html_table::html_table (simple_output *op, int linelen)
237 : out(op), columns(NULL), linelength(linelen), last_col(NULL), start_space(false)
239 tab_stops = new tabs();
242 html_table::~html_table ()
244 cols *c;
245 if (tab_stops != NULL)
246 delete tab_stops;
248 c = columns;
249 while (columns != NULL) {
250 columns = columns->next;
251 delete c;
252 c = columns;
257 * remove_cols - remove a list of columns as defined by, c.
260 void html_table::remove_cols (cols *c)
262 cols *p;
264 while (c != NULL) {
265 p = c;
266 c = c->next;
267 delete p;
272 * set_linelength - sets the line length value in this table.
273 * It also adds an extra blank column to the
274 * table should linelen exceed the last column.
277 void html_table::set_linelength (int linelen)
279 cols *p = NULL;
280 cols *c;
281 linelength = linelen;
283 for (c = columns; c != NULL; c = c->next) {
284 if (c->right > linelength) {
285 c->right = linelength;
286 remove_cols(c->next);
287 c->next = NULL;
288 return;
290 p = c;
292 if (p != NULL && p->right > 0 && linelength > p->right)
293 add_column(p->no+1, p->right, linelength, 'L');
297 * get_effective_linelength -
300 int html_table::get_effective_linelength (void)
302 if (columns != NULL)
303 return linelength - columns->left;
304 else
305 return linelength;
309 * add_indent - adds the indent to a table.
312 void html_table::add_indent (int indent)
314 if (columns != NULL && columns->left > indent)
315 add_column(0, indent, columns->left, 'L');
319 * emit_table_header - emits the html header for this table.
322 void html_table::emit_table_header (int space)
324 if (columns == NULL)
325 return;
327 // dump_table();
329 last_col = NULL;
330 if (linelength > 0) {
331 out->nl();
332 out->nl();
334 out->put_string("<table width=\"100%\"")
335 .put_string(" border=\"0\" rules=\"none\" frame=\"void\"\n")
336 .put_string(" cellspacing=\"0\" cellpadding=\"0\"");
337 out->put_string(">")
338 .nl();
339 if (dialect == xhtml)
340 emit_colspan();
341 out->put_string("<tr valign=\"top\" align=\"left\"");
342 if (space) {
343 out->put_string(" style=\"margin-top: ");
344 out->put_string(STYLE_VERTICAL_SPACE);
345 out->put_string("\"");
347 out->put_string(">").nl();
352 * get_right - returns the right most position of this column.
355 int html_table::get_right (cols *c)
357 if (c != NULL && c->right > 0)
358 return c->right;
359 if (c->next != NULL)
360 return c->left;
361 return linelength;
365 * set_space - assigns start_space. Used to determine the
366 * vertical alignment when generating the next table row.
369 void html_table::set_space (int space)
371 start_space = space;
375 * emit_colspan - emits a series of colspan entries defining the
376 * table columns.
379 void html_table::emit_colspan (void)
381 cols *b = columns;
382 cols *c = columns;
383 int width = 0;
385 out->put_string("<colgroup>");
386 while (c != NULL) {
387 if (b != NULL && b != c && is_gap(b))
389 * blank column for gap
391 out->put_string("<col width=\"")
392 .put_number(is_gap(b))
393 .put_string("%\" class=\"center\"></col>")
394 .nl();
396 width = (get_right(c)*100 + get_effective_linelength()/2)
397 / get_effective_linelength()
398 - (c->left*100 + get_effective_linelength()/2)
399 /get_effective_linelength();
400 switch (c->alignment) {
401 case 'C':
402 out->put_string("<col width=\"")
403 .put_number(width)
404 .put_string("%\" class=\"center\"></col>")
405 .nl();
406 break;
407 case 'R':
408 out->put_string("<col width=\"")
409 .put_number(width)
410 .put_string("%\" class=\"right\"></col>")
411 .nl();
412 break;
413 default:
414 out->put_string("<col width=\"")
415 .put_number(width)
416 .put_string("%\"></col>")
417 .nl();
419 b = c;
420 c = c->next;
422 out->put_string("</colgroup>").nl();
426 * emit_td - writes out a <td> tag with a corresponding width
427 * if the dialect is html4.
430 void html_table::emit_td (int percentage, const char *s)
432 if (percentage) {
433 if (dialect == html4) {
434 out->put_string("<td width=\"")
435 .put_number(percentage)
436 .put_string("%\"");
437 if (s != NULL)
438 out->put_string(s);
439 out->nl();
441 else {
442 out->put_string("<td");
443 if (s != NULL)
444 out->put_string(s);
445 out->nl();
451 * emit_col - moves onto column, n.
454 void html_table::emit_col (int n)
456 cols *c = columns;
457 cols *b = columns;
458 int width = 0;
460 // must be a different row
461 if (last_col != NULL && n <= last_col->no)
462 emit_new_row();
464 while (c != NULL && c->no < n)
465 c = c->next;
467 // can we find column, n?
468 if (c != NULL && c->no == n) {
469 // shutdown previous column
470 if (last_col != NULL)
471 out->put_string("</td>").nl();
473 // find previous column
474 if (last_col == NULL)
475 b = columns;
476 else
477 b = last_col;
479 // have we a gap?
480 if (last_col != NULL) {
481 emit_td(is_gap(b), "></td>");
482 b = b->next;
485 // move across to column n
486 while (b != c) {
487 // we compute the difference after converting positions
488 // to avoid rounding errors
489 width = (get_right(b)*100 + get_effective_linelength()/2)
490 / get_effective_linelength()
491 - (b->left*100 + get_effective_linelength()/2)
492 /get_effective_linelength();
493 emit_td(width, "></td>");
494 // have we a gap?
495 emit_td(is_gap(b), "></td>");
496 b = b->next;
498 width = (get_right(b)*100 + get_effective_linelength()/2)
499 / get_effective_linelength()
500 - (b->left*100 + get_effective_linelength()/2)
501 /get_effective_linelength();
502 switch (b->alignment) {
503 case 'C':
504 emit_td(width, " align=center>");
505 break;
506 case 'R':
507 emit_td(width, " align=right>");
508 break;
509 default:
510 emit_td(width);
512 // remember column, b
513 last_col = b;
518 * finish_row -
521 void html_table::finish_row (void)
523 int n = 0;
524 cols *c;
526 if (last_col != NULL) {
527 for (c = last_col->next; c != NULL; c = c->next)
528 n = c->no;
530 if (n > 0)
531 emit_col(n);
532 #if 1
533 if (last_col != NULL) {
534 out->put_string("</td>");
535 last_col = NULL;
537 #endif
538 out->put_string("</tr>").nl();
543 * emit_new_row - move to the next row.
546 void html_table::emit_new_row (void)
548 finish_row();
550 out->put_string("<tr valign=\"top\" align=\"left\"");
551 if (start_space) {
552 out->put_string(" style=\"margin-top: ");
553 out->put_string(STYLE_VERTICAL_SPACE);
554 out->put_string("\"");
556 out->put_string(">").nl();
557 start_space = false;
558 last_col = NULL;
561 void html_table::emit_finish_table (void)
563 finish_row();
564 out->put_string("</table>");
568 * add_column - adds a column. It returns false if hstart..hend
569 * crosses into a different columns.
572 int html_table::add_column (int coln, int hstart, int hend, char align)
574 cols *c = get_column(coln);
576 if (c == NULL)
577 return insert_column(coln, hstart, hend, align);
578 else
579 return modify_column(c, hstart, hend, align);
583 * get_column - returns the column, coln.
586 cols *html_table::get_column (int coln)
588 cols *c = columns;
590 while (c != NULL && coln != c->no)
591 c = c->next;
593 if (c != NULL && coln == c->no)
594 return c;
595 else
596 return NULL;
600 * insert_column - inserts a column, coln.
601 * It returns true if it does not bump into
602 * another column.
605 int html_table::insert_column (int coln, int hstart, int hend, char align)
607 cols *c = columns;
608 cols *l = columns;
609 cols *n = NULL;
611 while (c != NULL && c->no < coln) {
612 l = c;
613 c = c->next;
615 if (l != NULL && l->no>coln && hend > l->left)
616 return false; // new column bumps into previous one
618 l = NULL;
619 c = columns;
620 while (c != NULL && c->no < coln) {
621 l = c;
622 c = c->next;
625 if ((l != NULL) && (hstart < l->right))
626 return false; // new column bumps into previous one
628 if ((l != NULL) && (l->next != NULL) &&
629 (l->next->left < hend))
630 return false; // new column bumps into next one
632 n = new cols;
633 if (l == NULL) {
634 n->next = columns;
635 columns = n;
636 } else {
637 n->next = l->next;
638 l->next = n;
640 n->left = hstart;
641 n->right = hend;
642 n->no = coln;
643 n->alignment = align;
644 return true;
648 * modify_column - given a column, c, modify the width to
649 * contain hstart..hend.
650 * It returns true if it does not clash with
651 * the next or previous column.
654 int html_table::modify_column (cols *c, int hstart, int hend, char align)
656 cols *l = columns;
658 while (l != NULL && l->next != c)
659 l = l->next;
661 if ((l != NULL) && (hstart < l->right))
662 return false; // new column bumps into previous one
664 if ((c->next != NULL) && (c->next->left < hend))
665 return false; // new column bumps into next one
667 if (c->left > hstart)
668 c->left = hstart;
670 if (c->right < hend)
671 c->right = hend;
673 c->alignment = align;
675 return true;
679 * find_tab_column - finds the column number for position, pos.
680 * It searches through the list tab stops.
683 int html_table::find_tab_column (int pos)
685 // remember the first column is reserved for untabbed glyphs
686 return tab_stops->find_tab(pos)+1;
690 * find_column - find the column number for position, pos.
691 * It searches through the list of columns.
694 int html_table::find_column (int pos)
696 int p=0;
697 cols *c;
699 for (c = columns; c != NULL; c = c->next) {
700 if (c->left > pos)
701 return p;
702 p = c->no;
704 return p;
708 * no_columns - returns the number of table columns (rather than tabs)
711 int html_table::no_columns (void)
713 int n=0;
714 cols *c;
716 for (c = columns; c != NULL; c = c->next)
717 n++;
718 return n;
722 * is_gap - returns the gap between column, c, and the next column.
725 int html_table::is_gap (cols *c)
727 if (c == NULL || c->right <= 0 || c->next == NULL)
728 return 0;
729 else
730 // we compute the difference after converting positions
731 // to avoid rounding errors
732 return (c->next->left*100 + get_effective_linelength()/2)
733 / get_effective_linelength()
734 - (c->right*100 + get_effective_linelength()/2)
735 / get_effective_linelength();
739 * no_gaps - returns the number of table gaps between the columns
742 int html_table::no_gaps (void)
744 int n=0;
745 cols *c;
747 for (c = columns; c != NULL; c = c->next)
748 if (is_gap(c))
749 n++;
750 return n;
754 * get_tab_pos - returns the, nth, tab position
757 int html_table::get_tab_pos (int n)
759 return tab_stops->get_tab_pos(n);
762 char html_table::get_tab_align (int n)
764 return tab_stops->get_tab_align(n);
768 void html_table::dump_table (void)
770 if (columns != NULL) {
771 cols *c;
772 for (c = columns; c != NULL; c = c->next) {
773 printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment);
775 } else
776 tab_stops->dump_tabs();
780 * html_indent - creates an indent with indentation, ind, given
781 * a line length of linelength.
784 html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength)
786 table = new html_table(op, linelength);
788 table->add_column(1, ind+pageoffset, linelength, 'L');
789 table->add_indent(pageoffset);
790 in = ind;
791 pg = pageoffset;
792 ll = linelength;
795 html_indent::~html_indent (void)
797 end();
798 delete table;
801 void html_indent::begin (int space)
803 if (in + pg == 0) {
804 if (space) {
805 table->out->put_string(" style=\"margin-top: ");
806 table->out->put_string(STYLE_VERTICAL_SPACE);
807 table->out->put_string("\"");
810 else {
812 // we use exactly the same mechanism for calculating
813 // indentation as html_table::emit_col
815 table->out->put_string(" style=\"margin-left:")
816 .put_number(((in + pg) * 100 + ll/2) / ll -
817 (ll/2)/ll)
818 .put_string("%;");
820 if (space) {
821 table->out->put_string(" margin-top: ");
822 table->out->put_string(STYLE_VERTICAL_SPACE);
824 table->out->put_string("\"");
828 void html_indent::end (void)
833 * get_reg - collects the registers as supplied during initialization.
835 void html_indent::get_reg (int *ind, int *pageoffset, int *linelength)
837 *ind = in;
838 *pageoffset = pg;
839 *linelength = ll;
842 // s-it2-mode