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