summaryrefslogtreecommitdiffstats
path: root/contrib/groff/src/devices/grohtml
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/groff/src/devices/grohtml')
-rw-r--r--contrib/groff/src/devices/grohtml/Makefile.sub11
-rw-r--r--contrib/groff/src/devices/grohtml/grohtml.man96
-rw-r--r--contrib/groff/src/devices/grohtml/html-table.cc687
-rw-r--r--contrib/groff/src/devices/grohtml/html-table.h130
-rw-r--r--contrib/groff/src/devices/grohtml/html-text.cc581
-rw-r--r--contrib/groff/src/devices/grohtml/html-text.h124
-rw-r--r--contrib/groff/src/devices/grohtml/html.h3
-rw-r--r--contrib/groff/src/devices/grohtml/output.cc56
-rw-r--r--contrib/groff/src/devices/grohtml/post-html.cc2417
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 = &pound;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 "&amp;"
- // 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);
}
OpenPOWER on IntegriCloud