diff options
Diffstat (limited to 'contrib/groff/src/devices/grohtml')
-rw-r--r-- | contrib/groff/src/devices/grohtml/Makefile.sub | 11 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/grohtml.man | 96 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-table.cc | 687 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-table.h | 130 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-text.cc | 581 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-text.h | 124 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/html.h | 3 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/output.cc | 56 | ||||
-rw-r--r-- | contrib/groff/src/devices/grohtml/post-html.cc | 2417 |
9 files changed, 2982 insertions, 1123 deletions
diff --git a/contrib/groff/src/devices/grohtml/Makefile.sub b/contrib/groff/src/devices/grohtml/Makefile.sub index 10f28ce..33e41f8 100644 --- a/contrib/groff/src/devices/grohtml/Makefile.sub +++ b/contrib/groff/src/devices/grohtml/Makefile.sub @@ -1,15 +1,18 @@ -PROG=post-grohtml +PROG=post-grohtml$(EXEEXT) MAN1=grohtml.n XLIBS=$(LIBDRIVER) $(LIBGROFF) MLIB=$(LIBM) OBJS=\ - post-html.o \ - html-text.o \ - output.o + post-html.$(OBJEXT) \ + html-table.$(OBJEXT) \ + html-text.$(OBJEXT) \ + output.$(OBJEXT) CCSRCS=\ $(srcdir)/post-html.cc \ + $(srcdir)/html-table.cc \ $(srcdir)/html-text.cc \ $(srcdir)/output.cc HDRS=\ $(srcdir)/html.h \ + $(srcdir)/html-table.h \ $(srcdir)/html-text.h diff --git a/contrib/groff/src/devices/grohtml/grohtml.man b/contrib/groff/src/devices/grohtml/grohtml.man index 7b0f5e1..976990a 100644 --- a/contrib/groff/src/devices/grohtml/grohtml.man +++ b/contrib/groff/src/devices/grohtml/grohtml.man @@ -1,5 +1,5 @@ .ig -Copyright (C) 1999-2000, 2001 Free Software Foundation, Inc. +Copyright (C) 1999-2000, 2001, 2002 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are @@ -23,8 +23,10 @@ the original English. .el .TP "\\$1" .. .TH GROHTML @MAN1EXT@ "@MDATE@" "Groff Version @VERSION@" +. .SH NAME grohtml \- html driver for groff +. .SH SYNOPSIS .nr a \n(.j .ad l @@ -36,17 +38,25 @@ grohtml \- html driver for groff .ie \\n(.$-1 .RI "[\ \fB\\$1\fP" "\\$2" "\ ]" .el .RB "[\ " "\\$1" "\ ]" .. -.OP \-v?lrn +.OP \-vhlrn .OP \-D dir .OP \-F dir .OP \-i resolution -.OP \-I image stem -.OP \-o image vertical offset +.OP \-I \%image-stem +.OP \-o \%image-vertical-offset +.OP \-a \%aa-text-bits +.OP \-a \%aa-graphic-bits .RI "[\ " files\|.\|.\|. "\ ]" .br .ad \na +. .SH DESCRIPTION +The .B grohtml +front end (which consists of a preprocessor, +.BR pre-grohtml , +and a device driver, +.BR post-grohtml ) translates the output of GNU .B troff to html. @@ -76,11 +86,51 @@ using option. .SH OPTIONS .TP -.B \-v -Displays the version. +.BI \-a aa-text-bits +Number of bits of antialiasing information to be used by +.I text +when generating png images. +The default is\~4 but legal values are 0, 1, 2, and\~4. +Note your version of +.B gs +needs to support the +.B \%\-dTextAlphaBits +and +.B \%\-dGraphicAlphaBits +options in order to exploit antialiasing. +A value of\~0 stops +.B grohtml +from issuing antialiasing commands to +.BR gs . +.TP +.BI \-g aa-graphic-bits +Number of bits of antialiasing information to be used by +.I graphics +when generating png images. +The default is\~4 but legal values are 0, 1, 2, and\~4. +Note your version of +.B gs +needs to support the +.B \%\-dTextAlphaBits +and +.B \%\-dGraphicAlphaBits +options in order to exploit antialiasing. +A value of\~0 stops +.B grohtml +from issuing antialiasing commands to +.BR gs . +.TP +.B -b +Initialize the background color to white. .TP -.B \-? -Emits a usage synopsis. +.B -h +Generates section and number headings by using +.BR <B> .\|.\|. </B> +and increasing the font size, rather than using the +.BI <H n >\c +\&.\|.\|.\c +.BI </H n > +tags. .TP .B -l Turns off the production of automatic section links at the top of the document. @@ -91,10 +141,15 @@ Turns off the automatic header and footer line (html rule). .B -n Generate simple heading anchors whenever a section/number heading is found. Without the option the anchor value is the textual heading. -This can cause problems when a heading contains a `?' on some brousers +This can cause problems when a heading contains a `?' on some browsers (netscape). This flag is automatically turned on if a heading contains an image. .TP +.B -p +Display page rendering progress to stderr. +.B grohtml +only displays a page number when an image is required. +.TP .BI \-F dir Prepend directory .IB dir /dev name @@ -105,8 +160,8 @@ is the name of the device, usually .TP .BI \-i resolution Select the resolution for all images. -By default this is 80 pixels per inch. -Example: -i100 indicates 100 pixels per inch. +By default this is 100 pixels per inch. +Example: -i200 indicates 200 pixels per inch. .TP .BI \-I stem Determine the image stem name. @@ -115,6 +170,9 @@ If omitted grohtml uses .RI ( XXX is the process ID). .TP +.BI \-o vertical-offset +Specify the vertical offset of images in points. +.TP .BI \-D dir Inform .B grohtml @@ -123,9 +181,7 @@ to place all image files into directory .TP .B \-v Print the version number. -.TP -.B \-? -Display usage. +. .SH USAGE There are styles called .BR R , @@ -137,9 +193,19 @@ mounted at font positions 1 to 4. .SH DEPENDENCIES .B grohtml is dependent upon the png utilities -.RB ( \&\%pnmcut ,\ \%pnmtopng ) +.RB ( \&\%pnmcut ,\ \%pnmcrop ,\ \%pnmtopng ) and GhostScript .RB ( gs ). +.B \%pnmtopng +(version 2.37.6 or greater) +and +.B \%pnmcut +from the netpbm package (version 9.16 or greater) will work also. +It is also dependent upon +.B \%psselect +from the +.B PSUtils +package. Images are generated whenever a table, picture, equation or line is encountered. .SH BUGS diff --git a/contrib/groff/src/devices/grohtml/html-table.cc b/contrib/groff/src/devices/grohtml/html-table.cc new file mode 100644 index 0000000..a2bb255 --- /dev/null +++ b/contrib/groff/src/devices/grohtml/html-table.cc @@ -0,0 +1,687 @@ +// -*- C++ -*- +/* Copyright (C) 2002 Free Software Foundation, Inc. + * + * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc + * + * html-table.h + * + * provides the methods necessary to handle indentation and tab + * positions using html tables. + */ + +/* +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "driver.h" +#include "stringclass.h" +#include "cset.h" +#include "html-table.h" +#include "ctype.h" +#include "html.h" + +#if !defined(TRUE) +# define TRUE (1==1) +#endif +#if !defined(FALSE) +# define FALSE (1==0) +#endif + +tabs::tabs () + : tab(NULL) +{ +} + +tabs::~tabs () +{ + delete_list(); +} + +/* + * delete_list - frees the tab list and sets tab to NULL. + */ + +void tabs::delete_list (void) +{ + tab_position *p = tab; + tab_position *q; + + while (p != NULL) { + q = p; + p = p->next; + free(q); + } + tab = NULL; +} + +void tabs::clear (void) +{ + delete_list(); +} + +/* + * compatible - returns TRUE if the tab stops in, s, do + * not conflict with the current tab stops. + * The new tab stops are _not_ placed into + * this class. + */ + +int tabs::compatible (const char *s) +{ + char align; + int total=0; + tab_position *last = tab; + + if (last == NULL) + return FALSE; // no tab stops defined + + // move over tag name + while ((*s != (char)0) && !isspace(*s)) + s++; + + while (*s != (char)0 && last != NULL) { + // move over white space + while ((*s != (char)0) && isspace(*s)) + s++; + // collect alignment + align = *s; + // move over alignment + s++; + // move over white space + while ((*s != (char)0) && isspace(*s)) + s++; + // collect tab position + total += atoi(s); + // move over tab position + while ((*s != (char)0) && !isspace(*s)) + s++; + if (last->alignment != align || last->position != total) + return FALSE; + + last = last->next; + } + return TRUE; +} + +/* + * init - scans the string, s, and initializes the tab stops. + */ + +void tabs::init (const char *s) +{ + char align; + int total=0; + tab_position *last = NULL; + + clear(); // remove any tab stops + + // move over tag name + while ((*s != (char)0) && !isspace(*s)) + s++; + + while (*s != (char)0) { + // move over white space + while ((*s != (char)0) && isspace(*s)) + s++; + // collect alignment + align = *s; + // move over alignment + s++; + // move over white space + while ((*s != (char)0) && isspace(*s)) + s++; + // collect tab position + total = atoi(s); + // move over tab position + while ((*s != (char)0) && !isspace(*s)) + s++; + if (last == NULL) { + tab = (tab_position *)malloc(sizeof(tab_position)); + last = tab; + } else { + last->next = (tab_position *)malloc(sizeof(tab_position)); + last = last->next; + } + last->alignment = align; + last->position = total; + last->next = NULL; + } +} + +/* + * find_tab - returns the tab number corresponding to the position, pos. + */ + +int tabs::find_tab (int pos) +{ + tab_position *p; + int i=0; + + for (p = tab; p != NULL; p = p->next) { + i++; + if (p->position == pos) + return i; + } + return 0; +} + +/* + * get_tab_pos - returns the, nth, tab position + */ + +int tabs::get_tab_pos (int n) +{ + tab_position *p; + + n--; + for (p = tab; (p != NULL) && (n>0); p = p->next) { + n--; + if (n == 0) + return p->position; + } + return 0; +} + +char tabs::get_tab_align (int n) +{ + tab_position *p; + + n--; + for (p = tab; (p != NULL) && (n>0); p = p->next) { + n--; + if (n == 0) + return p->alignment; + } + return 'L'; +} + +/* + * dump_tab - display tab positions + */ + +void tabs::dump_tabs (void) +{ + int i=1; + tab_position *p; + + for (p = tab; p != NULL; p = p->next) { + printf("tab %d is %d\n", i, p->position); + i++; + } +} + +/* + * html_table - methods + */ + +html_table::html_table (simple_output *op, int linelen) + : columns(NULL), out(op), linelength(linelen), last_col(NULL), start_space(FALSE) +{ + tab_stops = new tabs(); +} + +html_table::~html_table () +{ + if (tab_stops != NULL) + delete tab_stops; +} + +/* + * remove_cols - remove a list of columns as defined by, c. + */ + +void html_table::remove_cols (cols *c) +{ + cols *p; + + while (c != NULL) { + p = c; + c = c->next; + free(p); + } +} + +/* + * set_linelength - sets the line length value in this table. + * It also adds an extra blank column to the + * table should linelen exceed the last column. + */ + +void html_table::set_linelength (int linelen) +{ + cols *p = NULL; + cols *c; + linelength = linelen; + + for (c = columns; c != NULL; c = c->next) { + if (c->right > linelength) { + c->right = linelength; + remove_cols(c->next); + c->next = NULL; + return; + } + p = c; + } + if (p != NULL && p->right != 0) + add_column(p->no+1, p->right+1, linelen, 'L'); +} + +/* + * get_effective_linelength - + */ + +int html_table::get_effective_linelength (void) +{ + if (columns != NULL) + return linelength - columns->left; + else + return linelength; +} + +/* + * add_indent - adds the indent to a table. + */ + +void html_table::add_indent (int indent) +{ + if (columns != NULL && columns->left > indent) + add_column(0, indent, columns->left-1, 'L'); +} + +/* + * emit_table_header - emits the html header for this table. + */ + +void html_table::emit_table_header (int space) +{ + if (columns == NULL) + return; + + // dump_table(); + + last_col = NULL; + if (linelength > 0) { + int n = no_columns() + no_gaps(); + + out->nl(); + out->nl(); + if (space) + out->put_string("<p>"); + start_space = space; + out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"").put_number(n).put_string("\" cellspacing=\"0\" cellpadding=\"0\">").nl(); + out->put_string("<tr valign=\"top\" align=\"left\">").nl(); + } +} + +/* + * get_right - returns the right most position of this column. + */ + +int html_table::get_right (cols *c) +{ + if (c != NULL && c->right > 0) + return c->right; + if (c->next != NULL) + return c->left; + return linelength; +} + +/* + * emit_col - moves onto column, n. + */ + +void html_table::emit_col (int n) +{ + cols *c = columns; + cols *b = columns; + int width = 0; + + // must be a different row + if (last_col != NULL && n <= last_col->no) + emit_new_row(); + + while (c != NULL && c->no < n) + c = c->next; + + // can we find column, n? + if (c != NULL && c->no == n) { + // shutdown previous column + if (last_col != NULL) + out->put_string("</td>").nl(); + + // find previous column + if (last_col == NULL) + b = columns; + else + b = last_col; + + // have we a gap? + if (last_col != NULL) { + if (is_gap(b)) + out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl(); + b = b->next; + } + + // move across to column n + while (b != c) { + width = ((get_right(b) - b->left) * 100)/get_effective_linelength(); + out->put_string("<td width=\"").put_number(width).put_string("%\"></td>").nl(); + // have we a gap? + if (is_gap(b)) + out->put_string("<td width=\"").put_number(is_gap(b)).put_string("%\"></td>").nl(); + b = b->next; + } + width = ((get_right(b) - b->left) * 100)/get_effective_linelength(); + switch (b->alignment) { + + case 'C': out->put_string("<td width=\"").put_number(width).put_string("%\" align=center>").nl(); + break; + case 'R': out->put_string("<td width=\"").put_number(width).put_string("%\" align=right>").nl(); + break; + default: + out->put_string("<td width=\"").put_number(width).put_string("%\">").nl(); + } + // remember column, b + last_col = b; + } +} + +/* + * finish_row - + */ + +void html_table::finish_row (void) +{ + int n = 0; + cols *c; + + if (last_col != NULL) { + for (c = last_col->next; c != NULL; c = c->next) + n = c->no; + + if (n > 0) + emit_col(n); + out->put_string("</td>").nl(); + } +} + +/* + * emit_new_row - move to the next row. + */ + +void html_table::emit_new_row (void) +{ + finish_row(); + out->put_string("<tr valign=\"top\" align=\"left\">").nl(); + last_col = NULL; +} + +void html_table::emit_finish_table (void) +{ + finish_row(); + // out->put_string("linelength = ").put_number(linelength).nl(); + out->put_string("</table>"); + if (start_space) + out->put_string("</p>"); + out->nl(); +} + +/* + * add_column - adds a column. It returns FALSE if hstart..hend + * crosses into a different columns. + */ + +int html_table::add_column (int coln, int hstart, int hend, char align) +{ + cols *c = get_column(coln); + + if (c == NULL) + return insert_column(coln, hstart, hend, align); + else + return modify_column(c, hstart, hend, align); +} + +/* + * get_column - returns the column, coln. + */ + +cols *html_table::get_column (int coln) +{ + cols *c = columns; + + while (c != NULL && coln != c->no) + c = c->next; + + if (c != NULL && coln == c->no) + return c; + else + return NULL; +} + +/* + * insert_column - inserts a column, coln. + * It returns TRUE if it does not bump into + * another column. + */ + +int html_table::insert_column (int coln, int hstart, int hend, char align) +{ + cols *c = columns; + cols *l = NULL; + cols *n = NULL; + + while (c != NULL && c->no < coln) { + l = c; + c = c->next; + } + if ((l != NULL) && (hstart < l->right)) + return FALSE; // new column bumps into previous one + + if ((l != NULL) && (l->next != NULL) && + (l->next->left < hend)) + return FALSE; // new column bumps into next one + + n = (cols *)malloc(sizeof(cols)); + if (l == NULL) { + n->next = columns; + columns = n; + } else { + n->next = l->next; + l->next = n; + } + n->left = hstart; + n->right = hend; + n->no = coln; + n->alignment = align; + return TRUE; +} + +/* + * modify_column - given a column, c, modify the width to + * contain hstart..hend. + * It returns TRUE if it does not clash with + * the next or previous column. + */ + +int html_table::modify_column (cols *c, int hstart, int hend, char align) +{ + cols *l = columns; + + while (l != NULL && l->next != c) + l = l->next; + + if ((l != NULL) && (hstart < l->right)) + return FALSE; // new column bumps into previous one + + if ((c->next != NULL) && (c->next->left < hend)) + return FALSE; // new column bumps into next one + + if (c->left > hstart) + c->left = hstart; + + if (c->right < hend) + c->right = hend; + + c->alignment = align; + + return TRUE; +} + +/* + * find_tab_column - finds the column number for position, pos. + * It searches through the list tab stops. + */ + +int html_table::find_tab_column (int pos) +{ + // remember the first column is reserved for un tabbed glyphs + return tab_stops->find_tab(pos)+1; +} + +/* + * find_column - find the column number for position, pos. + * It searches through the list of columns. + */ + +int html_table::find_column (int pos) +{ + int p=0; + cols *c; + + for (c = columns; c != NULL; c = c->next) { + if (c->left > pos) + return p; + p = c->no; + } + return p; +} + +/* + * no_columns - returns the number of table columns (rather than tabs) + */ + +int html_table::no_columns (void) +{ + int n=0; + cols *c; + + for (c = columns; c != NULL; c = c->next) + n++; + return n; +} + +/* + * is_gap - returns the gap between column, c, and the next column. + */ + +int html_table::is_gap (cols *c) +{ + if (c == NULL || c->right == 0 || c->next == NULL) + return 0; + else + return (c->next->left - c->right)*100/get_effective_linelength(); +} + +/* + * no_gaps - returns the number of table gaps between the columns + */ + +int html_table::no_gaps (void) +{ + int n=0; + cols *c; + + for (c = columns; c != NULL; c = c->next) + if (is_gap(c)) + n++; + return n; +} + +/* + * get_tab_pos - returns the, nth, tab position + */ + +int html_table::get_tab_pos (int n) +{ + return tab_stops->get_tab_pos(n); +} + +char html_table::get_tab_align (int n) +{ + return tab_stops->get_tab_align(n); +} + + +void html_table::dump_table (void) +{ + if (columns != NULL) { + cols *c; + for (c = columns; c != NULL; c = c->next) { + printf("column %d %d..%d %c\n", c->no, c->left, c->right, c->alignment); + } + } else + tab_stops->dump_tabs(); +} + +/* + * html_indent - creates an indent with indentation, ind, given + * a line length of linelength. + */ + +html_indent::html_indent (simple_output *op, int ind, int pageoffset, int linelength) +{ + table = new html_table(op, linelength); + + table->add_column(1, ind+pageoffset, linelength, 'L'); + table->add_indent(pageoffset); + in = ind; + pg = pageoffset; + ll = linelength; + is_used = FALSE; +} + +html_indent::~html_indent (void) +{ + end(); + delete table; +} + +void html_indent::begin (int space) +{ + if (! is_used) { + table->emit_table_header(space); + table->emit_col(1); + is_used = TRUE; + } +} + +void html_indent::end (void) +{ + if (is_used) + table->emit_finish_table(); + is_used = FALSE; +} + +/* + * get_reg - collects the registers as supplied during initialization. + */ + +void html_indent::get_reg (int *ind, int *pageoffset, int *linelength) +{ + *ind = in; + *pageoffset = pg; + *linelength = ll; +} diff --git a/contrib/groff/src/devices/grohtml/html-table.h b/contrib/groff/src/devices/grohtml/html-table.h new file mode 100644 index 0000000..3152060 --- /dev/null +++ b/contrib/groff/src/devices/grohtml/html-table.h @@ -0,0 +1,130 @@ +// -*- C++ -*- +/* Copyright (C) 2002 Free Software Foundation, Inc. + * + * Gaius Mulley (gaius@glam.ac.uk) wrote html-table.cc + * + * html-table.h + * + * provides the methods necessary to handle indentation and tab + * positions using html tables. + */ + +/* +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License along +with groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "html.h" + +#if !defined(HTML_TABLE_H) +#define HTML_TABLE_H + +typedef struct tab_position { + char alignment; + int position; + struct tab_position *next; +} tab_position; + + +class tabs { +public: + tabs (); + ~tabs (); + void clear (void); + int compatible (const char *s); + void init (const char *s); + int find_tab (int pos); + int get_tab_pos (int n); + char get_tab_align (int n); + void dump_tabs (void); + +private: + void delete_list (void); + tab_position *tab; +}; + +/* + * define a column + */ + +typedef struct cols { + int left, right; + int no; + char alignment; + struct cols *next; +} cols; + +class html_table { +public: + html_table (simple_output *op, int linelen); + ~html_table (void); + int add_column (int coln, int hstart, int hend, char align); + cols *get_column (int coln); + int insert_column (int coln, int hstart, int hend, char align); + int modify_column (cols *c, int hstart, int hend, char align); + int find_tab_column (int pos); + int find_column (int pos); + int get_tab_pos (int n); + char get_tab_align (int n); + void set_linelength (int linelen); + int no_columns (void); + int no_gaps (void); + int is_gap (cols *c); + void dump_table (void); + void emit_table_header (int space); + void emit_col (int n); + void emit_new_row (void); + void emit_finish_table (void); + int get_right (cols *c); + void add_indent (int indent); + void finish_row (void); + int get_effective_linelength (void); + + tabs *tab_stops; /* tab stop positions */ +private: + cols *columns; /* column entries */ + simple_output *out; + int linelength; + cols *last_col; /* last column started */ + int start_space; /* encapsulate with <p> </p> */ + + void remove_cols (cols *c); +}; + +/* + * the indentation wrapper. + * Builds an indentation from a html-table. + * This table is only emitted if the paragraph is emitted. + */ + +class html_indent { +public: + html_indent (simple_output *op, int ind, int pageoffset, int linelength); + ~html_indent (void); + void begin (int space); // called if we need to use the indent + void get_reg (int *ind, int *pageoffset, int *linelength); + + // the indent is shutdown when it is deleted + +private: + void end (void); + int is_used; + int pg; // values of the registers as passed via initialization + int ll; + int in; + html_table *table; +}; + +#endif diff --git a/contrib/groff/src/devices/grohtml/html-text.cc b/contrib/groff/src/devices/grohtml/html-text.cc index 56d6c78..31e4311 100644 --- a/contrib/groff/src/devices/grohtml/html-text.cc +++ b/contrib/groff/src/devices/grohtml/html-text.cc @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc * @@ -40,10 +40,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "html-text.h" +// #define DEBUGGING html_text::html_text (simple_output *op) : stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE), - current_indentation(-1), pageoffset(-1), linelength(-1) + current_indentation(-1), pageoffset(-1), linelength(-1), + blank_para(TRUE), start_space(FALSE) { } @@ -52,6 +54,87 @@ html_text::~html_text () flush_text(); } + +#if defined(DEBUGGING) +static int debugStack = FALSE; + + +/* + * turnDebug - flip the debugStack boolean and return the new value. + */ + +static int turnDebug (void) +{ + debugStack = 1-debugStack; + return debugStack; +} + +/* + * dump_stack_element - display an element of the html stack, p. + */ + +void html_text::dump_stack_element (tag_definition *p) +{ + fprintf(stderr, " | "); + switch (p->type) { + + case P_TAG: if (p->indent == NULL) { + fprintf(stderr, "<P %s>", (char *)p->arg1); break; + } else { + fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break; + } + case I_TAG: fprintf(stderr, "<I>"); break; + case B_TAG: fprintf(stderr, "<B>"); break; + case SUB_TAG: fprintf(stderr, "<SUB>"); break; + case SUP_TAG: fprintf(stderr, "<SUP>"); break; + case TT_TAG: fprintf(stderr, "<TT>"); break; + case PRE_TAG: if (p->indent == NULL) { + fprintf(stderr, "<PRE>"); break; + } else { + fprintf(stderr, "<PRE [TABLE]>"); break; + } + case SMALL_TAG: fprintf(stderr, "<SMALL>"); break; + case BIG_TAG: fprintf(stderr, "<BIG>"); break; + case BREAK_TAG: fprintf(stderr, "<BREAK>"); break; + case COLOR_TAG: { + if (p->col.is_default()) + fprintf(stderr, "<COLOR (default)>"); + else { + unsigned int r, g, b; + + p->col.get_rgb(&r, &g, &b); + fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101); + } + break; + } + default: fprintf(stderr, "unknown tag"); + } + if (p->text_emitted) + fprintf(stderr, "[t] "); +} + +/* + * dump_stack - debugging function only. + */ + +void html_text::dump_stack (void) +{ + if (debugStack) { + tag_definition *p = stackptr; + + while (p != NULL) { + dump_stack_element(p); + p = p->next; + } + } + fprintf(stderr, "\n"); + fflush(stderr); +} +#else +void html_text::dump_stack (void) {} +#endif + + /* * end_tag - shuts down the tag. */ @@ -62,19 +145,21 @@ void html_text::end_tag (tag_definition *t) case I_TAG: out->put_string("</i>"); break; case B_TAG: out->put_string("</b>"); break; - case P_TAG: out->put_string("</p>").nl().enable_newlines(FALSE); break; + case P_TAG: out->put_string("</p>"); + if (t->indent != NULL) { + delete t->indent; + t->indent = NULL; + } + out->nl(); out->enable_newlines(FALSE); + blank_para = TRUE; break; case SUB_TAG: out->put_string("</sub>"); break; case SUP_TAG: out->put_string("</sup>"); break; case TT_TAG: out->put_string("</tt>"); break; - case PRE_TAG: out->put_string("</pre>"); - if (! is_present(TABLE_TAG)) { - out->nl(); - out->enable_newlines(TRUE); - } - break; + case PRE_TAG: out->put_string("</pre>"); out->nl(); out->enable_newlines(TRUE); + blank_para = TRUE; break; case SMALL_TAG: out->put_string("</small>"); break; case BIG_TAG: out->put_string("</big>"); break; - case TABLE_TAG: issue_table_end(); break; + case COLOR_TAG: out->put_string("</font>"); break; default: error("unrecognised tag"); @@ -99,6 +184,27 @@ void html_text::issue_tag (char *tagname, char *arg) } /* + * issue_color_begin - writes out an html color tag. + */ + +void html_text::issue_color_begin (color *c) +{ + unsigned int r, g, b; + char buf[6+1]; + + out->put_string("<font color=\"#"); + if (c->is_default()) + sprintf(buf, "000000"); + else { + c->get_rgb(&r, &g, &b); + // we have to scale 0..0xFFFF to 0..0xFF + sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); + } + out->put_string(buf); + out->put_string("\">"); +} + +/* * start_tag - starts a tag. */ @@ -106,60 +212,42 @@ void html_text::start_tag (tag_definition *t) { switch (t->type) { - case I_TAG: issue_tag("<i", t->arg1); break; - case B_TAG: issue_tag("<b", t->arg1); break; - case P_TAG: issue_tag("\n<p", t->arg1); + case I_TAG: issue_tag("<i", (char *)t->arg1); break; + case B_TAG: issue_tag("<b", (char *)t->arg1); break; + case P_TAG: if (t->indent == NULL) { + out->nl(); + issue_tag("\n<p", (char *)t->arg1); + } else { + out->nl(); + out->simple_comment("INDENTATION"); + t->indent->begin(FALSE); + start_space = FALSE; + issue_tag("<p", (char *)t->arg1); + } + out->enable_newlines(TRUE); break; - case SUB_TAG: issue_tag("<sub", t->arg1); break; - case SUP_TAG: issue_tag("<sup", t->arg1); break; - case TT_TAG: issue_tag("<tt", t->arg1); break; - case PRE_TAG: out->nl(); issue_tag("<pre", t->arg1); + case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break; + case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break; + case TT_TAG: issue_tag("<tt", (char *)t->arg1); break; + case PRE_TAG: if (t->indent != NULL) { + out->nl(); + out->simple_comment("INDENTATION"); + t->indent->begin(FALSE); + start_space = FALSE; + } + out->enable_newlines(TRUE); + out->nl(); issue_tag("<pre", (char *)t->arg1); out->enable_newlines(FALSE); break; - case SMALL_TAG: issue_tag("<small", t->arg1); break; - case BIG_TAG: issue_tag("<big", t->arg1); break; - case TABLE_TAG: issue_table_begin(t); break; + case SMALL_TAG: issue_tag("<small", (char *)t->arg1); break; + case BIG_TAG: issue_tag("<big", (char *)t->arg1); break; case BREAK_TAG: break; + case COLOR_TAG: issue_color_begin(&t->col); break; default: error("unrecognised tag"); } } -int html_text::table_is_void (tag_definition *t) -{ - if (linelength > 0) { - return( current_indentation*100/linelength <= 0 ); - } else { - return( FALSE ); - } -} - -void html_text::issue_table_begin (tag_definition *t) -{ - if (linelength > 0) { - int width=current_indentation*100/linelength; - - if (width > 0) { - out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"2\" cellspacing=\"0\" cellpadding=\"0\">").nl(); - out->put_string("<tr valign=\"top\" align=\"left\">").nl(); - if ((t->arg1 == 0) || (strcmp(t->arg1, "") == 0)) - out->put_string("<td width=\"").put_number(width).put_string("%\"></td>"); - else { - out->put_string("<td width=\"").put_number(width).put_string("%\">").nl(); - out->put_string(t->arg1).put_string("</td>"); - t->arg1[0] = (char)0; - } - out->put_string("<td width=\"").put_number(100-width).put_string("%\">").nl(); - } - } -} - -void html_text::issue_table_end (void) -{ - out->put_string("</td></table>").nl(); - out->enable_newlines(TRUE); -} - /* * flush_text - flushes html tags which are outstanding on the html stack. */ @@ -190,116 +278,94 @@ int html_text::is_present (HTML_TAG t) tag_definition *p=stackptr; while (p != NULL) { - if (t == p->type) { - return( TRUE ); - } + if (t == p->type) + return TRUE; p = p->next; } - return( FALSE ); + return FALSE; } +extern void stop(); + /* - * push_para - adds a new entry onto the html paragraph stack. + * do_push - places, tag_definition, p, onto the stack */ -void html_text::push_para (HTML_TAG t, char *arg) +void html_text::do_push (tag_definition *p) { - tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + HTML_TAG t = p->type; - p->type = t; - p->arg1 = arg; - p->text_emitted = FALSE; +#if defined(DEBUGGING) + if (t == PRE_TAG) + stop(); + debugStack = TRUE; + fprintf(stderr, "\nentering do_push ("); + dump_stack_element(p); + fprintf(stderr, ")\n"); + dump_stack(); + fprintf(stderr, ")\n"); + fflush(stderr); +#endif /* - * if t is a P_TAG or TABLE_TAG or PRE_TAG make sure it goes on the end of the stack. - * But we insist that a TABLE_TAG is always after a PRE_TAG - * and that a P_TAG is always after a TABLE_TAG + * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack. */ - if (((t == P_TAG) || (t == PRE_TAG) || (t == TABLE_TAG)) && - (lastptr != NULL)) { - if (((lastptr->type == TABLE_TAG) && (t == PRE_TAG)) || - ((lastptr->type == P_TAG) && (t == TABLE_TAG))) { - /* - * insert p before the lastptr - */ - if (stackptr == lastptr) { - /* - * only on element of the stack - */ - p->next = stackptr; - stackptr = p; - } else { - /* - * more than one element is on the stack - */ - tag_definition *q = stackptr; - - while (q->next != lastptr) { - q = q->next; - } - q->next = p; - p->next = lastptr; - } - } else { - /* - * store, p, at the end - */ - lastptr->next = p; - lastptr = p; - p->next = NULL; - } + if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) { + /* + * store, p, at the end + */ + lastptr->next = p; + lastptr = p; + p->next = NULL; } else { p->next = stackptr; if (stackptr == NULL) lastptr = p; stackptr = p; } + +#if defined(DEBUGGING) + dump_stack(); + fprintf(stderr, "exiting do_push\n"); +#endif } /* - * do_indent - remember the indent parameters and if - * indent is > pageoff and indent has changed - * then we start a html table to implement the indentation. + * push_para - adds a new entry onto the html paragraph stack. */ -void html_text::do_indent (char *arg, int indent, int pageoff, int linelen) +void html_text::push_para (HTML_TAG t, void *arg, html_indent *in) { - if ((current_indentation != -1) && - (pageoffset+current_indentation != indent+pageoff)) { - /* - * actual indentation of text has changed, we need to put - * a table tag onto the stack. - */ - do_table(arg); - } - current_indentation = indent; - pageoffset = pageoff; - linelength = linelen; + tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + + p->type = t; + p->arg1 = arg; + p->text_emitted = FALSE; + p->indent = in; + + if (t == PRE_TAG && is_present(PRE_TAG)) + fatal("cannot have multiple PRE_TAGs"); + + do_push(p); } -void html_text::do_table (char *arg) +void html_text::push_para (HTML_TAG t) { - int in_pre = is_in_pre(); - // char *para_type = done_para(); - done_pre(); - shutdown(TABLE_TAG); // shutdown a previous table, if present - remove_break(); - if (in_pre) { - do_pre(); - } - // do_para(para_type); - push_para(TABLE_TAG, arg); + push_para(t, (void *)"", NULL); } -/* - * done_table - terminates a possibly existing table. - */ - -void html_text::done_table (void) +void html_text::push_para (color *c) { - shutdown(TABLE_TAG); - space_emitted = TRUE; + tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + + p->type = COLOR_TAG; + p->arg1 = NULL; + p->col = *c; + p->text_emitted = FALSE; + p->indent = NULL; + + do_push(p); } /* @@ -308,11 +374,8 @@ void html_text::done_table (void) void html_text::do_italic (void) { - done_bold(); - done_tt(); - if (! is_present(I_TAG)) { - push_para(I_TAG, ""); - } + if (! is_present(I_TAG)) + push_para(I_TAG); } /* @@ -321,11 +384,8 @@ void html_text::do_italic (void) void html_text::do_bold (void) { - done_italic(); - done_tt(); - if (! is_present(B_TAG)) { - push_para(B_TAG, ""); - } + if (! is_present(B_TAG)) + push_para(B_TAG); } /* @@ -334,11 +394,8 @@ void html_text::do_bold (void) void html_text::do_tt (void) { - done_bold(); - done_italic(); - if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) { - push_para(TT_TAG, ""); - } + if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) + push_para(TT_TAG); } /* @@ -347,13 +404,15 @@ void html_text::do_tt (void) void html_text::do_pre (void) { - done_bold(); - done_italic(); done_tt(); - (void)done_para(); - if (! is_present(PRE_TAG)) { - push_para(PRE_TAG, ""); - } + if (is_present(P_TAG)) { + html_indent *i = remove_indent(P_TAG); + (void)done_para(); + if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, i); + } else if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, NULL); + dump_stack(); } /* @@ -363,16 +422,26 @@ void html_text::do_pre (void) int html_text::is_in_pre (void) { - return( is_present(PRE_TAG) ); + return is_present(PRE_TAG); +} + +/* + * do_color - initiates a new color tag. + */ + +void html_text::do_color (color *c) +{ + shutdown(COLOR_TAG); // shutdown a previous color tag, if present + push_para(c); } /* - * is_in_table - returns TRUE if we are currently within a table. + * done_color - shutdown an outstanding color tag, if it exists. */ -int html_text::is_in_table (void) +void html_text::done_color (void) { - return( is_present(TABLE_TAG) ); + shutdown(COLOR_TAG); } /* @@ -388,6 +457,7 @@ char *html_text::shutdown (HTML_TAG t) tag_definition *temp =NULL; int notext =TRUE; + dump_stack(); while ((stackptr != NULL) && (stackptr->type != t)) { notext = (notext && (! stackptr->text_emitted)); if (! notext) { @@ -417,12 +487,14 @@ char *html_text::shutdown (HTML_TAG t) end_tag(stackptr); } if (t == P_TAG) { - arg = stackptr->arg1; + arg = (char *)stackptr->arg1; } p = stackptr; stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; + if (p->indent != NULL) + delete p->indent; free(p); } @@ -430,13 +502,16 @@ char *html_text::shutdown (HTML_TAG t) * and restore unaffected tags */ while (temp != NULL) { - push_para(temp->type, temp->arg1); + if (temp->type == COLOR_TAG) + push_para(&temp->col); + else + push_para(temp->type, temp->arg1, temp->indent); p = temp; temp = temp->next; free(p); } } - return( arg ); + return arg; } /* @@ -519,37 +594,9 @@ void html_text::done_big (void) void html_text::check_emit_text (tag_definition *t) { if ((t != NULL) && (! t->text_emitted)) { - /* - * we peep and see whether there is a <p> before the <table> - * in which case we skip the <p> - */ - if (t->type == TABLE_TAG) { - if (table_is_void(t)) { - tag_definition *n = t->next; - remove_def(t); - check_emit_text(n); - } else { - /* - * a table which will be emitted, is there a <p> succeeding it? - */ - if ((t->next != NULL) && - (t->next->type == P_TAG) && - ((t->next->arg1 == 0) || strcmp(t->next->arg1, "") == 0)) { - /* - * yes skip the <p> - */ - check_emit_text(t->next->next); - } else { - check_emit_text(t->next); - } - t->text_emitted = TRUE; - start_tag(t); - } - } else { - check_emit_text(t->next); - t->text_emitted = TRUE; - start_tag(t); - } + check_emit_text(t->next); + t->text_emitted = TRUE; + start_tag(t); } } @@ -557,7 +604,7 @@ void html_text::check_emit_text (tag_definition *t) * do_emittext - tells the class that text was written during the current tag. */ -void html_text::do_emittext (char *s, int length) +void html_text::do_emittext (const char *s, int length) { if ((! is_present(P_TAG)) && (! is_present(PRE_TAG))) do_para(""); @@ -577,25 +624,47 @@ void html_text::do_emittext (char *s, int length) } out->put_string(s, length); space_emitted = FALSE; + blank_para = FALSE; } /* - * do_para- starts a new paragraph + * do_para - starts a new paragraph */ -void html_text::do_para (char *arg) +void html_text::do_para (const char *arg, html_indent *in) { - done_pre(); if (! is_present(P_TAG)) { - remove_sub_sup(); - if ((arg != 0) && (strcmp(arg, "") != 0)) { - remove_tag(TABLE_TAG); + if (is_present(PRE_TAG)) { + html_indent *i = remove_indent(PRE_TAG); + done_pre(); + if (i == in || in == NULL) + in = i; + else + delete i; } - push_para(P_TAG, arg); + remove_sub_sup(); + push_para(P_TAG, (void *)arg, in); space_emitted = TRUE; } } +void html_text::do_para (const char *arg) +{ + do_para(arg, NULL); +} + +void html_text::do_para (simple_output *op, const char *arg1, + int indentation, int pageoffset, int linelength) +{ + html_indent *indent; + + if (indentation == 0) + indent = NULL; + else + indent = new html_indent(op, indentation, pageoffset, linelength); + do_para(arg1, indent); +} + /* * done_para - shuts down a paragraph tag. */ @@ -603,7 +672,27 @@ void html_text::do_para (char *arg) char *html_text::done_para (void) { space_emitted = TRUE; - return( shutdown(P_TAG) ); + return shutdown(P_TAG); +} + +/* + * remove_indent - returns the indent associated with, tag. + * The indent associated with tag is set to NULL. + */ + +html_indent *html_text::remove_indent (HTML_TAG tag) +{ + tag_definition *p=stackptr; + + while (p != NULL) { + if (tag == p->type) { + html_indent *i = p->indent; + p->indent = NULL; + return i; + } + p = p->next; + } + return NULL; } /* @@ -613,11 +702,19 @@ char *html_text::done_para (void) void html_text::do_space (void) { if (is_in_pre()) { - do_emittext("", 0); + if (blank_para) + start_space = TRUE; + else { + do_emittext("", 0); + out->nl(); + } } else { - do_para(done_para()); + html_indent *i = remove_indent(P_TAG); + + do_para(done_para(), i); + space_emitted = TRUE; + start_space = TRUE; } - space_emitted = TRUE; } /* @@ -629,7 +726,7 @@ void html_text::do_break (void) if (! is_present(PRE_TAG)) { if (emitted_text()) { if (! is_present(BREAK_TAG)) { - push_para(BREAK_TAG, ""); + push_para(BREAK_TAG); } } } @@ -654,7 +751,25 @@ void html_text::do_newline (void) int html_text::emitted_text (void) { - return( ! space_emitted); + return !space_emitted; +} + +/* + * ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph. + */ + +int html_text::ever_emitted_text (void) +{ + return !blank_para; +} + +/* + * starts_with_space - returns TRUE if we have start this paragraph with a .sp + */ + +int html_text::starts_with_space (void) +{ + return start_space; } /* @@ -758,9 +873,9 @@ int html_text::remove_break (void) if (stackptr == NULL) lastptr = NULL; q = stackptr; - } else if (l == 0) { + } else if (l == 0) error("stack list pointers are wrong"); - } else { + else { l->next = p->next; q = p->next; if (l->next == NULL) @@ -772,13 +887,35 @@ int html_text::remove_break (void) * now determine whether text was issued before <br> */ while (q != 0) { - if (q->text_emitted) { - return( TRUE ); - } else { + if (q->text_emitted) + return TRUE; + else q = q->next; + } + return FALSE; +} + +/* + * remove_para_align - removes a paragraph which has a text + * argument. If the paragraph has no text + * argument then it is left alone. + */ + +void html_text::remove_para_align (void) +{ + if (is_present(P_TAG)) { + tag_definition *p=stackptr; + + while (p != NULL) { + if (p->type == P_TAG && p->arg1 != NULL) { + html_indent *i = remove_indent(P_TAG); + done_para(); + do_para("", i); + return; + } + p = p->next; } } - return( FALSE ); } /* @@ -789,11 +926,10 @@ int html_text::remove_break (void) void html_text::do_small (void) { - if (is_present(BIG_TAG)) { + if (is_present(BIG_TAG)) done_big(); - } else { - push_para(SMALL_TAG, ""); - } + else + push_para(SMALL_TAG); } /* @@ -802,11 +938,10 @@ void html_text::do_small (void) void html_text::do_big (void) { - if (is_present(SMALL_TAG)) { + if (is_present(SMALL_TAG)) done_small(); - } else { - push_para(BIG_TAG, ""); - } + else + push_para(BIG_TAG); } /* @@ -815,7 +950,7 @@ void html_text::do_big (void) void html_text::do_sup (void) { - push_para(SUP_TAG, ""); + push_para(SUP_TAG); } /* @@ -824,6 +959,6 @@ void html_text::do_sup (void) void html_text::do_sub (void) { - push_para(SUB_TAG, ""); + push_para(SUB_TAG); } diff --git a/contrib/groff/src/devices/grohtml/html-text.h b/contrib/groff/src/devices/grohtml/html-text.h index 5bbcd43..c43cbda 100644 --- a/contrib/groff/src/devices/grohtml/html-text.h +++ b/contrib/groff/src/devices/grohtml/html-text.h @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc * @@ -26,18 +26,22 @@ with groff; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "html.h" +#include "html-table.h" /* * html tags */ typedef enum {I_TAG, B_TAG, P_TAG, SUB_TAG, SUP_TAG, TT_TAG, - PRE_TAG, SMALL_TAG, BIG_TAG, BREAK_TAG, TABLE_TAG} HTML_TAG; + PRE_TAG, SMALL_TAG, BIG_TAG, BREAK_TAG, + COLOR_TAG} HTML_TAG; typedef struct tag_definition { HTML_TAG type; - char *arg1; + void *arg1; int text_emitted; + color col; + html_indent *indent; tag_definition *next; } tag_definition ; @@ -49,61 +53,73 @@ typedef struct tag_definition { class html_text { public: - html_text (simple_output *op); - ~html_text (void); - void flush_text (void); - void do_emittext (char *s, int length); - void do_italic (void); - void do_bold (void); - void do_roman (void); - void do_tt (void); - void do_pre (void); - void do_small (void); - void do_big (void); - void do_para (char *arg1); - void do_sup (void); - void do_sub (void); - void do_space (void); - void do_break (void); - void do_newline (void); - void do_table (char *arg); - void done_bold (void); - void done_italic (void); - char *done_para (void); - void done_sup (void); - void done_sub (void); - void done_tt (void); - void done_pre (void); - void done_small (void); - void done_big (void); - void do_indent (char *arg, int indent, int pageoff, int linelen); - int emitted_text (void); - void emit_space (void); - int is_in_pre (void); - void remove_tag (HTML_TAG tag); - void remove_sub_sup (void); - void done_table (void); - int is_in_table (void); + html_text (simple_output *op); + ~html_text (void); + void flush_text (void); + void do_emittext (const char *s, int length); + void do_italic (void); + void do_bold (void); + void do_roman (void); + void do_tt (void); + void do_pre (void); + void do_small (void); + void do_big (void); + void do_para (const char *arg); // used for no indentation + void do_para (simple_output *op, const char *arg1, + int indentation, int pageoffset, int linelength); + void do_sup (void); + void do_sub (void); + void do_space (void); + void do_break (void); + void do_newline (void); + void do_table (const char *arg); + void done_bold (void); + void done_italic (void); + char *done_para (void); + void done_sup (void); + void done_sub (void); + void done_tt (void); + void done_pre (void); + void done_small (void); + void done_big (void); + void do_color (color *c); + void done_color (void); + int emitted_text (void); + int ever_emitted_text (void); + int starts_with_space (void); + void emit_space (void); + int is_in_pre (void); + void remove_tag (HTML_TAG tag); + void remove_sub_sup (void); + void remove_para_align (void); private: tag_definition *stackptr; /* the current paragraph state */ tag_definition *lastptr; /* the end of the stack */ simple_output *out; - int space_emitted; - int current_indentation; /* current .in value */ - int pageoffset; /* .po value */ - int linelength; /* current line length */ + int space_emitted; /* just emitted a space? */ + int current_indentation; /* current .in value */ + int pageoffset; /* .po value */ + int linelength; /* current line length */ + int blank_para; /* have we ever written text? */ + int start_space; /* does para start with a .sp */ + html_indent *indent; /* our indent class */ - int is_present (HTML_TAG t); - void end_tag (tag_definition *t); - void start_tag (tag_definition *t); - void push_para (HTML_TAG t, char *arg); - char *shutdown (HTML_TAG t); - void check_emit_text (tag_definition *t); - int remove_break (void); - void issue_tag (char *tagname, char *arg); - void issue_table_begin (tag_definition *t); - void issue_table_end (void); - int table_is_void (tag_definition *t); - void remove_def (tag_definition *t); + int is_present (HTML_TAG t); + void end_tag (tag_definition *t); + void start_tag (tag_definition *t); + void do_para (const char *arg, html_indent *in); + void push_para (HTML_TAG t); + void push_para (HTML_TAG t, void *arg, html_indent *in); + void push_para (color *c); + void do_push (tag_definition *p); + char *shutdown (HTML_TAG t); + void check_emit_text (tag_definition *t); + int remove_break (void); + void issue_tag (char *tagname, char *arg); + void issue_color_begin (color *c); + void remove_def (tag_definition *t); + html_indent *remove_indent (HTML_TAG tag); + void dump_stack_element (tag_definition *p); + void dump_stack (void); }; diff --git a/contrib/groff/src/devices/grohtml/html.h b/contrib/groff/src/devices/grohtml/html.h index 69b6e35..431647c 100644 --- a/contrib/groff/src/devices/grohtml/html.h +++ b/contrib/groff/src/devices/grohtml/html.h @@ -20,8 +20,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #if !defined(HTML_H) # define HTML_H -# undef DEBUGGING -// # define DEBUGGING /* * class and structure needed to buffer words @@ -53,6 +51,7 @@ public: simple_output(FILE *, int max_line_length); simple_output &put_string(const char *, int); simple_output &put_string(const char *s); + simple_output &put_string(const string &s); simple_output &put_troffps_char (const char *s); simple_output &put_translated_string(const char *s); simple_output &put_number(int); diff --git a/contrib/groff/src/devices/grohtml/output.cc b/contrib/groff/src/devices/grohtml/output.cc index 88ab7d6..67d5874 100644 --- a/contrib/groff/src/devices/grohtml/output.cc +++ b/contrib/groff/src/devices/grohtml/output.cc @@ -38,6 +38,9 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <unistd.h> #endif +#undef DEBUGGING +// #define DEBUGGING + #if !defined(TRUE) # define TRUE (1==1) #endif @@ -45,6 +48,18 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define FALSE (1==0) #endif + +#if defined(DEBUGGING) +# define FPUTC(X,Y) do { fputc((X),(Y)); fputc((X), stderr); fflush(stderr); } while (0) +# define FPUTS(X,Y) do { fputs((X),(Y)); fputs((X), stderr); fflush(stderr); } while (0) +# define PUTC(X,Y) do { putc((X),(Y)); putc((X), stderr); fflush(stderr); } while (0) +#else +# define FPUTC(X,Y) do { fputc((X),(Y)); } while (0) +# define FPUTS(X,Y) do { fputs((X),(Y)); } while (0) +# define PUTC(X,Y) do { putc((X),(Y)); } while (0) +#endif + + /* * word - initialise a word and set next to NULL */ @@ -88,7 +103,7 @@ int word_list::flush (FILE *f) while (head != 0) { t = head; head = head->next; - fputs(t->s, f); + FPUTS(t->s, f); delete t; } head = 0; @@ -146,7 +161,7 @@ simple_output &simple_output::copy_file(FILE *infp) { int c; while ((c = getc(infp)) != EOF) - putc(c, fp); + PUTC(c, fp); return *this; } @@ -154,7 +169,7 @@ simple_output &simple_output::end_line() { flush_last_word(); if (col != 0) { - putc('\n', fp); + PUTC('\n', fp); col = 0; } return *this; @@ -169,10 +184,10 @@ simple_output &simple_output::simple_comment(const char *s) { flush_last_word(); if (col != 0) - putc('\n', fp); - fputs("<!-- ", fp); - fputs(s, fp); - fputs(" -->\n", fp); + PUTC('\n', fp); + FPUTS("<!-- ", fp); + FPUTS(s, fp); + FPUTS(" -->\n", fp); col = 0; return *this; } @@ -181,7 +196,7 @@ simple_output &simple_output::begin_comment(const char *s) { flush_last_word(); if (col != 0) - putc('\n', fp); + PUTC('\n', fp); col = 0; put_string("<!--"); space_or_newline(); @@ -205,7 +220,7 @@ simple_output &simple_output::end_comment() simple_output &simple_output::check_newline(int n) { if ((col + n + last_word.get_length() + 1 > max_line_length) && (newlines)) { - fputc('\n', fp); + FPUTC('\n', fp); col = last_word.flush(fp); } return *this; @@ -218,11 +233,8 @@ simple_output &simple_output::check_newline(int n) simple_output &simple_output::space_or_newline (void) { -#if defined(DEBUGGING) - fflush(fp); // just for testing -#endif if ((col + last_word.get_length() + 1 > max_line_length) && (newlines)) { - fputc('\n', fp); + FPUTC('\n', fp); if (last_word.get_length() > 0) { col = last_word.flush(fp); } else { @@ -231,7 +243,7 @@ simple_output &simple_output::space_or_newline (void) } else { if (last_word.get_length() != 0) { if (col > 0) { - fputc(' ', fp); + FPUTC(' ', fp); col++; } col += last_word.flush(fp); @@ -250,7 +262,7 @@ simple_output &simple_output::nl (void) space_or_newline(); col += last_word.flush(fp); if (col != 0) { - fputc('\n', fp); + FPUTC('\n', fp); col = 0; } return *this ; @@ -266,7 +278,7 @@ simple_output &simple_output::set_fixed_point(int n) simple_output &simple_output::put_raw_char(char c) { col += last_word.flush(fp); - putc(c, fp); + PUTC(c, fp); col++; return *this; } @@ -283,6 +295,12 @@ simple_output &simple_output::put_string(const char *s) return *this; } +simple_output &simple_output::put_string(const string &s) +{ + last_word.add_word(s.contents(), s.length()); + return *this; +} + simple_output &simple_output::put_number(int n) { char buf[1 + INT_DIGITS + 1]; @@ -322,15 +340,15 @@ void simple_output::flush_last_word (void) if (len > 0) { if (newlines) { if (col + len + 1 > max_line_length) { - fputs("\n", fp); + FPUTS("\n", fp); col = 0; } else { - fputs(" ", fp); + FPUTS(" ", fp); col++; } len += last_word.flush(fp); } else { - fputs(" ", fp); + FPUTS(" ", fp); col++; col += last_word.flush(fp); } diff --git a/contrib/groff/src/devices/grohtml/post-html.cc b/contrib/groff/src/devices/grohtml/post-html.cc index 0c36941..4431f17 100644 --- a/contrib/groff/src/devices/grohtml/post-html.cc +++ b/contrib/groff/src/devices/grohtml/post-html.cc @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cc * but it owes a huge amount of ideas and raw code from @@ -28,6 +28,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "cset.h" #include "html.h" #include "html-text.h" +#include "html-table.h" #include <time.h> @@ -47,25 +48,26 @@ extern "C" const char *Version_string; # define FALSE (1==0) #endif -#define MAX_STRING_LENGTH 4096 #define MAX_LINE_LENGTH 60 /* maximum characters we want in a line */ #define SIZE_INCREMENT 2 /* font size increment <big> = +2 */ #define BASE_POINT_SIZE 10 /* 10 points is the base size ie html size 3 */ #define CENTER_TOLERANCE 2 /* how many pixels off center will we still */ -#define ANCHOR_TEMPLATE "heading%d" /* if simple anchor is set we use this */ +#define ANCHOR_TEMPLATE "heading" /* if simple anchor is set we use this */ #define UNICODE_DESC_START 0x80 /* all character entities above this are */ /* either encoded by their glyph names or if */ /* there is no name then we use &#nnn; */ -#define INDENTATION /* #undef INDENTATION to remove .in handling */ - typedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT; +typedef enum {col_tag, tab_tag, tab0_tag, none} colType; + +#undef DEBUG_TABLES + /* * prototypes */ -void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len, int and_single); -char *get_html_translation (font *f, const char *name); +char *get_html_translation (font *f, const string &name); +int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single); static int auto_links = TRUE; /* by default we enable automatic links at */ @@ -73,6 +75,9 @@ static int auto_links = TRUE; /* by default we enable aut static int auto_rule = TRUE; /* by default we enable an automatic rule */ /* at the top and bottom of the document */ static int simple_anchors = FALSE; /* default to anchors with heading text */ +static int manufacture_headings = FALSE; /* default is to use the Hn html headings, */ + /* rather than manufacture our own. */ +static color *default_background = NULL; /* has user requested initial bg color? */ /* @@ -83,41 +88,27 @@ void stop () {} static int min (int a, int b) { - if (a < b) { - return( a ); - } else { - return( b ); - } + if (a < b) + return a; + else + return b; } static int max (int a, int b) { - if (a > b) { - return( a ); - } else { - return( b ); - } + if (a > b) + return a; + else + return b; } /* - * is_subsection - returns TRUE if a1..a2 is within b1..b2 - */ - -#if 0 -static int is_subsection (int a1, int a2, int b1, int b2) -{ - // easier to see whether this is not the case - return( !((a1 < b1) || (a1 > b2) || (a2 < b1) || (a2 > b2)) ); -} -#endif - -/* * is_intersection - returns TRUE if range a1..a2 intersects with b1..b2 */ static int is_intersection (int a1, int a2, int b1, int b2) { - // again easier to prove NOT outside limits + // easier to prove NOT outside limits return( ! ((a1 > b2) || (a2 < b1)) ); } @@ -230,8 +221,9 @@ struct style { int font_no; int height; int slant; + color col; style (); - style (font *, int, int, int, int); + style (font *, int, int, int, int, color); int operator == (const style &) const; int operator != (const style &) const; }; @@ -241,15 +233,15 @@ style::style() { } -style::style(font *p, int sz, int h, int sl, int no) - : f(p), point_size(sz), font_no(no), height(h), slant(sl) +style::style(font *p, int sz, int h, int sl, int no, color c) + : f(p), point_size(sz), font_no(no), height(h), slant(sl), col(c) { } int style::operator==(const style &s) const { return (f == s.f && point_size == s.point_size - && height == s.height && slant == s.slant); + && height == s.height && slant == s.slant && col == s.col); } int style::operator!=(const style &s) const @@ -263,23 +255,33 @@ int style::operator!=(const style &s) const struct char_block { enum { SIZE = 256 }; - char buffer[SIZE]; + char *buffer; int used; char_block *next; char_block(); + char_block::char_block(int length); }; char_block::char_block() +: buffer(NULL), used(0), next(0) +{ +} + +char_block::char_block(int length) : used(0), next(0) { + buffer = (char *)malloc(max(length, char_block::SIZE)); + if (buffer == NULL) + fatal("out of memory error"); } class char_buffer { public: char_buffer(); ~char_buffer(); - char *add_string(char *, unsigned int); + char *add_string(const char *, unsigned int); + char *add_string(const string &); private: char_block *head; char_block *tail; @@ -299,24 +301,23 @@ char_buffer::~char_buffer() } } -char *char_buffer::add_string (char *s, unsigned int length) +char *char_buffer::add_string (const char *s, unsigned int length) { int i=0; unsigned int old_used; + if (s == NULL || length == 0) + return NULL; + if (tail == 0) { - tail = new char_block; + tail = new char_block(length+1); head = tail; } else { if (tail->used + length+1 > char_block::SIZE) { - tail->next = new char_block; - tail = tail->next; + tail->next = new char_block(length+1); + tail = tail->next; } } - // at this point we have a tail which is ready for the string. - if (tail->used + length+1 > char_block::SIZE) { - fatal("need to increase char_block::SIZE"); - } old_used = tail->used; do { @@ -336,59 +337,196 @@ char *char_buffer::add_string (char *s, unsigned int length) return( &tail->buffer[old_used] ); } +char *char_buffer::add_string (const string &s) +{ + return add_string(s.contents(), s.length()); +} + /* * the classes and methods for maintaining glyph positions. */ class text_glob { public: - text_glob (style *s, char *string, unsigned int length, - int min_vertical , int min_horizontal, - int max_vertical , int max_horizontal, - int is_html , int is_troff_command, - int is_auto_image, - int is_a_line , int thickness); - text_glob (void); - ~text_glob (void); - int is_a_line (void); - int is_a_tag (void); - int is_raw (void); - int is_eol (void); - int is_auto_img (void); - int is_br (void); + void text_glob_html (style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal); + void text_glob_special (style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal); + void text_glob_line (style *s, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal, + int thickness); + void text_glob_auto_image(style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal); + void text_glob_tag (style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal); + + text_glob (void); + ~text_glob (void); + int is_a_line (void); + int is_a_tag (void); + int is_eol (void); + int is_auto_img (void); + int is_br (void); + int is_in (void); + int is_po (void); + int is_ti (void); + int is_ce (void); + int is_eol_ce (void); + int is_col (void); + int is_tab (void); + int is_tab0 (void); + int is_ta (void); + int is_tab_ts (void); + int is_tab_te (void); + int is_nf (void); + int is_fi (void); + int get_arg (void); + int get_tab_args (char *align); + + void remember_table (html_table *t); + html_table *get_table (void); style text_style; - char *text_string; + const char *text_string; unsigned int text_length; int minv, minh, maxv, maxh; - int is_raw_command; // should the text be sent directly to the device? int is_tag; // is this a .br, .sp, .tl etc int is_img_auto; // image created by eqn delim + int is_special; // text has come via 'x X html:' int is_line; // is the command a <line>? int thickness; // the thickness of a line + html_table *tab; // table description + +private: + text_glob (style *s, char *str, int length, + int min_vertical , int min_horizontal, + int max_vertical , int max_horizontal, + bool is_troff_command, + bool is_auto_image, bool is_special_command, + bool is_a_line , int thickness); }; -text_glob::text_glob (style *s, char *string, unsigned int length, +text_glob::text_glob (style *s, char *str, int length, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal, - int is_html, int is_troff_command, - int is_auto_image, - int is_a_line, int line_thickness) - : text_style(*s), text_string(string), text_length(length), + bool is_troff_command, + bool is_auto_image, bool is_special_command, + bool is_a_line, int line_thickness) + : text_style(*s), text_string(str), text_length(length), minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal), - is_raw_command(is_html), is_tag(is_troff_command), is_img_auto(is_auto_image), - is_line(is_a_line), thickness(line_thickness) + is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command), + is_line(is_a_line), thickness(line_thickness), tab(NULL) { } text_glob::text_glob () : text_string(0), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1), - is_raw_command(FALSE), is_tag(FALSE), is_line(FALSE), thickness(0) + is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL) { } text_glob::~text_glob () { + if (tab != NULL) + delete tab; +} + +/* + * text_glob_html - used to place html text into the glob buffer. + */ + +void text_glob::text_glob_html (style *s, char *str, int length, + int min_vertical , int min_horizontal, + int max_vertical , int max_horizontal) +{ + text_glob *g = new text_glob(s, str, length, + min_vertical, min_horizontal, max_vertical, max_horizontal, + FALSE, FALSE, FALSE, FALSE, 0); + *this = *g; +} + +/* + * text_glob_html - used to place html specials into the glob buffer. + * This text is essentially html commands coming through + * from the macro sets, with special designated sequences of + * characters translated into html. See add_and_encode. + */ + +void text_glob::text_glob_special (style *s, char *str, int length, + int min_vertical , int min_horizontal, + int max_vertical , int max_horizontal) +{ + text_glob *g = new text_glob(s, str, length, + min_vertical, min_horizontal, max_vertical, max_horizontal, + FALSE, FALSE, TRUE, FALSE, 0); + *this = *g; +} + +/* + * text_glob_line - record horizontal draw line commands. + */ + +void text_glob::text_glob_line (style *s, + int min_vertical , int min_horizontal, + int max_vertical , int max_horizontal, + int thickness) +{ + text_glob *g = new text_glob(s, "", 0, + min_vertical, min_horizontal, max_vertical, max_horizontal, + FALSE, FALSE, FALSE, TRUE, thickness); + *this = *g; +} + +/* + * text_glob_auto_image - record the presence of a .auto-image tag command. + * Used to mark that an image has been created automatically + * by a preprocessor and (pre-grohtml/troff) combination. + * Under some circumstances images may not be created. + * (consider .EQ + * delim $$ + * .EN + * .TS + * tab(!), center; + * l!l. + * $1 over x$!recripical of x + * .TE + * + * the first auto-image marker is created via .EQ/.EN pair + * and no image is created. + * The second auto-image marker occurs at $1 over x$ + * Currently this image will not be created + * as the whole of the table is created as an image. + * (Once html tables are handled by grohtml this will change. + * Shortly this will be the case). + */ + +void text_glob::text_glob_auto_image(style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal) +{ + text_glob *g = new text_glob(s, str, length, + min_vertical, min_horizontal, max_vertical, max_horizontal, + TRUE, TRUE, FALSE, FALSE, 0); + *this = *g; +} + +/* + * text_glob_tag - records a troff tag. + */ + +void text_glob::text_glob_tag (style *s, char *str, int length, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal) +{ + text_glob *g = new text_glob(s, str, length, + min_vertical, min_horizontal, max_vertical, max_horizontal, + TRUE, FALSE, FALSE, FALSE, 0); + *this = *g; } /* @@ -397,7 +535,7 @@ text_glob::~text_glob () int text_glob::is_a_line (void) { - return( is_line ); + return is_line; } /* @@ -406,7 +544,7 @@ int text_glob::is_a_line (void) int text_glob::is_a_tag (void) { - return( is_tag ); + return is_tag; } /* @@ -419,12 +557,121 @@ int text_glob::is_eol (void) } /* - * is_raw - returns TRUE if glob contains raw html. + * is_eol_ce - returns TRUE if glob contains the tag eol.ce + */ + +int text_glob::is_eol_ce (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0) ); +} + + +/* + * is_nf - returns TRUE if glob contains the tag .nf + */ + +int text_glob::is_nf (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:.nf") == 0) ); +} + +/* + * is_fi - returns TRUE if glob contains the tag .fi + */ + +int text_glob::is_fi (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:.fi") == 0) ); +} + +/* + * is_ce - returns TRUE if glob contains the tag .ce + */ + +int text_glob::is_ce (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:.ce") == 0) ); +} + +/* + * is_in - returns TRUE if glob contains the tag .in + */ + +int text_glob::is_in (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:.in ", strlen("html-tag:.in ")) == 0) ); +} + +/* + * is_po - returns TRUE if glob contains the tag .po */ -int text_glob::is_raw (void) +int text_glob::is_po (void) { - return( is_raw_command ); + return( is_tag && (strncmp(text_string, "html-tag:.po ", strlen("html-tag:.po ")) == 0) ); +} + +/* + * is_ti - returns TRUE if glob contains the tag .ti + */ + +int text_glob::is_ti (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:.ti ", strlen("html-tag:.ti ")) == 0) ); +} + +/* + * is_col - returns TRUE if glob contains the tag .col + */ + +int text_glob::is_col (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:.col", strlen("html-tag:.col")) == 0) ); +} + +/* + * is_tab_ts - returns TRUE if glob contains the tag .tab_ts + */ + +int text_glob::is_tab_ts (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0) ); +} + +/* + * is_tab_te - returns TRUE if glob contains the tag .tab_te + */ + +int text_glob::is_tab_te (void) +{ + return( is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0) ); +} + +/* + * is_ta - returns TRUE if glob contains the tag .ta + */ + +int text_glob::is_ta (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:.ta ", strlen("html-tag:.ta ")) == 0) ); +} + +/* + * is_tab - returns TRUE if glob contains the tag tab + */ + +int text_glob::is_tab (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:tab ", strlen("html-tag:tab ")) == 0) ); +} + +/* + * is_tab0 - returns TRUE if glob contains the tag tab0 + */ + +int text_glob::is_tab0 (void) +{ + return( is_tag && (strncmp(text_string, "html-tag:tab0", strlen("html-tag:tab0")) == 0) ); } /* @@ -434,16 +681,82 @@ int text_glob::is_raw (void) int text_glob::is_auto_img (void) { - return( is_img_auto ); + return is_img_auto; } /* * is_br - returns TRUE if the glob is a tag containing a .br + * or an implied .br. Note that we do not include .nf or .fi + * as grohtml will place a .br after these commands if they + * should break the line. */ int text_glob::is_br (void) { - return( is_a_tag() && (strcmp("html-tag:.br", text_string) == 0) ); + return( is_a_tag() && ((strcmp ("html-tag:.br", text_string) == 0) || + (strncmp("html-tag:.sp", text_string, 11) == 0) || + (strcmp ("html-tag:.ce", text_string) == 0)) ); +} + +int text_glob::get_arg (void) +{ + if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { + const char *p = text_string; + + while ((*p != (char)0) && (!isspace(*p))) + p++; + while ((*p != (char)0) && (isspace(*p))) + p++; + if (*p == (char)0) + return -1; + return atoi(p); + } + return -1; +} + +/* + * get_tab_args - returns the tab position and alignment of the tab tag + */ + +int text_glob::get_tab_args (char *align) +{ + if (strncmp("html-tag:", text_string, strlen("html-tag:")) == 0) { + const char *p = text_string; + + // firstly the alignment C|R|L + while ((*p != (char)0) && (!isspace(*p))) + p++; + while ((*p != (char)0) && (isspace(*p))) + p++; + *align = *p; + // now the int value + while ((*p != (char)0) && (!isspace(*p))) + p++; + while ((*p != (char)0) && (isspace(*p))) + p++; + if (*p == (char)0) + return -1; + return atoi(p); + } + return -1; +} + +/* + * remember_table - saves table, t, in the text_glob. + */ + +void text_glob::remember_table (html_table *t) +{ + tab = t; +} + +/* + * get_table - returns the stored table description. + */ + +html_table *text_glob::get_table (void) +{ + return tab; } /* @@ -502,6 +815,8 @@ public: int is_equal_to_head (void); void start_from_head (void); void start_from_tail (void); + void insert (text_glob *in); + void move_to (text_glob *in); text_glob *move_right_get_data (void); text_glob *move_left_get_data (void); text_glob *get_data (void); @@ -569,6 +884,7 @@ void list::add (text_glob *in, int line_number, int min_vertical, int min_horizo if (head == 0) { head = t; tail = t; + ptr = t; t->left = t; t->right = t; } else { @@ -719,7 +1035,7 @@ text_glob* list::move_right_get_data (void) /* * move_left_get_data - returns the datum referenced via ptr and moves - * ptr right. + * ptr right. */ text_glob* list::move_left_get_data (void) @@ -733,21 +1049,55 @@ text_glob* list::move_left_get_data (void) } /* + * insert - inserts data after the current position. + */ + +void list::insert (text_glob *in) +{ + if (is_empty()) + fatal("list must not be empty if we are inserting data"); + else { + if (ptr == 0) + ptr = head; + + element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, ptr->maxv, ptr->maxh); + if (ptr == tail) + tail = t; + ptr->right->left = t; + t->right = ptr->right; + ptr->right = t; + t->left = ptr; + } +} + +/* + * move_to - moves the current position to the point where data, in, exists. + * This is an expensive method and should be used sparingly. + */ + +void list::move_to (text_glob *in) +{ + ptr = head; + while (ptr != tail && ptr->datum != in) + ptr = ptr->right; +} + +/* * page class and methods */ class page { public: page (void); - void add (style *s, char *string, unsigned int length, + void add (style *s, const string &str, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal); - void add_html (style *s, char *string, unsigned int length, + void add_tag (style *s, const string &str, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal); - void add_tag (style *s, char *string, unsigned int length, + void add_and_encode (style *s, const string &str, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal); @@ -755,6 +1105,7 @@ public: int line_number, int x1, int y1, int x2, int y2, int thickness); + void insert_tag (const string &str); void dump_page (void); // debugging method // and the data @@ -767,32 +1118,34 @@ page::page() { } -void page::add (style *s, char *string, unsigned int length, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) +/* + * insert_tag - inserts a tag after the current position. + */ + +void page::insert_tag (const string &str) { - if (length > 0) { - text_glob *g=new text_glob(s, buffer.add_string(string, length), length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, FALSE, FALSE, FALSE, 0); - glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); + if (str.length() > 0) { + text_glob *g=new text_glob(); + text_glob *f=glyphs.get_data(); + g->text_glob_tag(&f->text_style, buffer.add_string(str), str.length(), + f->minv, f->minh, f->maxv, f->maxh); + glyphs.insert(g); } } /* - * add_html - add a raw html command, for example mailto, line, background, image etc. + * add - add html text to the list of glyphs. */ -void page::add_html (style *s, char *string, unsigned int length, - int line_number, - int min_vertical, int min_horizontal, - int max_vertical, int max_horizontal) +void page::add (style *s, const string &str, + int line_number, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal) { - if (length > 0) { - text_glob *g=new text_glob(s, buffer.add_string(string, length), length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - TRUE, FALSE, FALSE, FALSE, 0); + if (str.length() > 0) { + text_glob *g=new text_glob(); + g->text_glob_html(s, buffer.add_string(str), str.length(), + min_vertical, min_horizontal, max_vertical, max_horizontal); glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); } } @@ -801,17 +1154,23 @@ void page::add_html (style *s, char *string, unsigned int length, * add_tag - adds a troff tag, for example: .tl .sp .br */ -void page::add_tag (style *s, char *string, unsigned int length, +void page::add_tag (style *s, const string &str, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal) { - if (length > 0) { - text_glob *g=new text_glob(s, buffer.add_string(string, length), length, - min_vertical, min_horizontal, max_vertical, max_horizontal, - FALSE, TRUE, - (strncmp(string, "html-tag:.auto-image", 20) == 0), - FALSE, 0); + if (str.length() > 0) { + text_glob *g; + + if (strncmp((str+'\0').contents(), "html-tag:.auto-image", 20) == 0) { + g = new text_glob(); + g->text_glob_auto_image(s, buffer.add_string(str), str.length(), + min_vertical, min_horizontal, max_vertical, max_horizontal); + } else { + g = new text_glob(); + g->text_glob_tag(s, buffer.add_string(str), str.length(), + min_vertical, min_horizontal, max_vertical, max_horizontal); + } glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); } } @@ -826,29 +1185,115 @@ void page::add_line (style *s, int thickness) { if (y1 == y2) { - text_glob *g = new text_glob(s, "", 0, - min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2), - FALSE, TRUE, FALSE, FALSE, thickness); + text_glob *g = new text_glob(); + g->text_glob_line(s, + min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2), + thickness); glyphs.add(g, line_number, min(y1, y2), min(x1, y2), max(y1, y2), max(x1, x2)); } } /* + * to_unicode - returns a unicode translation of int, ch. + */ + +static char *to_unicode (unsigned int ch) +{ + static char buf[30]; + + sprintf(buf, "&#%u;", ch); + return buf; +} + +/* + * add_and_encode - adds a special string to the page, it translates the string + * into html glyphs. The special string will have come from x X html: + * and can contain troff character encodings which appear as + * \(char\). A sequence of \\ represents \. + * So for example we can write: + * "cost = \(Po\)3.00 file = \\foo\\bar" + * which is translated into: + * "cost = £3.00 file = \foo\bar" + */ + +void page::add_and_encode (style *s, const string &str, + int line_number, + int min_vertical, int min_horizontal, + int max_vertical, int max_horizontal) +{ + string html_string; + char *html_glyph; + int i=0; + + if (s->f == NULL) + return; + while (i < str.length()) { + if ((i+1<str.length()) && (str.substring(i, 2) == string("\\("))) { + // start of escape + i += 2; // move over \( + int a = i; + while ((i+1<str.length()) && (str.substring(i, 2) != string("\\)"))) { + i++; + } + int n = i; + if ((i+1<str.length()) && (str.substring(i, 2) == string("\\)"))) + i++; + else + n = -1; + if (n > 0) { + string troff_charname = str.substring(a, n-a); + html_glyph = get_html_translation(s->f, troff_charname); + if (html_glyph) + html_string += html_glyph; + else { + int index=s->f->name_to_index((troff_charname + '\0').contents()); + + if (s->f->contains(index) && (index != 0)) + html_string += s->f->get_code(index); + } + } + } else + html_string += str[i]; + i++; + } + if (html_string.length() > 0) { + text_glob *g=new text_glob(); + g->text_glob_special(s, buffer.add_string(html_string), html_string.length(), + min_vertical, min_horizontal, max_vertical, max_horizontal); + glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); + } +} + +/* * dump_page - dump the page contents for debugging purposes. */ void page::dump_page(void) { +#if defined(DEBUG_TABLES) + text_glob *old_pos = glyphs.get_data(); text_glob *g; + printf("\n<!--\n"); printf("\n\ndebugging start\n"); glyphs.start_from_head(); do { g = glyphs.get_data(); + if (g->is_tab_ts()) { + printf("\n\n"); + if (g->get_table() != NULL) + g->get_table()->dump_table(); + } printf("%s ", g->text_string); + if (g->is_tab_te()) + printf("\n\n"); glyphs.move_right(); } while (! glyphs.is_equal_to_head()); + glyphs.move_to(old_pos); printf("\ndebugging end\n\n"); + printf("\n-->\n"); + fflush(stdout); +#endif } /* @@ -895,12 +1340,13 @@ public: int has_been_written; int has_been_found; - char text[MAX_STRING_LENGTH]; + int with_h1; + string text; }; title_desc::title_desc () - : has_been_written(FALSE), has_been_found(FALSE) + : has_been_written(FALSE), has_been_found(FALSE), with_h1(FALSE) { } @@ -918,7 +1364,7 @@ public: list headers; // list of headers built from .NH and .SH int header_level; // current header level int written_header; // have we written the header yet? - char header_buffer[MAX_STRING_LENGTH]; // current header text + string header_buffer; // current header text void write_headings (FILE *f, int force); }; @@ -948,9 +1394,13 @@ void header_desc::write_headings (FILE *f, int force) do { g = headers.get_data(); fputs("<a href=\"#", f); - if (simple_anchors) - fprintf(f, ANCHOR_TEMPLATE, h); - else + if (simple_anchors) { + string buffer(ANCHOR_TEMPLATE); + + buffer += as_string(h); + buffer += '\0'; + fprintf(f, buffer.contents()); + } else fputs(g->text_string, f); h++; fputs("\">", f); @@ -968,16 +1418,18 @@ class html_printer : public printer { simple_output html; int res; int space_char_index; + int space_width; int no_of_printed_pages; int paper_length; - enum { SBUF_SIZE = 8192 }; - char sbuf[SBUF_SIZE]; - int sbuf_len; + string sbuf; int sbuf_start_hpos; int sbuf_vpos; int sbuf_end_hpos; + int sbuf_prev_hpos; int sbuf_kern; style sbuf_style; + int last_sbuf_length; + int overstrike_detected; style output_style; int output_hpos; int output_vpos; @@ -986,21 +1438,22 @@ class html_printer : public printer { int line_thickness; int output_line_thickness; unsigned char output_space_code; - string defs; char *inside_font_style; int page_number; title_desc title; - title_desc indent; // use title class to remember $1 of .ip header_desc header; int header_indent; int supress_sub_sup; int cutoff_heading; page *page_contents; html_text *current_paragraph; + html_indent *indent; + html_table *table; int end_center; int end_tempindent; TAG_ALIGNMENT next_tag; int fill_on; + int max_linelength; int linelength; int pageoffset; int indentation; @@ -1008,6 +1461,7 @@ class html_printer : public printer { int pointsize; int vertical_spacing; int line_number; + color *background; void flush_sbuf (); void set_style (const style &); @@ -1020,19 +1474,15 @@ class html_printer : public printer { void set_line_thickness (const environment *); void terminate_current_font (void); void flush_font (void); - void add_char_to_sbuf (unsigned char code); - void add_to_sbuf (unsigned char code, const char *name); + void add_to_sbuf (int index, const string &s); void write_title (int in_head); - void determine_diacritical_mark (const char *name, const environment *env); - int sbuf_continuation (unsigned char code, const char *name, const environment *env, int w); - char *remove_last_char_from_sbuf (); - int seen_backwards_escape (char *s, int l); + int sbuf_continuation (int index, const char *name, const environment *env, int w); void flush_page (void); void troff_tag (text_glob *g); void flush_globs (void); void emit_line (text_glob *g); void emit_raw (text_glob *g); - void translate_to_html (text_glob *g); + void emit_html (text_glob *g); void determine_space (text_glob *g); void start_font (const char *name); void end_font (const char *name); @@ -1043,6 +1493,7 @@ class html_printer : public printer { void do_center (char *arg); void do_break (void); void do_eol (void); + void do_eol_ce (void); void do_title (void); void do_fill (int on); void do_heading (char *arg); @@ -1067,19 +1518,42 @@ class html_printer : public printer { int end_subscript (text_glob *g); int start_superscript (text_glob *g); int end_superscript (text_glob *g); - + void outstanding_eol (int n); + int is_bold (font *f); + font *make_bold (font *f); + int overstrike (int index, const char *name, const environment *env, int w); + void do_body (void); + int next_horiz_pos (text_glob *g, int nf); + void lookahead_for_tables (void); + void insert_tab_te (void); + text_glob *insert_tab_ts (text_glob *where); + void insert_tab0_foreach_tab (void); + void insert_tab_0 (text_glob *where); + void do_indent (int in, int pageoff, int linelen); + void shutdown_table (void); + void do_tab_ts (text_glob *g); + void do_tab_te (void); + void do_col (char *s); + void do_tab (char *s); + void do_tab0 (void); + int calc_nf (text_glob *g, int nf); + void calc_po_in (text_glob *g, int nf); + void remove_tabs (void); + void remove_courier_tabs (void); + void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g); + void add_table_end (char *debug_string); // ADD HERE public: - html_printer (); - ~html_printer (); - void set_char (int i, font *f, const environment *env, int w, const char *name); - void draw (int code, int *p, int np, const environment *env); - void begin_page (int); - void end_page (int); - void special (char *arg, const environment *env, char type); - font *make_font (const char *); - void end_of_line (); + html_printer (); + ~html_printer (); + void set_char (int i, font *f, const environment *env, int w, const char *name); + void draw (int code, int *p, int np, const environment *env); + void begin_page (int); + void end_page (int); + void special (char *arg, const environment *env, char type); + font *make_font (const char *); + void end_of_line (); }; printer *make_printer() @@ -1092,7 +1566,7 @@ static void usage(FILE *stream); void html_printer::set_style(const style &sty) { const char *fontname = sty.f->get_name(); - if (fontname == 0) + if (fontname == NULL) fatal("no internalname specified for font"); #if 0 @@ -1100,6 +1574,33 @@ void html_printer::set_style(const style &sty) #endif } +/* + * is_bold - returns TRUE if font, f, is bold. + */ + +int html_printer::is_bold (font *f) +{ + const char *fontname = f->get_name(); + return (strcmp(fontname, "B") == 0) || (strcmp(fontname, "BI") == 0); +} + +/* + * make_bold - if a bold font of, f, exists then return it. + */ + +font *html_printer::make_bold (font *f) +{ + const char *fontname = f->get_name(); + + if (strcmp(fontname, "B") == 0) + return f; + if (strcmp(fontname, "I") == 0) + return font::load_font("BI"); + if (strcmp(fontname, "BI") == 0) + return f; + return NULL; +} + void html_printer::end_of_line() { flush_sbuf(); @@ -1127,8 +1628,6 @@ void html_printer::emit_raw (text_glob *g) determine_space(g); current_paragraph->do_emittext(g->text_string, g->text_length); } else { - int in_table=current_paragraph->is_in_table(); - current_paragraph->done_para(); switch (next_tag) { @@ -1136,10 +1635,10 @@ void html_printer::emit_raw (text_glob *g) current_paragraph->do_para("align=center"); break; case LEFT: - current_paragraph->do_para("align=left"); + current_paragraph->do_para(&html, "align=left", indentation, pageoffset, linelength); break; case RIGHT: - current_paragraph->do_para("align=right"); + current_paragraph->do_para(&html, "align=right", indentation, pageoffset, linelength); break; default: fatal("unknown enumeration"); @@ -1148,13 +1647,14 @@ void html_printer::emit_raw (text_glob *g) current_paragraph->done_para(); next_tag = INLINE; supress_sub_sup = TRUE; -#if defined(INDENTATION) - if (in_table) { - stop(); - current_paragraph->do_indent(NULL, 0, pageoffset, linelength); - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); + if (indentation > 0) { + /* + * restore indentation + */ + int newin = indentation; + indentation = 0; + do_indent(newin, pageoffset, linelength); } -#endif } } @@ -1165,16 +1665,16 @@ void html_printer::emit_raw (text_glob *g) void html_printer::do_center (char *arg) { int n = atoi(arg); - current_paragraph->do_break(); - current_paragraph->done_para(); - supress_sub_sup = TRUE; - + if (n > 0) { + current_paragraph->done_para(); + supress_sub_sup = TRUE; current_paragraph->do_para("align=center"); end_center += n; } else { end_center = 0; + current_paragraph->remove_para_align(); } } @@ -1229,23 +1729,16 @@ static int exists (const char *filename) * providing that the image exists. */ -static char *generate_img_src (const char *filename) +static string &generate_img_src (const char *filename) { - static char buffer[MAX_STRING_LENGTH]; + string *s = new string(""); while (filename && (filename[0] == ' ')) { filename++; } - if (exists(filename)) { - strcpy(buffer, "<img src=\""); - strncat(buffer, filename, MAX_STRING_LENGTH-strlen("<img src=\"")-1); - if (strlen(buffer) < MAX_STRING_LENGTH-3) { - strncat(buffer, "\">", 3); - } - return( (char *)&buffer ); - } else { - return( 0 ); - } + if (exists(filename)) + *s += string("<img src=\"") + filename + "\">"; + return *s; } /* @@ -1258,19 +1751,30 @@ static char *generate_img_src (const char *filename) void html_printer::do_auto_image (text_glob *g, const char *filename) { - char *buffer = generate_img_src(filename); + string buffer = generate_img_src(filename); - if (buffer) { + if (! buffer.empty()) { /* * utilize emit_raw by creating a new text_glob. */ text_glob h = *g; - h.text_string = buffer; - h.text_length = strlen(buffer); + h.text_string = buffer.contents(); + h.text_length = buffer.length(); emit_raw(&h); - } else { + } else next_tag = INLINE; +} + +/* + * outstanding_eol - call do_eol, n, times. + */ + +void html_printer::outstanding_eol (int n) +{ + while (n > 0) { + do_eol(); + n--; } } @@ -1282,7 +1786,7 @@ void html_printer::do_title (void) { text_glob *t; int removed_from_head; - char buf[MAX_STRING_LENGTH]; + int eol_ce = 0; if (page_number == 1) { int found_title_start = FALSE; @@ -1292,44 +1796,43 @@ void html_printer::do_title (void) t = page_contents->glyphs.get_data(); removed_from_head = FALSE; if (t->is_auto_img()) { - char *img=generate_img_src((char *)(t->text_string + 20)); + string img = generate_img_src((char *)(t->text_string + 20)); - if (img) { - if (found_title_start) { - strcat(title.text, " "); - } + if (! img.empty()) { + if (found_title_start) + title.text += " "; found_title_start = TRUE; title.has_been_found = TRUE; - strcat(title.text, img); + title.text += img; } page_contents->glyphs.sub_move_right(); /* move onto next word */ removed_from_head = ((!page_contents->glyphs.is_empty()) && (page_contents->glyphs.is_equal_to_head())); - } else if (t->is_raw_command) { - /* skip raw commands + } else if (t->is_eol_ce()) { + /* process the eol associated with .ce */ + eol_ce++; page_contents->glyphs.sub_move_right(); /* move onto next word */ } else if (t->is_eol()) { /* end of title found */ title.has_been_found = TRUE; + outstanding_eol(eol_ce); return; } else if (t->is_a_tag()) { /* end of title found, but move back so that we read this tag and process it */ page_contents->glyphs.move_left(); /* move backwards to last word */ title.has_been_found = TRUE; + outstanding_eol(eol_ce); return; } else if (found_title_start) { - strcat(title.text, " "); - str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE); - strcat(title.text, buf); - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); + title.text += " " + string(t->text_string, t->text_length); + page_contents->glyphs.sub_move_right(); /* move onto next word */ + removed_from_head = ((!page_contents->glyphs.is_empty()) && + (page_contents->glyphs.is_equal_to_head())); } else { - str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE); - strcpy((char *)title.text, buf); + title.text += string(t->text_string, t->text_length); found_title_start = TRUE; title.has_been_found = TRUE; page_contents->glyphs.sub_move_right(); /* move onto next word */ @@ -1338,20 +1841,19 @@ void html_printer::do_title (void) } } while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head)); } - // page_contents->glyphs.move_left(); /* move backwards to last word */ + outstanding_eol(eol_ce); } } void html_printer::write_header (void) { - if (strlen(header.header_buffer) > 0) { + if (! header.header_buffer.empty()) { if (header.header_level > 7) { header.header_level = 7; } // firstly we must terminate any font and type faces current_paragraph->done_para(); - current_paragraph->done_table(); supress_sub_sup = TRUE; if (cutoff_heading+2 > header.header_level) { @@ -1359,12 +1861,13 @@ void html_printer::write_header (void) header.no_of_headings++; style st; - text_glob *h=new text_glob(&st, - header.headings.add_string(header.header_buffer, strlen(header.header_buffer)), - strlen(header.header_buffer), - header.no_of_headings, header.header_level, - header.no_of_headings, header.header_level, - FALSE, FALSE, FALSE, FALSE, FALSE); + text_glob *h=new text_glob(); + h->text_glob_html(&st, + header.headings.add_string(header.header_buffer), + header.header_buffer.length(), + header.no_of_headings, header.header_level, + header.no_of_headings, header.header_level); + header.headers.add(h, header.no_of_headings, header.no_of_headings, header.no_of_headings, @@ -1374,26 +1877,45 @@ void html_printer::write_header (void) html.nl().put_string("<a name=\""); if (simple_anchors) { - char buffer[MAX_LINE_LENGTH]; + string buffer(ANCHOR_TEMPLATE); - sprintf(buffer, ANCHOR_TEMPLATE, header.no_of_headings); - html.put_string(buffer); + buffer += as_string(header.no_of_headings); + buffer += '\0'; + html.put_string(buffer.contents()); } else { html.put_string(header.header_buffer); } html.put_string("\"></a>").nl(); } - // and now we issue the real header - html.put_string("<h"); - html.put_number(header.header_level); - html.put_string(">"); - html.put_string(header.header_buffer); - html.put_string("</h"); - html.put_number(header.header_level); - html.put_string(">").nl(); + if (manufacture_headings) { + // line break before a header + if (!current_paragraph->emitted_text()) + current_paragraph->do_space(); + // user wants manufactured headings which look better than <Hn></Hn> + if (header.header_level<4) { + html.put_string("<b><font size=\"+1\">"); + html.put_string(header.header_buffer); + html.put_string("</font></b>").nl(); + } + else { + html.put_string("<b>"); + html.put_string(header.header_buffer); + html.put_string("</b>").nl(); + } + } + else { + // and now we issue the real header + html.put_string("<h"); + html.put_number(header.header_level); + html.put_string(">"); + html.put_string(header.header_buffer); + html.put_string("</h"); + html.put_number(header.header_level); + html.put_string(">").nl(); + } - current_paragraph->do_para(""); + current_paragraph->do_para(&html, "", indentation, pageoffset, linelength); } } @@ -1401,9 +1923,10 @@ void html_printer::determine_header_level (int level) { if (level == 0) { int i; - int l=strlen(header.header_buffer); - for (i=0; ((i<l) && ((header.header_buffer[i] == '.') || is_digit(header.header_buffer[i]))) ; i++) { + for (i=0; ((i<header.header_buffer.length()) + && ((header.header_buffer[i] == '.') + || is_digit(header.header_buffer[i]))) ; i++) { if (header.header_buffer[i] == '.') { level++; } @@ -1420,35 +1943,33 @@ void html_printer::do_heading (char *arg) { text_glob *g; text_glob *l = 0; - char buf[MAX_STRING_LENGTH]; int level=atoi(arg); - strcpy(header.header_buffer, ""); + header.header_buffer.clear(); page_contents->glyphs.move_right(); if (! page_contents->glyphs.is_equal_to_head()) { g = page_contents->glyphs.get_data(); do { if (g->is_auto_img()) { - char *img=generate_img_src((char *)(g->text_string + 20)); + string img=generate_img_src((char *)(g->text_string + 20)); - if (img) { + if (! img.empty()) { simple_anchors = TRUE; // we cannot use full heading anchors with images - if (l != 0) { - strcat(header.header_buffer, " "); - } + if (l != 0) + header.header_buffer += " "; + l = g; - strcat(header.header_buffer, img); + header.header_buffer += img; } - } else if (! (g->is_a_line() || g->is_a_tag() || g->is_raw())) { + } else if (! (g->is_a_line() || g->is_a_tag())) { /* - * we ignore raw commands when constructing a heading + * we ignore tags commands when constructing a heading */ - if (l != 0) { - strcat(header.header_buffer, " "); - } + if (l != 0) + header.header_buffer += " "; l = g; - str_translate_to_html(g->text_style.f, buf, MAX_STRING_LENGTH, g->text_string, g->text_length, TRUE); - strcat(header.header_buffer, (char *)buf); + + header.header_buffer += string(g->text_string, g->text_length); } page_contents->glyphs.move_right(); g = page_contents->glyphs.get_data(); @@ -1478,22 +1999,20 @@ int html_printer::is_courier_until_eol (void) page_contents->glyphs.move_right(); do { g = page_contents->glyphs.get_data(); - if (! is_font_courier(g->text_style.f)) { + if (! g->is_a_tag() && (! is_font_courier(g->text_style.f))) result = FALSE; - } page_contents->glyphs.move_right(); - } while ((result) && + } while (result && (! page_contents->glyphs.is_equal_to_head()) && - (! g->is_eol())); + (! g->is_fi()) && (! g->is_eol())); /* * now restore our previous position. */ - while (page_contents->glyphs.get_data() != orig) { + while (page_contents->glyphs.get_data() != orig) page_contents->glyphs.move_left(); - } } - return( result ); + return result; } /* @@ -1502,12 +2021,11 @@ int html_printer::is_courier_until_eol (void) void html_printer::do_linelength (char *arg) { -#if defined(INDENTATION) - if (fill_on) { - linelength = atoi(arg); - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); - } -#endif + if (max_linelength == -1) + max_linelength = atoi(arg); + + if (fill_on) + do_indent(indentation, pageoffset, atoi(arg)); } /* @@ -1516,12 +2034,8 @@ void html_printer::do_linelength (char *arg) void html_printer::do_pageoffset (char *arg) { -#if defined(INDENTATION) - pageoffset = atoi(arg); - if (fill_on) { - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); - } -#endif + if (fill_on) + do_indent(indentation, atoi(arg), linelength); } /* @@ -1530,12 +2044,8 @@ void html_printer::do_pageoffset (char *arg) void html_printer::do_indentation (char *arg) { -#if defined(INDENTATION) - if (fill_on) { - indentation = atoi(arg); - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); - } -#endif + if (fill_on) + do_indent(atoi(arg), pageoffset, linelength); } /* @@ -1544,81 +2054,47 @@ void html_printer::do_indentation (char *arg) void html_printer::do_tempindent (char *arg) { -#if defined(INDENTATION) if (fill_on) { end_tempindent = 1; prev_indent = indentation; - indentation = atoi(arg); - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); + do_indent(atoi(arg), pageoffset, linelength); } -#endif } /* - * do_indentedparagraph - handle the .ip tag, this buffers the next line - * and passes this to text-text as the left hand - * column table entry. + * shutdown_table - shuts down the current table. */ -void html_printer::do_indentedparagraph (void) +void html_printer::shutdown_table (void) { -#if defined(INDENTATION) - text_glob *t; - int removed_from_head; - char buf[MAX_STRING_LENGTH]; - int found_indent_start = FALSE; + if (table != NULL) { + current_paragraph->done_para(); + table->emit_finish_table(); + // dont delete this table as it will be deleted when we destroy the text_glob + table = NULL; + } +} - indent.has_been_found = FALSE; - indent.text[0] = (char)0; +/* + * do_indent - remember the indent parameters and if + * indent is > pageoff and indent has changed + * then we start a html table to implement the indentation. + */ - if (! page_contents->glyphs.is_empty()) { - page_contents->glyphs.sub_move_right(); /* move onto next word */ - do { - t = page_contents->glyphs.get_data(); - removed_from_head = FALSE; - if (t->is_auto_img()) { - char *img=generate_img_src((char *)(t->text_string + 20)); - - if (img) { - if (found_indent_start) { - strcat(indent.text, " "); - } - found_indent_start = TRUE; - strcat(indent.text, img); - } - page_contents->glyphs.sub_move_right(); /* move onto next word */ - } else if (t->is_raw_command) { - /* skip raw commands - */ - page_contents->glyphs.sub_move_right(); /* move onto next word */ - } else if (t->is_a_tag() && (strncmp(t->text_string, "html-tag:.br", 12) == 0)) { - /* end of indented para found, but move back so that we read this tag and process it - */ - page_contents->glyphs.move_left(); /* move backwards to last word */ - indent.has_been_found = TRUE; - return; - } else if (t->is_a_tag()) { - page_contents->glyphs.sub_move_right(); /* move onto next word */ - } else if (found_indent_start) { - strcat(indent.text, " "); - str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE); - strcat(indent.text, buf); - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } else { - str_translate_to_html(t->text_style.f, buf, MAX_STRING_LENGTH, t->text_string, t->text_length, TRUE); - strcpy((char *)indent.text, buf); - found_indent_start = TRUE; - indent.has_been_found = TRUE; - page_contents->glyphs.sub_move_right(); /* move onto next word */ - removed_from_head = ((!page_contents->glyphs.is_empty()) && - (page_contents->glyphs.is_equal_to_head())); - } - } while ((! page_contents->glyphs.is_equal_to_head()) || (removed_from_head)); +void html_printer::do_indent (int in, int pageoff, int linelen) +{ + if ((indentation != -1) && + (pageoffset+indentation != in+pageoff)) { + + current_paragraph->done_para(); + + indentation = in; + pageoffset = pageoff; + if (linelen <= max_linelength) + linelength = linelen; + + current_paragraph->do_para(&html, "", indentation, pageoffset, max_linelength); } - // page_contents->glyphs.move_left(); /* move backwards to last word */ -#endif } /* @@ -1650,13 +2126,12 @@ void html_printer::do_fill (int on) supress_sub_sup = TRUE; if (fill_on != on) { - if (on) { - current_paragraph->done_pre(); - } else { + if (on) + current_paragraph->do_para(""); + else current_paragraph->do_pre(); - } + fill_on = on; } - fill_on = on; } /* @@ -1666,14 +2141,25 @@ void html_printer::do_fill (int on) void html_printer::do_eol (void) { if (! fill_on) { - current_paragraph->do_newline(); - current_paragraph->do_break(); + if (current_paragraph->ever_emitted_text()) { + current_paragraph->do_newline(); + current_paragraph->do_break(); + } } output_hpos = indentation+pageoffset; +} + +/* + * do_eol_ce - handle end of line specifically for a .ce + */ + +void html_printer::do_eol_ce (void) +{ if (end_center > 0) { - if (end_center > 1) { - current_paragraph->do_break(); - } + if (end_center > 1) + if (current_paragraph->emitted_text()) + current_paragraph->do_break(); + end_center--; if (end_center == 0) { current_paragraph->done_para(); @@ -1689,7 +2175,6 @@ void html_printer::do_eol (void) void html_printer::do_flush (void) { current_paragraph->done_para(); - current_paragraph->done_table(); } /* @@ -1699,12 +2184,9 @@ void html_printer::do_flush (void) void html_printer::do_links (void) { current_paragraph->done_para(); - current_paragraph->done_table(); auto_links = FALSE; /* from now on only emit under user request */ -#if !defined(DEBUGGING) file_list.add_new_file(xtmpfile()); html.set_file(file_list.get_file()); -#endif } /* @@ -1715,20 +2197,106 @@ void html_printer::do_links (void) void html_printer::do_break (void) { current_paragraph->do_break(); -#if defined(INDENTATION) if (end_tempindent > 0) { end_tempindent--; - if (end_tempindent == 0) { - indentation = prev_indent; - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); - } + if (end_tempindent == 0) + do_indent(prev_indent, pageoffset, linelength); } -#endif output_hpos = indentation+pageoffset; supress_sub_sup = TRUE; } /* + * do_tab_ts - start a table, which will have already been defined. + */ + +void html_printer::do_tab_ts (text_glob *g) +{ + html_table *t = g->get_table(); + + if (t != NULL) { + current_paragraph->done_pre(); + current_paragraph->done_para(); + + html.simple_comment("TABS"); + + t->set_linelength(max_linelength); + t->add_indent(pageoffset); + t->emit_table_header(FALSE); + } + + table = t; +} + +/* + * do_tab_te - finish a table. + */ + +void html_printer::do_tab_te (void) +{ + if (table) { + current_paragraph->done_para(); + table->emit_finish_table(); + } + + table = NULL; + + if (indentation > 0) { + /* + * restore indentation + */ + int newin = indentation; + indentation = 0; + do_indent(newin, pageoffset, linelength); + } +} + +/* + * do_tab - handle the "html-tag:tab" tag + */ + +void html_printer::do_tab (char *s) +{ + if (table) { + while (isspace(*s)) + s++; + s++; + int col = table->find_column(atoi(s) + pageoffset + indentation); + if (col > 0) { + current_paragraph->done_para(); + table->emit_col(col); + } + } +} + +/* + * do_tab0 - handle the "html-tag:tab0" tag + */ + +void html_printer::do_tab0 (void) +{ + if (table) { + int col = table->find_column(pageoffset+indentation); + if (col > 0) { + current_paragraph->done_para(); + table->emit_col(col); + } + } +} + +/* + * do_col - start column, s. + */ + +void html_printer::do_col (char *s) +{ + if (table) { + current_paragraph->done_para(); + table->emit_col(atoi(s)); + } +} + +/* * troff_tag - processes the troff tag and manipulates the troff state machine. */ @@ -1741,8 +2309,13 @@ void html_printer::troff_tag (text_glob *g) if (g->is_eol()) { do_eol(); + } else if (g->is_eol_ce()) { + do_eol_ce(); } else if (strncmp(t, ".sp", 3) == 0) { - current_paragraph->do_space(); + if (g->get_arg() > 0) + current_paragraph->do_space(); + else + current_paragraph->do_break(); supress_sub_sup = TRUE; } else if (strncmp(t, ".br", 3) == 0) { do_break(); @@ -1761,6 +2334,11 @@ void html_printer::troff_tag (text_glob *g) do_center(a); } else if (strncmp(t, ".tl", 3) == 0) { supress_sub_sup = TRUE; + title.with_h1 = TRUE; + do_title(); + } else if (strncmp(t, ".html-tl", 8) == 0) { + supress_sub_sup = TRUE; + title.with_h1 = FALSE; do_title(); } else if (strncmp(t, ".fi", 3) == 0) { do_fill(TRUE); @@ -1784,10 +2362,25 @@ void html_printer::troff_tag (text_glob *g) } else if (strncmp(t, ".vs", 3) == 0) { char *a = (char *)t+3; do_verticalspacing(a); - } else if (strncmp(t, ".ip", 3) == 0) { - do_indentedparagraph(); + } else if (strncmp(t, ".ps", 3) == 0) { + char *a = (char *)t+3; + do_pointsize(a); } else if (strcmp(t, ".links") == 0) { do_links(); + } else if (strcmp(t, ".no-auto-rule") == 0) { + auto_rule = FALSE; + } else if (strcmp(t, ".tab-ts") == 0) { + do_tab_ts(g); + } else if (strcmp(t, ".tab-te") == 0) { + do_tab_te(); + } else if (strncmp(t, ".col ", 5) == 0) { + char *a = (char *)t+4; + do_col(a); + } else if (strncmp(t, "tab ", 4) == 0) { + char *a = (char *)t+3; + do_tab(a); + } else if (strncmp(t, "tab0", 4) == 0) { + do_tab0(); } } @@ -1813,18 +2406,15 @@ void html_printer::flush_globs (void) do { g = page_contents->glyphs.get_data(); - if (strcmp(g->text_string, "XXXXXXX") == 0) { + if (strcmp(g->text_string, "XXXXXXX") == 0) stop(); - } - if (g->is_raw()) { - emit_raw(g); - } else if (g->is_a_tag()) { + if (g->is_a_tag()) { troff_tag(g); } else if (g->is_a_line()) { emit_line(g); } else { - translate_to_html(g); + emit_html(g); } /* * after processing the title (and removing it) the glyph list might be empty @@ -1836,29 +2426,474 @@ void html_printer::flush_globs (void) } } +/* + * calc_nf - calculates the _no_ format flag, given the + * text glob, g. + */ + +int html_printer::calc_nf (text_glob *g, int nf) +{ + if (g != NULL) { + if (g->is_fi()) + return FALSE; + if (g->is_nf()) + return TRUE; + } + return nf; +} + +/* + * calc_po_in - calculates the, in, po, registers + */ + +void html_printer::calc_po_in (text_glob *g, int nf) +{ + if (g->is_in()) + indentation = g->get_arg(); + else if (g->is_po()) + pageoffset = g->get_arg(); + else if (g->is_ti()) { + prev_indent = indentation; + indentation = g->get_arg(); + end_tempindent = 1; + } else if (g->is_br() && ((end_tempindent > 0) || (nf && g->is_eol()))) { + end_tempindent = 0; + indentation = prev_indent; + } +} + +/* + * next_horiz_pos - returns the next horiz position. + * -1 is returned if it doesn't exist. + */ + +int html_printer::next_horiz_pos (text_glob *g, int nf) +{ + int next = -1; + + if ((g != NULL) && (g->is_br() || (nf && g->is_eol()))) + if (! page_contents->glyphs.is_empty()) { + page_contents->glyphs.move_right_get_data(); + if (g == NULL) + page_contents->glyphs.start_from_head(); + else { + next = g->minh; + page_contents->glyphs.move_left(); + } + } + return next; +} + +/* + * insert_tab_ts - inserts a tab-ts before, where. + */ + +text_glob *html_printer::insert_tab_ts (text_glob *where) +{ + text_glob *start_of_table; + text_glob *old_pos = page_contents->glyphs.get_data(); + + page_contents->glyphs.move_to(where); + page_contents->glyphs.move_left(); + page_contents->insert_tag(string("html-tag:.tab-ts")); // tab table start + page_contents->glyphs.move_right(); + start_of_table = page_contents->glyphs.get_data(); + page_contents->glyphs.move_to(old_pos); + return start_of_table; +} + +/* + * insert_tab_te - inserts a tab-te before the current position + * (it skips backwards over .sp/.br) + */ + +void html_printer::insert_tab_te (void) +{ + text_glob *g = page_contents->glyphs.get_data(); + page_contents->dump_page(); + + while (page_contents->glyphs.get_data()->is_a_tag()) + page_contents->glyphs.move_left(); + + page_contents->insert_tag(string("html-tag:.tab-te")); // tab table end + while (g != page_contents->glyphs.get_data()) + page_contents->glyphs.move_right(); + page_contents->dump_page(); +} + +/* + * insert_tab_0 - inserts a tab0 before, where. + */ + +void html_printer::insert_tab_0 (text_glob *where) +{ + text_glob *old_pos = page_contents->glyphs.get_data(); + + page_contents->glyphs.move_to(where); + page_contents->glyphs.move_left(); + page_contents->insert_tag(string("html-tag:tab0")); // tab0 start of line + page_contents->glyphs.move_right(); + page_contents->glyphs.move_to(old_pos); +} + +/* + * remove_tabs - removes the tabs tags on this line. + */ + +void html_printer::remove_tabs (void) +{ + text_glob *orig = page_contents->glyphs.get_data(); + text_glob *g; + + if (! page_contents->glyphs.is_equal_to_tail()) { + do { + g = page_contents->glyphs.get_data(); + if (g->is_tab()) { + page_contents->glyphs.sub_move_right(); + if (g == orig) + orig = page_contents->glyphs.get_data(); + } else + page_contents->glyphs.move_right(); + } while ((! page_contents->glyphs.is_equal_to_head()) && + (! g->is_eol())); + + /* + * now restore our previous position. + */ + while (page_contents->glyphs.get_data() != orig) + page_contents->glyphs.move_left(); + } +} + +void html_printer::remove_courier_tabs (void) +{ + text_glob *g; + int line_start = TRUE; + int nf = FALSE; + + if (! page_contents->glyphs.is_empty()) { + page_contents->glyphs.start_from_head(); + line_start = TRUE; + do { + g = page_contents->glyphs.get_data(); + + nf = calc_nf(g, nf); + + if (line_start) { + if (line_start && nf && is_courier_until_eol()) { + remove_tabs(); + g = page_contents->glyphs.get_data(); + } + } + + line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && g->is_eol()); + page_contents->glyphs.move_right(); + } while (! page_contents->glyphs.is_equal_to_head()); + } +} + +void html_printer::insert_tab0_foreach_tab (void) +{ + text_glob *start_of_line = NULL; + text_glob *g = NULL; + int seen_tab = FALSE; + int seen_col = FALSE; + int nf = FALSE; + + if (! page_contents->glyphs.is_empty()) { + page_contents->glyphs.start_from_head(); + start_of_line = page_contents->glyphs.get_data(); + do { + g = page_contents->glyphs.get_data(); + + nf = calc_nf(g, nf); + + if (g->is_tab()) + seen_tab = TRUE; + + if (g->is_col()) + seen_col = TRUE; + + if (g->is_br() || (nf && g->is_eol())) { + do { + page_contents->glyphs.move_right(); + g = page_contents->glyphs.get_data(); + nf = calc_nf(g, nf); + if (page_contents->glyphs.is_equal_to_head()) { + if (seen_tab && !seen_col) + insert_tab_0(start_of_line); + return; + } + } while (g->is_br() || (nf && g->is_eol()) || g->is_ta()); + // printf("\nstart_of_line is: %s\n", g->text_string); + if (seen_tab && !seen_col) { + insert_tab_0(start_of_line); + page_contents->glyphs.move_to(g); + } + + seen_tab = FALSE; + seen_col = FALSE; + start_of_line = g; + } + page_contents->glyphs.move_right(); + } while (! page_contents->glyphs.is_equal_to_head()); + if (seen_tab && !seen_col) + insert_tab_0(start_of_line); + + } +} + +/* + * update_min_max - updates the extent of a column, given the left and right + * extents of a glyph, g. + */ + +void html_printer::update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g) +{ + switch (type_of_col) { + + case tab_tag: + break; + case tab0_tag: + *minimum = g->minh; + break; + case col_tag: + *minimum = g->minh; + *maximum = g->maxh; + break; + default: + break; + } +} + +/* + * add_table_end - moves left one glyph, adds a table end tag and adds a + * debugging string. + */ + +void html_printer::add_table_end (char *debug_string) +{ + page_contents->glyphs.move_left(); + insert_tab_te(); +#if defined(DEBUG_TABLES) + page_contents->insert_tag(string(debug_string)); +#endif +} + +/* + * lookahead_for_tables - checks for .col tags and inserts table start/end tags + */ + +void html_printer::lookahead_for_tables (void) +{ + text_glob *g; + text_glob *start_of_line = NULL; + text_glob *start_of_table = NULL; + text_glob *last = NULL; + colType type_of_col = none; + int left = 0; + int found_col = FALSE; + int seen_text = FALSE; + int ncol = 0; + int colmin; + int colmax; + html_table *table = new html_table(&html, -1); + const char *tab_defs = NULL; + char align = 'L'; + int nf = FALSE; + int old_pageoffset = pageoffset; + + remove_courier_tabs(); + page_contents->dump_page(); + insert_tab0_foreach_tab(); + page_contents->dump_page(); + if (! page_contents->glyphs.is_empty()) { + page_contents->glyphs.start_from_head(); + g = page_contents->glyphs.get_data(); + do { +#if defined(DEBUG_TABLES) + fprintf(stderr, " [") ; + fprintf(stderr, g->text_string) ; + fprintf(stderr, "] ") ; + fflush(stderr); + if (strcmp(g->text_string, "XXXXXXX") == 0) + stop(); +#endif + + nf = calc_nf(g, nf); + calc_po_in(g, nf); + if (g->is_col()) { + if (type_of_col == tab_tag && start_of_table != NULL) { + page_contents->glyphs.move_left(); + insert_tab_te(); + start_of_table->remember_table(table); + table = new html_table(&html, -1); + page_contents->insert_tag(string("*** TAB -> COL ***")); + if (tab_defs != NULL) + table->tab_stops->init(tab_defs); + start_of_table = NULL; + last = NULL; + } + type_of_col = col_tag; + found_col = TRUE; + ncol = g->get_arg(); + align = 'L'; + colmin = 0; + colmax = 0; + } else if (g->is_tab()) { + type_of_col = tab_tag; + colmin = g->get_tab_args(&align); + align = 'L'; // for now as 'C' and 'R' are broken + ncol = table->find_tab_column(colmin); + colmin += pageoffset + indentation; + colmax = table->get_tab_pos(ncol+1); + if (colmax > 0) + colmax += pageoffset + indentation; + } else if (g->is_tab0()) { + if (type_of_col == col_tag && start_of_table != NULL) { + page_contents->glyphs.move_left(); + insert_tab_te(); + start_of_table->remember_table(table); + table = new html_table(&html, -1); + page_contents->insert_tag(string("*** COL -> TAB ***")); + start_of_table = NULL; + last = NULL; + } + if (tab_defs != NULL) + table->tab_stops->init(tab_defs); + + type_of_col = tab0_tag; + ncol = 1; + colmin = 0; + colmax = table->get_tab_pos(2) + pageoffset + indentation; + } else if (! g->is_a_tag()) + update_min_max(type_of_col, &colmin, &colmax, g); + + if ((! g->is_a_tag()) || g->is_tab()) + seen_text = TRUE; + + if ((g->is_col() || g->is_tab() || g->is_tab0()) + && (start_of_line != NULL) && (start_of_table == NULL)) { + start_of_table = insert_tab_ts(start_of_line); + start_of_line = NULL; + seen_text = FALSE; + } else if (g->is_ce() && (start_of_table != NULL)) { + add_table_end("*** CE ***"); + start_of_table->remember_table(table); + start_of_table = NULL; + last = NULL; + } else if (g->is_ta()) { + tab_defs = g->text_string; + if (!table->tab_stops->compatible(tab_defs)) { + if (start_of_table != NULL) { + add_table_end("*** TABS ***"); + start_of_table->remember_table(table); + table = new html_table(&html, -1); + start_of_table = NULL; + type_of_col = none; + last = NULL; + } + table->tab_stops->init(tab_defs); + } + } + + if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) { + // we are in a table and have a glyph + if ((ncol == 0) || (! table->add_column(ncol, colmin, colmax, align))) { + if (ncol == 0) + add_table_end("*** NCOL == 0 ***"); + else + add_table_end("*** CROSSED COLS ***"); + + start_of_table->remember_table(table); + table = new html_table(&html, -1); + start_of_table = NULL; + type_of_col = none; + last = NULL; + } + } + + /* + * move onto next glob, check whether we are starting a new line + */ + g = page_contents->glyphs.move_right_get_data(); + + if (g == NULL) { + if (found_col) { + page_contents->glyphs.start_from_head(); + last = g; + found_col = FALSE; + } + } else if (g->is_br() || (nf && g->is_eol())) { + do { + g = page_contents->glyphs.move_right_get_data(); + nf = calc_nf(g, nf); + } while ((g != NULL) && (g->is_br() || (nf && g->is_eol()))); + start_of_line = g; + seen_text = FALSE; + ncol = 0; + left = next_horiz_pos(g, nf); + if (found_col) + last = g; + found_col = FALSE; + } + } while ((g != NULL) && (! page_contents->glyphs.is_equal_to_head())); + +#if defined(DEBUG_TABLES) + fprintf(stderr, "finished scanning for tables\n"); +#endif + + page_contents->glyphs.start_from_head(); + if (start_of_table != NULL) { + if (last != NULL) + while (last != page_contents->glyphs.get_data()) + page_contents->glyphs.move_left(); + + insert_tab_te(); + start_of_table->remember_table(table); + table = NULL; + page_contents->insert_tag(string("*** LAST ***")); + } + } + if (table != NULL) + delete table; + + // and reset the registers + pageoffset = old_pageoffset; + indentation = 0; + prev_indent = 0; + end_tempindent = 0; +} + void html_printer::flush_page (void) { supress_sub_sup = TRUE; flush_sbuf(); - // page_contents->dump_page(); + page_contents->dump_page(); + lookahead_for_tables(); + page_contents->dump_page(); + flush_globs(); current_paragraph->done_para(); - current_paragraph->done_table(); // move onto a new page delete page_contents; +#if defined(DEBUG_TABLES) + fprintf(stderr, "\n\n*** flushed page ***\n\n"); + + html.simple_comment("new page called"); +#endif page_contents = new page; } /* * determine_space - works out whether we need to write a space. - * If last glyth is ajoining then no space emitted. + * If last glyph is ajoining then no space emitted. */ void html_printer::determine_space (text_glob *g) { if (current_paragraph->is_in_pre()) { - int space_width = sbuf_style.f->get_space_width(sbuf_style.point_size); /* * .nf has been specified */ @@ -1902,7 +2937,16 @@ void html_printer::end_font (const char *fontname) current_paragraph->done_italic(); } else if (strcmp(fontname, "CR") == 0) { current_paragraph->done_tt(); - current_paragraph->done_pre(); + } else if (strcmp(fontname, "CI") == 0) { + current_paragraph->done_italic(); + current_paragraph->done_tt(); + } else if (strcmp(fontname, "CB") == 0) { + current_paragraph->done_bold(); + current_paragraph->done_tt(); + } else if (strcmp(fontname, "CBI") == 0) { + current_paragraph->done_bold(); + current_paragraph->done_italic(); + current_paragraph->done_tt(); } } @@ -1928,6 +2972,25 @@ void html_printer::start_font (const char *fontname) current_paragraph->do_pre(); } current_paragraph->do_tt(); + } else if (strcmp(fontname, "CI") == 0) { + if ((! fill_on) && (is_courier_until_eol())) { + current_paragraph->do_pre(); + } + current_paragraph->do_tt(); + current_paragraph->do_italic(); + } else if (strcmp(fontname, "CB") == 0) { + if ((! fill_on) && (is_courier_until_eol())) { + current_paragraph->do_pre(); + } + current_paragraph->do_tt(); + current_paragraph->do_bold(); + } else if (strcmp(fontname, "CBI") == 0) { + if ((! fill_on) && (is_courier_until_eol())) { + current_paragraph->do_pre(); + } + current_paragraph->do_tt(); + current_paragraph->do_italic(); + current_paragraph->do_bold(); } } @@ -1986,6 +3049,11 @@ void html_printer::do_font (text_glob *g) output_style.point_size = g->text_style.point_size; } } + if (output_style.col != g->text_style.col) { + current_paragraph->done_color(); + output_style.col = g->text_style.col; + current_paragraph->do_color(&output_style.col); + } } /* @@ -2070,18 +3138,14 @@ void html_printer::do_sup_or_sub (text_glob *g) } /* - * translate_to_html - translates a textual string into html text + * emit_html - write out the html text */ -void html_printer::translate_to_html (text_glob *g) +void html_printer::emit_html (text_glob *g) { - char buf[MAX_STRING_LENGTH]; - do_font(g); determine_space(g); - str_translate_to_html(g->text_style.f, buf, MAX_STRING_LENGTH, - g->text_string, g->text_length, TRUE); - current_paragraph->do_emittext(buf, strlen(buf)); + current_paragraph->do_emittext(g->text_string, g->text_length); output_vpos = g->minv; output_hpos = g->maxh; output_vpos_max = g->maxv; @@ -2094,18 +3158,26 @@ void html_printer::translate_to_html (text_glob *g) void html_printer::flush_sbuf() { - if (sbuf_len > 0) { + if (sbuf.length() > 0) { int r=font::res; // resolution of the device set_style(sbuf_style); + if (overstrike_detected && (! is_bold(sbuf_style.f))) { + font *bold_font = make_bold(sbuf_style.f); + if (bold_font != NULL) + sbuf_style.f = bold_font; + } - page_contents->add(&sbuf_style, sbuf, sbuf_len, + page_contents->add(&sbuf_style, sbuf, line_number, sbuf_vpos-sbuf_style.point_size*r/72, sbuf_start_hpos, sbuf_vpos , sbuf_end_hpos); output_hpos = sbuf_end_hpos; output_vpos = sbuf_vpos; - sbuf_len = 0; + last_sbuf_length = 0; + sbuf_prev_hpos = sbuf_end_hpos; + overstrike_detected = FALSE; + sbuf.clear(); } } @@ -2119,6 +3191,7 @@ void html_printer::draw(int code, int *p, int np, const environment *env) switch (code) { case 'l': +# if 0 if (np == 2) { page_contents->add_line(&sbuf_style, line_number, @@ -2126,6 +3199,7 @@ void html_printer::draw(int code, int *p, int np, const environment *env) } else { error("2 arguments required for line"); } +# endif break; case 't': { @@ -2143,125 +3217,30 @@ void html_printer::draw(int code, int *p, int np, const environment *env) } case 'P': - // fall through + break; case 'p': - { -#if 0 - if (np & 1) { - error("even number of arguments required for polygon"); - break; - } - if (np == 0) { - error("no arguments for polygon"); - break; - } - // firstly lets add our current position to polygon - int oh=env->hpos; - int ov=env->vpos; - int i=0; - - while (i<np) { - p[i+0] += oh; - p[i+1] += ov; - oh = p[i+0]; - ov = p[i+1]; - i += 2; - } - // now store polygon in page - page_contents->add_polygon(code, np, p, env->hpos, env->vpos, env->size, fill); -#endif - } break; case 'E': - // fall through + break; case 'e': -#if 0 - if (np != 2) { - error("2 arguments required for ellipse"); - break; - } - page_contents->add_line(code, - env->hpos, env->vpos-p[1]/2, env->hpos+p[0], env->vpos+p[1]/2, - env->size, fill); -#endif break; case 'C': - // fill circle - + break; case 'c': - { -#if 0 - // troff adds an extra argument to C - if (np != 1 && !(code == 'C' && np == 2)) { - error("1 argument required for circle"); - break; - } - page_contents->add_line(code, - env->hpos, env->vpos-p[0]/2, env->hpos+p[0], env->vpos+p[0]/2, - env->size, fill); -#endif - } break; case 'a': - { -#if 0 - if (np == 4) { - double c[2]; - - if (adjust_arc_center(p, c)) { - page_contents->add_arc('a', env->hpos, env->vpos, p, c, env->size, fill); - } else { - // a straignt line - page_contents->add_line('l', env->hpos, env->vpos, p[0]+p[2], p[1]+p[3], env->size, fill); - } - } else { - error("4 arguments required for arc"); - } -#endif - } break; case '~': - { -#if 0 - if (np & 1) { - error("even number of arguments required for spline"); - break; - } - if (np == 0) { - error("no arguments for spline"); - break; - } - // firstly lets add our current position to spline - int oh=env->hpos; - int ov=env->vpos; - int i=0; - - while (i<np) { - p[i+0] += oh; - p[i+1] += ov; - oh = p[i+0]; - ov = p[i+1]; - i += 2; - } - page_contents->add_spline('~', env->hpos, env->vpos, np, p, env->size, fill); -#endif - } break; case 'f': - { -#if 0 - if (np != 1 && np != 2) { - error("1 argument required for fill"); - break; - } - fill = p[0]; - if (fill < 0 || fill > FILL_MAX) { - // This means fill with the current color. - fill = FILL_MAX + 1; - } -#endif - break; - } + break; + case 'F': + // fill with color env->fill + if (background != NULL) + delete background; + background = new color; + *background = *env->fill; + break; default: error("unrecognised drawing command `%1'", char(code)); @@ -2272,7 +3251,8 @@ void html_printer::draw(int code, int *p, int np, const environment *env) html_printer::html_printer() : html(0, MAX_LINE_LENGTH), no_of_printed_pages(0), - sbuf_len(0), + last_sbuf_length(0), + overstrike_detected(FALSE), output_hpos(-1), output_vpos(-1), output_vpos_max(-1), @@ -2282,21 +3262,22 @@ html_printer::html_printer() header_indent(-1), supress_sub_sup(TRUE), cutoff_heading(100), + indent(NULL), + table(NULL), end_center(0), end_tempindent(0), next_tag(INLINE), fill_on(TRUE), + max_linelength(-1), linelength(0), pageoffset(0), indentation(0), prev_indent(0), - line_number(0) + pointsize(0), + line_number(0), + background(default_background) { -#if defined(DEBUGGING) - file_list.add_new_file(stdout); -#else file_list.add_new_file(xtmpfile()); -#endif html.set_file(file_list.get_file()); if (font::hor != 24) fatal("horizontal resolution must be 24"); @@ -2316,6 +3297,7 @@ html_printer::html_printer() res = r; html.set_fixed_point(point); space_char_index = font::name_to_index("space"); + space_width = font::hor; paper_length = font::paperlength; linelength = font::res*13/2; if (paper_length == 0) @@ -2325,174 +3307,65 @@ html_printer::html_printer() } /* - * add_char_to_sbuf - adds a single character to the sbuf. - */ - -void html_printer::add_char_to_sbuf (unsigned char code) -{ - if (sbuf_len < SBUF_SIZE) { - sbuf[sbuf_len] = code; - sbuf_len++; - } else { - fatal("need to increase SBUF_SIZE"); - } -} - -/* * add_to_sbuf - adds character code or name to the sbuf. */ -void html_printer::add_to_sbuf (unsigned char code, const char *name) +void html_printer::add_to_sbuf (int index, const string &s) { - if (name == 0) { - add_char_to_sbuf(code); - } else { - if (sbuf_style.f != NULL) { - char *html_glyph = get_html_translation(sbuf_style.f, name); + if (sbuf_style.f == NULL) + return; - if (html_glyph == NULL) { - add_char_to_sbuf(code); - } else { - int l = strlen(html_glyph); - int i; + char *html_glyph = NULL; + unsigned int code = sbuf_style.f->get_code(index); - // Escape the name, so that "&" doesn't get expanded to "&" - // later during translate_to_html. - add_char_to_sbuf('\\'); add_char_to_sbuf('('); + if (s.empty()) { + if (sbuf_style.f->contains(index)) + html_glyph = (char *)sbuf_style.f->get_special_device_encoding(index); + else + html_glyph = NULL; + + if ((html_glyph == NULL) && (code >= UNICODE_DESC_START)) + html_glyph = to_unicode(code); + } else + html_glyph = get_html_translation(sbuf_style.f, s); - for (i=0; i<l; i++) { - add_char_to_sbuf(html_glyph[i]); - } - add_char_to_sbuf('\\'); add_char_to_sbuf(')'); - } - } - } + last_sbuf_length = sbuf.length(); + if (html_glyph == NULL) + sbuf += ((char)code); + else + sbuf += html_glyph; } -int html_printer::sbuf_continuation (unsigned char code, const char *name, +int html_printer::sbuf_continuation (int index, const char *name, const environment *env, int w) { - if (sbuf_end_hpos == env->hpos) { - add_to_sbuf(code, name); + /* + * lets see whether the glyph is closer to the end of sbuf + */ + if ((sbuf_end_hpos == env->hpos) + || ((sbuf_prev_hpos < sbuf_end_hpos) + && (env->hpos < sbuf_end_hpos) + && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) { + add_to_sbuf(index, name); + sbuf_prev_hpos = sbuf_end_hpos; sbuf_end_hpos += w + sbuf_kern; - return( TRUE ); + return TRUE; } else { - if ((sbuf_len < SBUF_SIZE-1) && (env->hpos >= sbuf_end_hpos) && + if ((env->hpos >= sbuf_end_hpos) && ((sbuf_kern == 0) || (sbuf_end_hpos - sbuf_kern != env->hpos))) { /* * lets see whether a space is needed or not */ - int space_width = sbuf_style.f->get_space_width(sbuf_style.point_size); - if (env->hpos-sbuf_end_hpos < space_width/2) { - add_to_sbuf(code, name); + if (env->hpos-sbuf_end_hpos < space_width) { + add_to_sbuf(index, name); + sbuf_prev_hpos = sbuf_end_hpos; sbuf_end_hpos = env->hpos + w; - return( TRUE ); + return TRUE; } } } - return( FALSE ); -} - -/* - * seen_backwards_escape - returns TRUE if we can see a escape at position i..l in s - */ - -int html_printer::seen_backwards_escape (char *s, int l) -{ - /* - * this is tricky so it is broken into components for clarity - * (we let the compiler put in all back into a complex expression) - */ - if ((l>0) && (sbuf[l] == '(') && (sbuf[l-1] == '\\')) { - /* - * ok seen '\(' but we must now check for '\\(' - */ - if ((l>1) && (sbuf[l-2] == '\\')) { - /* - * escaped the escape - */ - return( FALSE ); - } else { - return( TRUE ); - } - } else { - return( FALSE ); - } -} - -/* - * reverse - return reversed string. - */ - -char *reverse (char *s) -{ - int i=0; - int j=strlen(s)-1; - char t; - - while (i<j) { - t = s[i]; - s[i] = s[j]; - s[j] = t; - i++; - j--; - } - return( s ); -} - -/* - * remove_last_char_from_sbuf - removes the last character from sbuf. - */ - -char *html_printer::remove_last_char_from_sbuf () -{ - int l=sbuf_len; - static char last[MAX_STRING_LENGTH]; - - if (l>0) { - l--; - if ((sbuf[l] == ')') && (l>0) && (sbuf[l-1] == '\\')) { - /* - * found terminating escape - */ - int i=0; - - l -= 2; - while ((l>0) && (! seen_backwards_escape(sbuf, l))) { - if (sbuf[l] == '\\') { - if (sbuf[l-1] == '\\') { - last[i] = sbuf[l]; - i++; - l--; - } - } else { - last[i] = sbuf[l]; - i++; - } - l--; - } - last[i] = (char)0; - sbuf_len = l; - if (seen_backwards_escape(sbuf, l)) { - sbuf_len--; - } - return( reverse(last) ); - } else { - if ((sbuf[l] == '\\') && (l>0) && (sbuf[l-1] == '\\')) { - l -= 2; - sbuf_len = l; - return( "\\" ); - } else { - sbuf_len--; - last[0] = sbuf[sbuf_len]; - last[1] = (char)0; - return( last ); - } - } - } else { - return( NULL ); - } + return FALSE ; } /* @@ -2500,149 +3373,57 @@ char *html_printer::remove_last_char_from_sbuf () * return the device encoding for such character. */ -char *get_html_translation (font *f, const char *name) +char *get_html_translation (font *f, const string &name) { - int index; + int index; - if ((f == 0) || (name == 0) || (strcmp(name, "") == 0)) { - return( NULL ); - } else { - index = f->name_to_index((char *)name); + if ((f == 0) || name.empty()) + return NULL; + else { + index = f->name_to_index((char *)(name + '\0').contents()); if (index == 0) { - error("character `%s' not found", name); - return( NULL ); - } else { - if (f->contains(index)) { - return( (char *)f->get_special_device_encoding(index) ); - } else { - return( NULL ); - } - } + error("character `%s' not found", (name + '\0').contents()); + return NULL; + } else + if (f->contains(index)) + return (char *)f->get_special_device_encoding(index); + else + return NULL; } } /* - * to_unicode - returns a unicode translation of char, ch. - */ - -static char *to_unicode (unsigned char ch) -{ - static char buf[20]; - - sprintf(buf, "&#%u;", (unsigned int)ch); - return( buf ); -} - -/* - * char_translate_to_html - convert a single non escaped character - * into the appropriate html character. + * overstrike - returns TRUE if the glyph (i, name) is going to overstrike + * a previous glyph in sbuf. + * If TRUE the font is changed to bold and the previous sbuf + * is flushed. */ -int char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single) +int html_printer::overstrike(int index, const char *name, const environment *env, int w) { - if (and_single) { - int t, l; - char *translation; - char name[2]; - - name[0] = ch; - name[1] = (char)0; - translation = get_html_translation(f, name); - if ((translation == NULL) && (ch >= UNICODE_DESC_START)) { - translation = to_unicode(ch); - } - if (translation) { - l = strlen(translation); - t = max(0, min(l, buflen-b)); - strncpy(&buf[b], translation, t); - b += t; - } else { - if (b<buflen) { - buf[b] = ch; - b++; - } - } - } else { + if ((env->hpos < sbuf_end_hpos) + || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) { /* - * do not attempt to encode single characters + * at this point we have detected an overlap */ - if (b<buflen) { - buf[b] = ch; - b++; - } - } - return( b ); -} - -/* - * str_translate_to_html - converts a string, str, into html text. It places - * the output input buffer, buf. It truncates string, str, if - * there is not enough space in buf. - * It looks up the html character encoding of single characters - * if, and_single, is TRUE. Characters such as < > & etc. - */ - -void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len, int and_single) -{ - char *translation; - int e; - char escaped_char[MAX_STRING_LENGTH]; - int l; - int i=0; - int b=0; - int t=0; - -#if 0 - if (strcmp(str, "``@,;:\\\\()[]''") == 0) { - stop(); - } -#endif - while (str[i] != (char)0) { - if ((str[i]=='\\') && (i+1<len)) { - i++; // skip the leading backslash - if (str[i] == '(') { - // start of escape - i++; - e = 0; - while ((str[i] != (char)0) && - (! ((str[i] == '\\') && (i+1<len) && (str[i+1] == ')')))) { - if (str[i] == '\\') { - i++; - } - escaped_char[e] = str[i]; - e++; - i++; - } - if ((str[i] == '\\') && (i+1<len) && (str[i+1] == ')')) { - i += 2; - } - escaped_char[e] = (char)0; - if (e > 0) { - translation = get_html_translation(f, escaped_char); - if (translation) { - l = strlen(translation); - t = max(0, min(l, buflen-b)); - strncpy(&buf[b], translation, t); - b += t; - } else { - int index=f->name_to_index(escaped_char); - - if (f->contains(index) && (index != 0)) { - buf[b] = f->get_code(index); - b++; - } - } - } - } else { - b = char_translate_to_html(f, buf, buflen, str[i], b, and_single); - i++; - } + if (overstrike_detected) { + /* already detected, remove previous glyph and use this glyph */ + sbuf.set_length(last_sbuf_length); + add_to_sbuf(index, name); + sbuf_end_hpos = env->hpos + w; + return TRUE; } else { - b = char_translate_to_html(f, buf, buflen, str[i], b, and_single); - i++; + /* first time we have detected an overstrike in the sbuf */ + sbuf.set_length(last_sbuf_length); /* remove previous glyph */ + if (! is_bold(sbuf_style.f)) + flush_sbuf(); + overstrike_detected = TRUE; + add_to_sbuf(index, name); + sbuf_end_hpos = env->hpos + w; + return TRUE; } } - buf[min(b, buflen)] = (char)0; + return FALSE ; } /* @@ -2652,33 +3433,25 @@ void str_translate_to_html (font *f, char *buf, int buflen, char *str, int len, void html_printer::set_char(int i, font *f, const environment *env, int w, const char *name) { - unsigned char code = f->get_code(i); - -#if 0 - if (code == ' ') { - stop(); - } -#endif - style sty(f, env->size, env->height, env->slant, env->fontno); + style sty(f, env->size, env->height, env->slant, env->fontno, *env->col); if (sty.slant != 0) { if (sty.slant > 80 || sty.slant < -80) { error("silly slant `%1' degrees", sty.slant); sty.slant = 0; } } - if ((sbuf_len > 0) && (sbuf_len < SBUF_SIZE) && (sty == sbuf_style) && - (sbuf_vpos == env->vpos) && (sbuf_continuation(code, name, env, w))) { + if (((! sbuf.empty()) && (sty == sbuf_style) && (sbuf_vpos == env->vpos)) + && (sbuf_continuation(i, name, env, w) || overstrike(i, name, env, w))) return; - } else { - flush_sbuf(); - sbuf_len = 0; - add_to_sbuf(code, name); - sbuf_end_hpos = env->hpos + w; - sbuf_start_hpos = env->hpos; - sbuf_vpos = env->vpos; - sbuf_style = sty; - sbuf_kern = 0; - } + + flush_sbuf(); + add_to_sbuf(i, name); + sbuf_end_hpos = env->hpos + w; + sbuf_start_hpos = env->hpos; + sbuf_prev_hpos = env->hpos; + sbuf_vpos = env->vpos; + sbuf_style = sty; + sbuf_kern = 0; } /* @@ -2694,9 +3467,11 @@ void html_printer::write_title (int in_head) html.put_string("</title>").nl().nl(); } else { title.has_been_written = TRUE; - html.put_string("<h1 align=center>"); - html.put_string(title.text); - html.put_string("</h1>").nl().nl(); + if (title.with_h1) { + html.put_string("<h1 align=center>"); + html.put_string(title.text); + html.put_string("</h1>").nl().nl(); + } } } else if (in_head) { // place empty title tags to help conform to `tidy' @@ -2731,9 +3506,7 @@ void html_printer::begin_page(int n) output_vpos = -1; output_vpos_max = -1; current_paragraph = new html_text(&html); -#if defined(INDENTATION) - current_paragraph->do_indent(indent.text, indentation, pageoffset, linelength); -#endif + do_indent(indentation, pageoffset, linelength); current_paragraph->do_para(""); } @@ -2748,47 +3521,62 @@ font *html_printer::make_font(const char *nm) return html_font::load_html_font(nm); } +void html_printer::do_body (void) +{ + if (background == NULL) + fputs("<body>\n\n", stdout); + else { + unsigned int r, g, b; + char buf[6+1]; + + background->get_rgb(&r, &g, &b); + // we have to scale 0..0xFFFF to 0..0xFF + sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); + + fputs("<body bgcolor=\"#", stdout); + fputs(buf, stdout); + fputs("\">\n\n", stdout); + } +} + html_printer::~html_printer() { +#ifdef LONG_FOR_TIME_T + long t; +#else + time_t t; +#endif + current_paragraph->flush_text(); html.end_line(); html.set_file(stdout); + html.begin_comment("Creator : ") + .put_string("groff ") + .put_string("version ") + .put_string(Version_string) + .end_comment(); + + t = time(0); + html.begin_comment("CreationDate: ") + .put_string(ctime(&t), strlen(ctime(&t))-1) + .end_comment(); + /* * 'HTML: The definitive guide', O'Reilly, p47. advises against specifying - * the dtd, so for the moment I'll leave this commented out. - * If requested we could always emit it if a command line switch - * was present. - * - * fputs("<!doctype html public \"-//IETF//DTD HTML 4.0//EN\">\n", stdout); + * the dtd. */ + // fputs("<!doctype html public \"-//IETF//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n", stdout); fputs("<html>\n", stdout); fputs("<head>\n", stdout); fputs("<meta name=\"generator\" content=\"groff -Thtml, see www.gnu.org\">\n", stdout); fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout); write_title(TRUE); fputs("</head>\n", stdout); - fputs("<body>\n\n", stdout); + do_body(); + write_title(FALSE); header.write_headings(stdout, FALSE); write_rule(); - { - html.begin_comment("Creator : ") - .put_string("groff ") - .put_string("version ") - .put_string(Version_string) - .end_comment(); - } - { -#ifdef LONG_FOR_TIME_T - long -#else - time_t -#endif - t = time(0); - html.begin_comment("CreationDate: ") - .put_string(ctime(&t), strlen(ctime(&t))-1) - .end_comment(); - } #if defined(DEBUGGING) html.begin_comment("Total number of pages: ").put_string(i_to_a(no_of_printed_pages)).end_comment(); #endif @@ -2825,13 +3613,13 @@ void html_printer::special(char *s, const environment *env, char type) if (s != 0) { flush_sbuf(); if (env->fontno >= 0) { - style sty(get_font_from_index(env->fontno), env->size, env->height, env->slant, env->fontno); + style sty(get_font_from_index(env->fontno), env->size, env->height, + env->slant, env->fontno, *env->col); sbuf_style = sty; } if (strncmp(s, "html:", 5) == 0) { int r=font::res; /* resolution of the device */ - char buf[MAX_STRING_LENGTH]; font *f=sbuf_style.f; if (f == NULL) { @@ -2839,28 +3627,26 @@ void html_printer::special(char *s, const environment *env, char type) f = font::load_font("TR", &found); } - str_translate_to_html(f, buf, MAX_STRING_LENGTH, - &s[5], strlen(s)-5, FALSE); /* * need to pass rest of string through to html output during flush */ - page_contents->add_html(&sbuf_style, buf, strlen(buf), - line_number, - env->vpos-env->size*r/72, env->hpos, - env->vpos , env->hpos); + page_contents->add_and_encode(&sbuf_style, string(&s[5]), + line_number, + env->vpos-env->size*r/72, env->hpos, + env->vpos , env->hpos); /* * assume that the html command has no width, if it does then hopefully troff * will have fudged this in a macro by requesting that the formatting move right by - * the appropriate width. + * the appropriate amount. */ } else if (strncmp(s, "index:", 6) == 0) { cutoff_heading = atoi(&s[6]); } else if (strncmp(s, "html-tag:", 9) == 0) { int r=font::res; /* resolution of the device */ - page_contents->add_tag(&sbuf_style, s, strlen(s), + page_contents->add_tag(&sbuf_style, string(s), line_number, env->vpos-env->size*r/72, env->hpos, env->vpos , env->hpos); @@ -2879,15 +3665,24 @@ int main(int argc, char **argv) { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "o:i:I:D:F:vd?lrn", long_options, NULL)) + while ((c = getopt_long(argc, argv, "a:g:o:i:I:D:F:vbdhlrnp", long_options, NULL)) != EOF) switch(c) { case 'v': - { - printf("GNU post-grohtml (groff) version %s\n", Version_string); - exit(0); - break; - } + printf("GNU post-grohtml (groff) version %s\n", Version_string); + exit(0); + break; + case 'a': + /* text antialiasing bits - handled by pre-html */ + break; + case 'g': + /* graphic antialiasing bits - handled by pre-html */ + break; + case 'b': + // set background color to white + default_background = new color; + default_background->set_gray(color::MAX_COLOR_VAL); + break; case 'F': font::command_line_font_dir(optarg); break; @@ -2897,9 +3692,19 @@ int main(int argc, char **argv) case 'r': auto_rule = FALSE; break; + case 'd': + /* handled by pre-html */ + break; + case 'h': + /* do not use the Hn headings of html, but manufacture our own */ + manufacture_headings = TRUE; + break; case 'o': /* handled by pre-html */ break; + case 'p': + /* handled by pre-html */ + break; case 'i': /* handled by pre-html */ break; @@ -2935,6 +3740,6 @@ int main(int argc, char **argv) static void usage(FILE *stream) { - fprintf(stream, "usage: %s [-vld?n] [-D dir] [-I image_stem] [-F dir] [files ...]\n", + fprintf(stream, "usage: %s [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n", program_name); } |