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