groff-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Groff-commit] groff ./ChangeLog src/roff/troff/request.h src/...


From: Werner LEMBERG
Subject: [Groff-commit] groff ./ChangeLog src/roff/troff/request.h src/...
Date: Tue, 12 Oct 2004 18:36:10 -0400

CVSROOT:        /cvsroot/groff
Module name:    groff
Branch:         
Changes by:     Werner LEMBERG <address@hidden> 04/10/12 21:39:31

Modified files:
        .              : ChangeLog 
        src/roff/troff : request.h 
        src/devices/grohtml: html.h html-table.cpp html-table.h 
                             html-text.cpp html-text.h output.cpp 
                             post-html.cpp 
        src/preproc/html: pre-html.cpp 

Log message:
        * src/roff/troff/request.h (macro): Make `p' public.
        New variable `is_a_diversion'.
        New member function `is_diversion'.
        
        * src/devices/grohtml/html.h (simple_output): New member function
        `force_nl'.
        
        * src/devices/grohtml/html-table.cpp (tabs::compatible): Fix
        computation of `total'.
        (tabs::check_init): New function.
        (html_table::emit_table_header): Emit style data.
        (html_table::insert_column): Improved.
        
        * src/devices/grohtml/html-table.h: Updated.
        
        * src/devices/grohtml/html-text.cpp (html_text::html_text):
        Initialize `start_space' with TRUE.
        (html_text::end_tag, html_start_tag): Fix `P_TAG' and `PRE_TAG'
        cases.
        (html_text::flush_text): Set `start_space' flag.
        (html_text::uses_indent, html_text::remove_para_space,
        html_text::get_alignment): New functions.
        (html_text::push_para): Updated.
        (html_text::do_para): Check for empty argument.
        Don't set `space_emitted'.
        (html_text::do_space, html_text::emit_space): Updated.
        
        * src/devices/grohtml/html-text.h (tag_definition): New variable
        `really_issued'.
        (html_text): New member function `uses_indent', `remove_para_space',
        `get_alignment'.
        
        * src/devices/grohtml/output.cpp (simple_output::force_nl): New
        function.
        (simple_output:nl): Always emit `\n'.
        
        * src/devices/grohtml/post-html.cpp: Include `string.h'.
        (BASE_POINT_SIZE): Removed.
        (base_point_size, head_info): New global variables.
        (text_glob): New member functions `is_ll', `is_tl', `is_eo_tl',
        `is_eo_h'.
        (text_glob::is_nf, text_glob::is_fi): Handle `.fi 0' and `.fi 1'
        tags, respectively.
        (page::add_and_encode): Pass additional parameter for tag flag.
        (assert_pos): New structure.
        (assert_state): New class.
        (html_printer): Remove `indentation', `prev_indent'.
        Add variables `troff_indent', `device_indent', `temp_indent'.
        Add variables `seen_indent', `next_indent', `seen_pageoffset',
        `next_pageoffset', `seen_linelenght', `next_linelength',
        `seen_center', `next_center', `seen_space', `seen_break', `as'.
        Add member functions `do_check_center', `do_space', `do_head',
        `get_troff_indent', `restore_troff_indent', `handle_assertion',
        `handle_state_assertion', `do_end_para', `set_char_and_width'.
        Change argument to `do_fill' to `char *'.
        Update constructor.
        (html_printer::emit_raw): Call `shutdown_table'.
        Use new functions.
        (html_printer::do_center): Simplified.
        (html_printer::do_title): Improved.
        (html_printer::write_header): Emit one more newline.
        Use new functions.
        (html_printer::do_heading, html_printer::do_indent,
        html_printer::do_eol, html_printer::do_tab_ts,
        html_printer::do_tab, html_printer::do_tab0,
        html_printer::calc_po_in, html_printer::next_horiz_pos,
        html_printer::remove_courier_tabs,
        html_printer::insert_tab0_foreach_tab, html_printer::begin_page):
        Updated.
        (html_printer::do_linelength, html_printer::do_pageoffset,
        html_printer::do_indentation, html_printer::do_tempindent,
        html_printer::do_tab_te): Simplified.
        (html_printer::do_pointsize): Check whether point size is really
        associated a `.tl' tag.
        (html_printer::do_break): Rewritten.
        (html_printer::troff_tag): Improved.
        (html_printer::flush_globs): Updated.
        (html_printer::lookahead_for_tables): Handle `is_br'.
        Use new functions.
        (html_printer::set_char): Check `sbuf_style.f'.
        (html_printer::write_navigation): Use string comparison.
        (html_printer::~html_printer): Emit `head_info'.
        (html_printer::special): Rewritten.
        (get_str, make_val): New functions.
        (main): New option `s' to set the base point size.
        
        * src/preproc/html/pre-html.cpp (scanArguments): Handle option `s'.

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/ChangeLog.diff?tr1=1.749&tr2=1.750&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/roff/troff/request.h.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/html.h.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/html-table.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/html-table.h.diff?tr1=1.2&tr2=1.3&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/html-text.cpp.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/html-text.h.diff?tr1=1.11&tr2=1.12&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/output.cpp.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/devices/grohtml/post-html.cpp.diff?tr1=1.9&tr2=1.10&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/groff/groff/src/preproc/html/pre-html.cpp.diff?tr1=1.11&tr2=1.12&r1=text&r2=text

Patches:
Index: groff/ChangeLog
diff -u groff/ChangeLog:1.749 groff/ChangeLog:1.750
--- groff/ChangeLog:1.749       Tue Oct 12 05:44:51 2004
+++ groff/ChangeLog     Tue Oct 12 21:39:30 2004
@@ -1,3 +1,94 @@
+2004-10-11  Gaius Mulley  <address@hidden>
+
+       * src/roff/troff/request.h (macro): Make `p' public.
+       New variable `is_a_diversion'.
+       New member function `is_diversion'.
+
+
+       * src/devices/grohtml/html.h (simple_output): New member function
+       `force_nl'.
+
+       * src/devices/grohtml/html-table.cpp (tabs::compatible): Fix
+       computation of `total'.
+       (tabs::check_init): New function.
+       (html_table::emit_table_header): Emit style data.
+       (html_table::insert_column): Improved.
+
+       * src/devices/grohtml/html-table.h: Updated.
+
+       * src/devices/grohtml/html-text.cpp (html_text::html_text):
+       Initialize `start_space' with TRUE.
+       (html_text::end_tag, html_start_tag): Fix `P_TAG' and `PRE_TAG'
+       cases.
+       (html_text::flush_text): Set `start_space' flag.
+       (html_text::uses_indent, html_text::remove_para_space,
+       html_text::get_alignment): New functions.
+       (html_text::push_para): Updated.
+       (html_text::do_para): Check for empty argument.
+       Don't set `space_emitted'.
+       (html_text::do_space, html_text::emit_space): Updated.
+
+       * src/devices/grohtml/html-text.h (tag_definition): New variable
+       `really_issued'.
+       (html_text): New member function `uses_indent', `remove_para_space',
+       `get_alignment'.
+
+       * src/devices/grohtml/output.cpp (simple_output::force_nl): New
+       function.
+       (simple_output:nl): Always emit `\n'.
+
+       * src/devices/grohtml/post-html.cpp: Include `string.h'.
+       (BASE_POINT_SIZE): Removed.
+       (base_point_size, head_info): New global variables.
+       (text_glob): New member functions `is_ll', `is_tl', `is_eo_tl',
+       `is_eo_h'.
+       (text_glob::is_nf, text_glob::is_fi): Handle `.fi 0' and `.fi 1'
+       tags, respectively.
+       (page::add_and_encode): Pass additional parameter for tag flag.
+       (assert_pos): New structure.
+       (assert_state): New class.
+       (html_printer): Remove `indentation', `prev_indent'.
+       Add variables `troff_indent', `device_indent', `temp_indent'.
+       Add variables `seen_indent', `next_indent', `seen_pageoffset',
+       `next_pageoffset', `seen_linelenght', `next_linelength',
+       `seen_center', `next_center', `seen_space', `seen_break', `as'.
+       Add member functions `do_check_center', `do_space', `do_head',
+       `get_troff_indent', `restore_troff_indent', `handle_assertion',
+       `handle_state_assertion', `do_end_para', `set_char_and_width'.
+       Change argument to `do_fill' to `char *'.
+       Update constructor.
+       (html_printer::emit_raw): Call `shutdown_table'.
+       Use new functions.
+       (html_printer::do_center): Simplified.
+       (html_printer::do_title): Improved.
+       (html_printer::write_header): Emit one more newline.
+       Use new functions.
+       (html_printer::do_heading, html_printer::do_indent,
+       html_printer::do_eol, html_printer::do_tab_ts,
+       html_printer::do_tab, html_printer::do_tab0,
+       html_printer::calc_po_in, html_printer::next_horiz_pos,
+       html_printer::remove_courier_tabs,
+       html_printer::insert_tab0_foreach_tab, html_printer::begin_page):
+       Updated.
+       (html_printer::do_linelength, html_printer::do_pageoffset,
+       html_printer::do_indentation, html_printer::do_tempindent,
+       html_printer::do_tab_te): Simplified.
+       (html_printer::do_pointsize): Check whether point size is really
+       associated a `.tl' tag.
+       (html_printer::do_break): Rewritten.
+       (html_printer::troff_tag): Improved.
+       (html_printer::flush_globs): Updated.
+       (html_printer::lookahead_for_tables): Handle `is_br'.
+       Use new functions.
+       (html_printer::set_char): Check `sbuf_style.f'.
+       (html_printer::write_navigation): Use string comparison.
+       (html_printer::~html_printer): Emit `head_info'.
+       (html_printer::special): Rewritten.
+       (get_str, make_val): New functions.
+       (main): New option `s' to set the base point size.
+
+       * src/preproc/html/pre-html.cpp (scanArguments): Handle option `s'.
+
 2004-10-10  Gaius Mulley  <address@hidden>
 
        * src/roff/troff/node.cpp: New extern `debug_state'.
Index: groff/src/devices/grohtml/html-table.cpp
diff -u groff/src/devices/grohtml/html-table.cpp:1.1 
groff/src/devices/grohtml/html-table.cpp:1.2
--- groff/src/devices/grohtml/html-table.cpp:1.1        Tue Apr 15 15:13:21 2003
+++ groff/src/devices/grohtml/html-table.cpp    Tue Oct 12 21:39:31 2004
@@ -1,5 +1,5 @@
 // -*- C++ -*-
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  *  Gaius Mulley (address@hidden) wrote html-table.cpp
  *
@@ -104,7 +104,7 @@
     while ((*s != (char)0) && isspace(*s))
       s++;
     // collect tab position
-    total += atoi(s);
+    total = atoi(s);
     // move over tab position
     while ((*s != (char)0) && !isspace(*s))
       s++;
@@ -162,6 +162,16 @@
 }
 
 /*
+ *  check_init - define tab stops using, s, providing none already exist.
+ */
+
+void tabs::check_init (const char *s)
+{
+  if (tab == NULL)
+    init(s);
+}
+
+/*
  *  find_tab - returns the tab number corresponding to the position, pos.
  */
 
@@ -326,10 +336,21 @@
 
     out->nl();
     out->nl();
+
+#if 0
     if (space)
       out->put_string("<p>");
+#endif
+
     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("<table width=\"100%\"")
+      .put_string(" border=0 rules=\"none\" frame=\"void\"\n")
+      .put_string("       cols=\"")
+      .put_number(n)
+      .put_string("\" cellspacing=\"0\" cellpadding=\"0\"")
+      .put_string(start_space ? " style=\"margin-top: 8px; margin-bottom: 
8px\"" : "")
+      .put_string(">")
+      .nl();
     out->put_string("<tr valign=\"top\" align=\"left\">").nl();
   }
 }
@@ -468,11 +489,11 @@
 void html_table::emit_finish_table (void)
 {
   finish_row();
-  // out->put_string("linelength = ").put_number(linelength).nl();
   out->put_string("</table>");
+#if 0
   if (start_space)
     out->put_string("</p>");
-  out->nl();
+#endif
 }
 
 /*
@@ -516,13 +537,23 @@
 int html_table::insert_column (int coln, int hstart, int hend, char align)
 {
   cols *c = columns;
-  cols *l = NULL;
+  cols *l = columns;
   cols *n = NULL;
 
   while (c != NULL && c->no < coln) {
     l = c;
     c = c->next;
   }
+  if (l != NULL && l->no>coln && hend > l->left)
+    return FALSE;      // new column bumps into previous one
+
+  l = NULL;
+  c = columns;
+  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
   
Index: groff/src/devices/grohtml/html-table.h
diff -u groff/src/devices/grohtml/html-table.h:1.2 
groff/src/devices/grohtml/html-table.h:1.3
--- groff/src/devices/grohtml/html-table.h:1.2  Tue Apr 15 15:13:21 2003
+++ groff/src/devices/grohtml/html-table.h      Tue Oct 12 21:39:31 2004
@@ -1,5 +1,5 @@
 // -*- C++ -*-
-/* Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  *  Gaius Mulley (address@hidden) wrote html-table.h
  *
@@ -45,6 +45,7 @@
   void  clear         (void);
   int   compatible    (const char *s);
   void  init          (const char *s);
+  void  check_init    (const char *s);
   int   find_tab      (int pos);
   int   get_tab_pos   (int n);
   char  get_tab_align (int n);
Index: groff/src/devices/grohtml/html-text.cpp
diff -u groff/src/devices/grohtml/html-text.cpp:1.3 
groff/src/devices/grohtml/html-text.cpp:1.4
--- groff/src/devices/grohtml/html-text.cpp:1.3 Thu Apr  8 20:43:20 2004
+++ groff/src/devices/grohtml/html-text.cpp     Tue Oct 12 21:39:31 2004
@@ -40,12 +40,12 @@
 
 #include "html-text.h"
 
-// #define DEBUGGING
+#undef DEBUGGING
 
 html_text::html_text (simple_output *op) :
   stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE),
   current_indentation(-1), pageoffset(-1), linelength(-1),
-  blank_para(TRUE), start_space(FALSE)
+  blank_para(TRUE), start_space(TRUE)
 {
 }
 
@@ -145,17 +145,19 @@
 
   case I_TAG:      out->put_string("</i>"); break;
   case B_TAG:      out->put_string("</b>"); break;
-  case P_TAG:      out->put_string("</p>");
-                   if (t->indent != NULL) {
+  case P_TAG:      if (t->indent == NULL) {
+                       if (t->really_issued)
+                        out->put_string("</p>");
+                   } else {
                     delete t->indent;
                     t->indent = NULL;
                   }
-                  out->nl(); out->enable_newlines(FALSE);
+                  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>"); out->nl(); 
out->enable_newlines(TRUE);
+  case PRE_TAG:    out->put_string("</pre>"); out->enable_newlines(TRUE);
                    blank_para = TRUE; break;
   case SMALL_TAG:  out->put_string("</small>"); break;
   case BIG_TAG:    out->put_string("</big>"); break;
@@ -214,16 +216,19 @@
 
   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) {
+  case P_TAG:      if (t->indent != NULL) {
                      out->nl();
-                     issue_tag("\n<p", (char *)t->arg1);
-                   } else {
-                    out->nl();
+#if defined(DEBUGGING)
                     out->simple_comment("INDENTATION");
+#endif
                     t->indent->begin(FALSE);
-                    start_space = FALSE;
-                     issue_tag("<p", (char *)t->arg1);
-                  }
+                    t->really_issued = FALSE;
+                  } else if (start_space) {
+                     out->nl();
+                     issue_tag("\n<p", (char *)t->arg1);
+                    t->really_issued = TRUE;
+                  } else
+                    t->really_issued = FALSE;
 
                    out->enable_newlines(TRUE); break;
   case SUB_TAG:    issue_tag("<sub", (char *)t->arg1); break;
@@ -231,9 +236,10 @@
   case TT_TAG:     issue_tag("<tt", (char *)t->arg1); break;
   case PRE_TAG:    if (t->indent != NULL) {
                      out->nl();
+#if defined(DEBUGGING)
                     out->simple_comment("INDENTATION");
+#endif
                     t->indent->begin(FALSE);
-                    start_space = FALSE;
                    }
                    out->enable_newlines(TRUE);
                    out->nl(); issue_tag("<pre", (char *)t->arg1);
@@ -267,6 +273,7 @@
     free(p);
   }
   lastptr = NULL;
+  start_space = TRUE;
 }
 
 /*
@@ -285,6 +292,23 @@
   return FALSE;
 }
 
+/*
+ *  uses_indent - returns TRUE if the current paragraph is using a
+ *                html table to effect an indent.
+ */
+
+int html_text::uses_indent (void)
+{
+  tag_definition *p = stackptr;
+
+  while (p != NULL) {
+    if (p->indent != NULL)
+      return TRUE;
+    p = p->next;
+  }
+  return FALSE;
+}
+
 extern void stop();
 
 /*
@@ -343,6 +367,7 @@
   p->arg1         = arg;
   p->text_emitted = FALSE;
   p->indent       = in;
+  p->really_issued= FALSE;
 
   if (t == PRE_TAG && is_present(PRE_TAG))
     fatal("cannot have multiple PRE_TAGs");
@@ -364,6 +389,7 @@
   p->col          = *c;
   p->text_emitted = FALSE;
   p->indent       = NULL;
+  p->really_issued= FALSE;
 
   do_push(p);
 }
@@ -475,8 +501,8 @@
       /*
        *  push tag onto temp stack
        */
-      p->next  = temp;
-      temp     = p;
+      p->next = temp;
+      temp    = p;
     }
 
     /*
@@ -615,13 +641,12 @@
     if (text) {
       if (is_present(PRE_TAG)) {
        out->nl();
-      } else {
+      } else
        out->put_string("<br>").nl();
-      }
     }
-  } else {
+  } else
     check_emit_text(stackptr);
-  }
+
   out->put_string(s, length);
   space_emitted = FALSE;
   blank_para = FALSE;
@@ -637,14 +662,14 @@
     if (is_present(PRE_TAG)) {
       html_indent *i = remove_indent(PRE_TAG);
       done_pre();    
-      if (i == in || in == NULL)
+      if ((arg == NULL || (strcmp(arg, "") == 0)) &&
+         (i == in || in == NULL))
        in = i;
       else
        delete i;
     }
     remove_sub_sup();
     push_para(P_TAG, (void *)arg, in);
-    space_emitted = TRUE;
   }
 }
 
@@ -697,19 +722,34 @@
 }
 
 /*
+ *  remove_para_space - removes the leading space to a paragraph
+ *                      (effectively this trims off the <p> and </p>
+ *                      tags.
+ */
+
+void html_text::remove_para_space (void)
+{
+  start_space = FALSE;
+}
+
+/*
  *  do_space - issues an end of paragraph
  */
 
 void html_text::do_space (void)
 {
   if (is_in_pre()) {
+#if 0
     if (blank_para)
       start_space = TRUE;
     else {
+#endif
       do_emittext("", 0);
-      out->nl();
+      out->force_nl();
       space_emitted = TRUE;
+#if 0
     }
+#endif
   } else {
     html_indent *i = remove_indent(P_TAG);
 
@@ -766,7 +806,7 @@
 }
 
 /*
- *  starts_with_space - returns TRUE if we have start this paragraph with a .sp
+ *  starts_with_space - returns TRUE if we started this paragraph with a .sp
  */
 
 int html_text::starts_with_space (void)
@@ -780,14 +820,12 @@
 
 void html_text::emit_space (void)
 {
-  if (space_emitted) {
-    if (is_present(PRE_TAG)) {
-      do_emittext(" ", 1);
-    }
-  } else {
+  if (is_present(PRE_TAG))
+    do_emittext(" ", 1);
+  else
     out->space_or_newline();
-    space_emitted = TRUE;
-  }
+
+  space_emitted = TRUE;
 }
 
 /*
@@ -838,7 +876,8 @@
 }
 
 /*
- *  remove_sub_sup - removes a sub or sup tag, should either exist on the 
stack.
+ *  remove_sub_sup - removes a sub or sup tag, should either exist
+ *                   on the stack.
  */
 
 void html_text::remove_sub_sup (void)
@@ -921,6 +960,25 @@
 }
 
 /*
+ *  get_alignment - returns the alignment for the paragraph.
+ *                  If no alignment was given then we return "".
+ */
+
+char *html_text::get_alignment (void)
+{
+  if (is_present(P_TAG)) {
+    tag_definition *p=stackptr;
+
+    while (p != NULL) {
+      if (p->type == P_TAG && p->arg1 != NULL)
+       return (char *)p->arg1;
+      p = p->next;
+    }
+  }
+  return "";
+}
+
+/*
  *  do_small - potentially inserts a <small> tag into the html stream.
  *             However we check for a <big> tag, if present then we terminate 
it.
  *             Otherwise a <small> tag is inserted.
Index: groff/src/devices/grohtml/html-text.h
diff -u groff/src/devices/grohtml/html-text.h:1.11 
groff/src/devices/grohtml/html-text.h:1.12
--- groff/src/devices/grohtml/html-text.h:1.11  Wed Apr 16 21:10:51 2003
+++ groff/src/devices/grohtml/html-text.h       Tue Oct 12 21:39:31 2004
@@ -1,5 +1,5 @@
 // -*- C++ -*-
-/* Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
  *
  *  Gaius Mulley (address@hidden) wrote html-text.h
  *
@@ -41,6 +41,7 @@
   void           *arg1;
   int             text_emitted;
   color           col;
+  int             really_issued;
   html_indent    *indent;
   tag_definition *next;
 } tag_definition ;
@@ -89,9 +90,12 @@
   int    starts_with_space (void);
   void   emit_space        (void);
   int    is_in_pre         (void);
+  int    uses_indent       (void);
   void   remove_tag        (HTML_TAG tag);
   void   remove_sub_sup    (void);
   void   remove_para_align (void);
+  void   remove_para_space (void);
+  char  *get_alignment     (void);
 
 private:
   tag_definition   *stackptr;    /* the current paragraph state */
Index: groff/src/devices/grohtml/html.h
diff -u groff/src/devices/grohtml/html.h:1.7 
groff/src/devices/grohtml/html.h:1.8
--- groff/src/devices/grohtml/html.h:1.7        Mon Jan  5 22:49:06 2004
+++ groff/src/devices/grohtml/html.h    Tue Oct 12 21:39:31 2004
@@ -1,5 +1,5 @@
 // -*- C++ -*-
-/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
      Written by James Clark (address@hidden)
 
 This file is part of groff.
@@ -72,6 +72,7 @@
   simple_output &enable_newlines(int);
   simple_output &check_newline(int n);
   simple_output &nl(void);
+  simple_output &force_nl(void);
   simple_output &space_or_newline (void);
   simple_output &begin_tag (void);
   FILE *get_file();
Index: groff/src/devices/grohtml/output.cpp
diff -u groff/src/devices/grohtml/output.cpp:1.1 
groff/src/devices/grohtml/output.cpp:1.2
--- groff/src/devices/grohtml/output.cpp:1.1    Tue Apr 15 15:13:22 2003
+++ groff/src/devices/grohtml/output.cpp        Tue Oct 12 21:39:31 2004
@@ -1,5 +1,5 @@
 // -*- C++ -*-
-/* Copyright (C) 2000, 2001, 2003 Free Software Foundation, Inc.
+/* Copyright (C) 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
  *
  *  Gaius Mulley (address@hidden) wrote output.cpp
  *  but it owes a huge amount of ideas and raw code from
@@ -253,6 +253,19 @@
 }
 
 /*
+ *  force_nl - forces a newline.
+ */
+
+simple_output &simple_output::force_nl (void)
+{
+  space_or_newline();
+  col += last_word.flush(fp);
+  FPUTC('\n', fp);
+  col = 0;
+  return *this ;
+}
+
+/*
  *  nl - writes a newline providing that we
  *       are not in the first column.
  */
@@ -261,10 +274,8 @@
 {
   space_or_newline();
   col += last_word.flush(fp);
-  if (col != 0) {
-    FPUTC('\n', fp);
-    col = 0;
-  }
+  FPUTC('\n', fp);
+  col = 0;
   return *this ;
 }
 
Index: groff/src/devices/grohtml/post-html.cpp
diff -u groff/src/devices/grohtml/post-html.cpp:1.9 
groff/src/devices/grohtml/post-html.cpp:1.10
--- groff/src/devices/grohtml/post-html.cpp:1.9 Thu Oct  7 11:50:17 2004
+++ groff/src/devices/grohtml/post-html.cpp     Tue Oct 12 21:39:31 2004
@@ -38,6 +38,7 @@
 
 #include <stdio.h>
 #include <fcntl.h>
+#include <string.h>
 
 extern "C" const char *Version_string;
 
@@ -50,8 +51,7 @@
 
 #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 CENTER_TOLERANCE                2            /* how many pixels off 
center do we allow    */
 #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 */
@@ -60,7 +60,7 @@
 typedef enum {col_tag, tab_tag, tab0_tag, none} colType;
 
 #undef DEBUG_TABLES
-
+// #define DEBUG_TABLES
 
 /*
  *  prototypes
@@ -83,6 +83,10 @@
 static int multiple_files = FALSE;                   /* must we the output be 
divided into       */
                                                      /* multiple html files, 
one for each        */
                                                      /* heading?               
                  */
+static int base_point_size = 0;                      /* which troff font size 
maps onto html     */
+                                                     /* size 3?                
                  */
+static string head_info;                             /* user supplied 
information to be placed   */
+                                                     /* into <head> </head>    
                  */
 
 
 /*
@@ -114,7 +118,7 @@
 static int is_intersection (int a1, int a2, int b1, int b2)
 {
   // easier to prove NOT outside limits
-  return( ! ((a1 > b2) || (a2 < b1)) );
+  return ! ((a1 > b2) || (a2 < b1));
 }
 
 /*
@@ -123,7 +127,7 @@
 
 static int is_digit (char ch)
 {
-  return( (ch >= '0') && (ch <= '9') );
+  return (ch >= '0') && (ch <= '9');
 }
 
 /*
@@ -145,7 +149,7 @@
  */
 
 file::file (FILE *f)
-  : fp(f), next(0), new_output_file(FALSE),
+  : fp(f), next(NULL), new_output_file(FALSE),
     require_links(FALSE), output_file_name("")
 {
 }
@@ -174,7 +178,7 @@
  */
 
 files::files ()
-  : head(0), tail(0), ptr(0)
+  : head(NULL), tail(NULL), ptr(NULL)
 {
 }
 
@@ -187,7 +191,7 @@
   if (ptr)
     return ptr->fp;
   else
-    return 0;
+    return NULL;
 }
 
 /*
@@ -205,7 +209,7 @@
 
 void files::move_next (void)
 {
-  if (ptr != 0)
+  if (ptr != NULL)
     ptr = ptr->next;
 }
 
@@ -215,7 +219,7 @@
 
 void files::add_new_file (FILE *f)
 {
-  if (head == 0) {
+  if (head == NULL) {
     head = new file(f);
     tail = head;
   } else {
@@ -313,7 +317,7 @@
 };
 
 style::style()
-  : f(0)
+  : f(NULL)
 {
 }
 
@@ -349,12 +353,12 @@
 };
 
 char_block::char_block()
-: buffer(NULL), used(0), next(0)
+: buffer(NULL), used(0), next(NULL)
 {
 }
 
 char_block::char_block(int length)
-: used(0), next(0)
+: used(0), next(NULL)
 {
   buffer = (char *)malloc(max(length, char_block::SIZE));
   if (buffer == NULL)
@@ -379,13 +383,13 @@
 };
 
 char_buffer::char_buffer()
-: head(0), tail(0)
+: head(NULL), tail(NULL)
 {
 }
 
 char_buffer::~char_buffer()
 {
-  while (head != 0) {
+  while (head != NULL) {
     char_block *temp = head;
     head = head->next;
     delete temp;
@@ -400,7 +404,7 @@
   if (s == NULL || length == 0)
     return NULL;
 
-  if (tail == 0) {
+  if (tail == NULL) {
     tail = new char_block(length+1);
     head = tail;
   } else {
@@ -466,7 +470,10 @@
   int  is_in               (void);
   int  is_po               (void);
   int  is_ti               (void);
+  int  is_ll               (void);
   int  is_ce               (void);
+  int  is_tl               (void);
+  int  is_eo_tl            (void);
   int  is_eol_ce           (void);
   int  is_col              (void);
   int  is_tab              (void);
@@ -476,6 +483,7 @@
   int  is_tab_te           (void);
   int  is_nf               (void);
   int  is_fi               (void);
+  int  is_eo_h             (void);
   int  get_arg             (void);
   int  get_tab_args        (char *align);
 
@@ -516,7 +524,7 @@
 }
 
 text_glob::text_glob ()
-  : text_string(0), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1),
+  : text_string(NULL), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1),
     is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL)
 {
 }
@@ -649,7 +657,7 @@
 
 int text_glob::is_eol (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:eol") == 0) );
+  return is_tag && (strcmp(text_string, "html-tag:.eol") == 0);
 }
 
 /*
@@ -658,26 +666,54 @@
 
 int text_glob::is_eol_ce (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0) );
+  return is_tag && (strcmp(text_string, "html-tag:eol.ce") == 0);
+}
+
+/*
+ *  is_tl - returns TRUE if glob contains the tag .tl
+ */
+
+int text_glob::is_tl (void)
+{
+  return is_tag && (strcmp(text_string, "html-tag:.tl") == 0);
 }
 
+/*
+ *  is_eo_tl - returns TRUE if glob contains the tag eo.tl
+ */
+
+int text_glob::is_eo_tl (void)
+{
+  return is_tag && (strcmp(text_string, "html-tag:.eo.tl") == 0);
+}
 
 /*
- *  is_nf - returns TRUE if glob contains the tag .nf
+ *  is_nf - returns TRUE if glob contains the tag .fi 0
  */
 
 int text_glob::is_nf (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:.nf") == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.fi", 12) == 0) &&
+         (get_arg() == 0);
 }
 
 /*
- *  is_fi - returns TRUE if glob contains the tag .fi
+ *  is_fi - returns TRUE if glob contains the tag .fi 1
  */
 
 int text_glob::is_fi (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:.fi") == 0) );
+  return( is_tag && (strncmp(text_string, "html-tag:.fi", 12) == 0) &&
+         (get_arg() == 1) );
+}
+
+/*
+ *  is_eo_h - returns TRUE if glob contains the tag .eo.h
+ */
+
+int text_glob::is_eo_h (void)
+{
+  return is_tag && (strcmp(text_string, "html-tag:.eo.h") == 0);
 }
 
 /*
@@ -686,7 +722,7 @@
 
 int text_glob::is_ce (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:.ce") == 0) );
+  return is_tag && (strcmp(text_string, "html-tag:.ce") == 0);
 }
 
 /*
@@ -695,7 +731,7 @@
 
 int text_glob::is_in (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:.in ", 
strlen("html-tag:.in ")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.in ", strlen("html-tag:.in 
")) == 0);
 }
 
 /*
@@ -704,7 +740,7 @@
 
 int text_glob::is_po (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:.po ", 
strlen("html-tag:.po ")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.po ", strlen("html-tag:.po 
")) == 0);
 }
 
 /*
@@ -713,7 +749,16 @@
 
 int text_glob::is_ti (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:.ti ", 
strlen("html-tag:.ti ")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.ti ", strlen("html-tag:.ti 
")) == 0);
+}
+
+/*
+ *  is_ll - returns TRUE if glob contains the tag .ll
+ */
+
+int text_glob::is_ll (void)
+{
+  return is_tag && (strncmp(text_string, "html-tag:.ll ", strlen("html-tag:.ll 
")) == 0);
 }
 
 /*
@@ -722,7 +767,7 @@
 
 int text_glob::is_col (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:.col", 
strlen("html-tag:.col")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.col", 
strlen("html-tag:.col")) == 0);
 }
 
 /*
@@ -731,7 +776,7 @@
 
 int text_glob::is_tab_ts (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0) );
+  return is_tag && (strcmp(text_string, "html-tag:.tab-ts") == 0);
 }
 
 /*
@@ -740,7 +785,7 @@
 
 int text_glob::is_tab_te (void)
 {
-  return( is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0) );
+  return is_tag && (strcmp(text_string, "html-tag:.tab-te") == 0);
 }
 
 /*
@@ -749,7 +794,7 @@
 
 int text_glob::is_ta (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:.ta ", 
strlen("html-tag:.ta ")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:.ta ", strlen("html-tag:.ta 
")) == 0);
 }
 
 /*
@@ -758,7 +803,7 @@
 
 int text_glob::is_tab (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:tab ", 
strlen("html-tag:tab ")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:tab ", strlen("html-tag:tab 
")) == 0);
 }
 
 /*
@@ -767,7 +812,7 @@
 
 int text_glob::is_tab0 (void)
 {
-  return( is_tag && (strncmp(text_string, "html-tag:tab0", 
strlen("html-tag:tab0")) == 0) );
+  return is_tag && (strncmp(text_string, "html-tag:tab0", 
strlen("html-tag:tab0")) == 0);
 }
 
 /*
@@ -789,9 +834,8 @@
 
 int text_glob::is_br (void)
 {
-  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)) );
+  return is_a_tag() && ((strcmp ("html-tag:.br", text_string) == 0) ||
+                       (strncmp("html-tag:.sp", text_string, 11) == 0));
 }
 
 int text_glob::get_arg (void)
@@ -858,10 +902,11 @@
 }
 
 /*
- *  the class and methods used to construct ordered double linked lists.
- *  In a previous implementation we used templates via #include 
"ordered-list.h",
- *  but this does assume that all C++ compilers can handle this feature. 
Pragmatically
- *  it is safer to assume this is not the case.
+ *  the class and methods used to construct ordered double linked
+ *  lists.  In a previous implementation we used templates via
+ *  #include "ordered-list.h", but this does assume that all C++
+ *  compilers can handle this feature. Pragmatically it is safer to
+ *  assume this is not the case.
  */
 
 struct element_list {
@@ -977,7 +1022,8 @@
 }
 
 /*
- *  add - adds a datum to the list in the order specified by the region 
position.
+ *  add - adds a datum to the list in the order specified by the
+ *        region position.
  */
 
 void list::add (text_glob *in, int line_number, int min_vertical, int 
min_horizontal, int max_vertical, int max_horizontal)
@@ -986,7 +1032,13 @@
   element_list *t    = new element_list(in, line_number, min_vertical, 
min_horizontal, max_vertical, max_horizontal);
   element_list *last;
 
-  if (head == 0) {
+#if 0
+  fprintf(stderr, "[%s %d,%d,%d,%d] ",
+         in->text_string, min_vertical, min_horizontal, max_vertical, 
max_horizontal);
+  fflush(stderr);
+#endif
+
+  if (head == NULL) {
     head     = t;
     tail     = t;
     ptr      = t;
@@ -995,9 +1047,8 @@
   } else {
     last = tail;
 
-    while ((last != head) && (is_less(t, last))) {
+    while ((last != head) && (is_less(t, last)))
       last = last->left;
-    }
 
     if (is_less(t, last)) {
       t->right          = last;
@@ -1005,9 +1056,8 @@
       t->left           = last->left;
       last->left        = t;
       // now check for a new head
-      if (last == head) {
+      if (last == head)
        head = t;
-      }
     } else {
       // add t beyond last
       t->right          = last->right;
@@ -1015,9 +1065,8 @@
       last->right->left = t;
       last->right       = t;
       // now check for a new tail
-      if (last == tail) {
+      if (last == tail)
        tail = t;
-      }
     }
   }
 }
@@ -1032,22 +1081,20 @@
   element_list *t=ptr->right;
 
   if (head == tail) {
-    head = 0;
-    if (tail != 0) {
+    head = NULL;
+    if (tail != NULL)
       delete tail;
-    }
-    tail = 0;
-    ptr  = 0;
+    
+    tail = NULL;
+    ptr  = NULL;
   } else {
-    if (head == ptr) {
+    if (head == ptr)
       head = head->right;
-    }
-    if (tail == ptr) {
+    if (tail == ptr)
       tail = tail->left;
-    }
     ptr->left->right = ptr->right;
     ptr->right->left = ptr->left;
-    ptr=t;
+    ptr = t;
   }
 }
 
@@ -1075,7 +1122,7 @@
 
 int list::is_empty (void)
 {
-  return( head == 0 );
+  return head == NULL;
 }
 
 /*
@@ -1084,7 +1131,7 @@
 
 int list::is_equal_to_tail (void)
 {
-  return( ptr == tail );
+  return ptr == tail;
 }
 
 /*
@@ -1093,7 +1140,7 @@
 
 int list::is_equal_to_head (void)
 {
-  return( ptr == head );
+  return ptr == head;
 }
 
 /*
@@ -1120,7 +1167,7 @@
 
 text_glob* list::get_data (void)
 {
-  return( ptr->datum );
+  return ptr->datum;
 }
 
 /*
@@ -1131,11 +1178,10 @@
 text_glob* list::move_right_get_data (void)
 {
   ptr = ptr->right;
-  if (ptr == head) {
-    return( 0 );
-  } else {
-    return( ptr->datum );
-  }
+  if (ptr == head)
+    return NULL;
+  else
+    return ptr->datum;
 }
 
 /*
@@ -1146,11 +1192,10 @@
 text_glob* list::move_left_get_data (void)
 {
   ptr = ptr->left;
-  if (ptr == tail) {
-    return( 0 );
-  } else {
-    return( ptr->datum );
-  }
+  if (ptr == tail)
+    return NULL;
+  else
+    return ptr->datum;
 }
 
 /*
@@ -1162,7 +1207,7 @@
   if (is_empty())
     fatal("list must not be empty if we are inserting data");
   else {
-    if (ptr == 0)
+    if (ptr == NULL)
       ptr = head;
     
     element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, 
ptr->maxv, ptr->maxh);
@@ -1205,7 +1250,8 @@
   void                        add_and_encode  (style *s, const string &str,
                                               int line_number,
                                               int min_vertical, int 
min_horizontal,
-                                              int max_vertical, int 
max_horizontal);
+                                              int max_vertical, int 
max_horizontal,
+                                              int is_tag);
   void                        add_line        (style *s,
                                               int line_number,
                                               int x1, int y1, int x2, int y2,
@@ -1327,7 +1373,8 @@
 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)
+                          int max_vertical, int max_horizontal,
+                          int is_tag)
 {
   string html_string;
   char *html_glyph;
@@ -1366,9 +1413,18 @@
   }
   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);
+    if (is_tag)
+      g->text_glob_tag(s, buffer.add_string(html_string),
+                      html_string.length(),
+                      min_vertical, min_horizontal,
+                      max_vertical, max_horizontal);
+    else
+      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);
   }
 }
 
@@ -1532,6 +1588,337 @@
   }
 }
 
+struct assert_pos {
+  assert_pos *next;
+  const char *val;
+  const char *id;
+};
+
+class assert_state {
+public:
+        assert_state ();
+        ~assert_state ();
+
+  void  addx (const char *c, const char *i, const char *v,
+             const char *f, const char *l);
+  void  addy (const char *c, const char *i, const char *v,
+             const char *f, const char *l);
+  void  build(const char *c, const char *v,
+             const char *f, const char *l);
+  void  check_br (int br);
+  void  check_ce (int ce);
+  void  check_fi (int fi);
+  void  check_sp (int sp);
+  void  reset    (void);
+
+private:
+  int check_br_flag;
+  int check_ce_flag;
+  int check_fi_flag;
+  int check_sp_flag;
+  const char *val_br;
+  const char *val_ce;
+  const char *val_fi;
+  const char *val_sp;
+  const char *file_br;
+  const char *file_ce;
+  const char *file_fi;
+  const char *file_sp;
+  const char *line_br;
+  const char *line_ce;
+  const char *line_fi;
+  const char *line_sp;
+
+  assert_pos *xhead;
+  assert_pos *yhead;
+
+  void add (assert_pos **h,
+           const char *c, const char *i, const char *v,
+           const char *f, const char *l);
+  void compare(assert_pos *t,
+              const char *v, const char *f, const char *l);
+  void close (const char *c);
+  void set (const char *c, const char *v,
+           const char *f, const char *l);
+  void check_value (const char *s, int v, const char *name,
+                   const char *f, const char *l, int *flag);
+  int check_value_error (int c, int v, const char *s,
+                        const char *name,
+                        const char *f, const char *l, int flag);
+};
+
+assert_state::assert_state ()
+{
+  reset();
+  val_br   = NULL;
+  val_ce   = NULL;
+  val_fi   = NULL;
+  val_sp   = NULL;
+  file_br  = NULL;
+  file_ce  = NULL;
+  file_fi  = NULL;
+  file_sp  = NULL;
+  line_br  = NULL;
+  line_ce  = NULL;
+  line_fi  = NULL;
+  line_sp  = NULL;
+  xhead    = NULL;
+  yhead    = NULL;
+}
+
+assert_state::~assert_state ()
+{
+  assert_pos *t;
+
+  while (xhead != NULL) {
+    t = xhead;
+    xhead = xhead->next;
+    free((void *)t->val);
+    free((void *)t->id);
+    free(t);
+  }
+  while (yhead != NULL) {
+    t = yhead;
+    yhead = yhead->next;
+    free((void *)t->val);
+    free((void *)t->id);
+    free(t);
+  }
+}
+
+void assert_state::reset (void)
+{
+  check_br_flag = 0;
+  check_ce_flag = 0;
+  check_fi_flag = 0;
+  check_sp_flag = 0;
+}
+
+void assert_state::add (assert_pos **h,
+                       const char *c, const char *i, const char *v,
+                       const char *f, const char *l)
+{
+  assert_pos *t = *h;
+
+  while (t != NULL) {
+    if (strcmp(t->id, i) == 0)
+      break;
+    t = t->next;
+  }
+  if (t != NULL && v != NULL && (v[0] != '='))
+    compare(t, v, f, l);
+  else {
+    if (t == NULL) {
+      t = (assert_pos *)malloc(sizeof(struct assert_pos));
+      t->next = *h;
+      (*h) = t;
+    }
+    if (v == NULL || v[0] != '=') {
+      if (f == NULL)
+       f = "stdin";
+      if (l == NULL)
+       l = "<none>";
+      if (v == NULL)
+       v = "no value at all";
+      fprintf(stderr, "%s:%s:error in assert format of id=%s expecting value 
to be prefixed with an `=' got %s\n",
+             f, l, i, v);
+    }
+    t->id = i;
+    t->val = v;
+    free((void *)c);
+    free((void *)f);
+    free((void *)l);
+  }
+}
+
+void assert_state::addx (const char *c, const char *i, const char *v,
+                        const char *f, const char *l)
+{
+  add(&xhead, c, i, v, f, l);
+}
+
+void assert_state::addy (const char *c, const char *i, const char *v,
+                        const char *f, const char *l)
+{
+  add(&yhead, c, i, v, f, l);
+}
+
+void assert_state::compare(assert_pos *t,
+                          const char *v, const char *f, const char *l)
+{
+  const char *s=t->val;
+
+  while ((*v) == '=')
+    v++;
+  while ((*s) == '=')
+    s++;
+  
+  if (strcmp(v, s) != 0) {
+    if (f == NULL)
+      f = "stdin";
+    if (l == NULL)
+      l = "<none>";
+    fprintf(stderr, "%s:%s: grohtml assertion failed at id%s expecting %s and 
was given %s\n",
+           f, l, t->id, s, v);
+  }
+}
+
+void assert_state::close (const char *c)
+{
+  if (strcmp(c, "sp") == 0)
+    check_sp_flag = 0;
+  else if (strcmp(c, "br") == 0)
+    check_br_flag = 0;
+  else if (strcmp(c, "fi") == 0)
+    check_fi_flag = 0;
+  else if (strcmp(c, "nf") == 0)
+    check_fi_flag = 0;
+  else if (strcmp(c, "ce") == 0)
+    check_ce_flag = 0;
+  else
+    fprintf(stderr, "internal error: unrecognised tag in grohtml (%s)\n", c);
+}
+
+const char *replace_negate_str (const char *before, char *after)
+{
+  if (before != NULL)
+    free((void *)before);
+
+  if (strlen(after) > 0) {
+    int d = atoi(after);
+
+    if (d < 0 || d > 1) {
+      fprintf(stderr, "expecting nf/fi value to be 0 or 1 not %d\n", d);
+      d = 0;
+    }
+    if (d == 0)
+      after[0] = '1';
+    else
+      after[0] = '0';
+    after[1] = (char)0;
+  }
+  return after;
+}
+
+const char *replace_str (const char *before, const char *after)
+{
+  if (before != NULL)
+    free((void *)before);
+  return after;
+}
+
+void assert_state::set (const char *c, const char *v,
+                       const char *f, const char *l)
+{
+  if (l == NULL)
+    l = "<none>";
+  if (f == NULL)
+    f = "stdin";
+
+  // fprintf(stderr, "%s:%s:setting %s to %s\n", f, l, c, v);
+  if (strcmp(c, "sp") == 0) {
+    check_sp_flag = 1;
+    val_sp = replace_str(val_sp, strdup(v));
+    file_sp = replace_str(file_sp, strdup(f));
+    line_sp = replace_str(line_sp, strdup(l));
+  } else if (strcmp(c, "br") == 0) {
+    check_br_flag = 1;
+    val_br = replace_str(val_br, strdup(v));
+    file_br = replace_str(file_br, strdup(f));
+    line_br = replace_str(line_br, strdup(l));
+  } else if (strcmp(c, "fi") == 0) {
+    check_fi_flag = 1;
+    val_fi = replace_str(val_fi, strdup(v));
+    file_fi = replace_str(file_fi, strdup(f));
+    line_fi = replace_str(line_fi, strdup(l));
+  } else if (strcmp(c, "nf") == 0) {
+    check_fi_flag = 1;
+    val_fi = replace_negate_str(val_fi, strdup(v));
+    file_fi = replace_str(file_fi, strdup(f));
+    line_fi = replace_str(line_fi, strdup(l));
+  } else if (strcmp(c, "ce") == 0) {
+    check_ce_flag = 1;
+    val_ce = replace_str(val_ce, strdup(v));
+    file_ce = replace_str(file_ce, strdup(f));
+    line_ce = replace_str(line_ce, strdup(l));
+  }
+}
+
+/*
+ *  build - builds the troff state assertion.
+ *          see tmac/www.tmac for cmd examples.
+ */
+
+void assert_state::build (const char *c, const char *v,
+                         const char *f, const char *l)
+{
+  if (c[0] == '{')
+    set(&c[1], v, f, l);
+  if (c[0] == '}')
+    close(&c[1]);
+}
+
+int assert_state::check_value_error (int c, int v, const char *s,
+                                    const char *name,
+                                    const char *f, const char *l, int flag)
+{
+  if (! c) {
+    if (f == NULL)
+      f = "stdin";
+    if (l == NULL)
+      l = "<none>";
+    fprintf(stderr, "%s:%s:grohtml (troff state) assertion failed, expected %s 
to be %s but found it to contain %d\n",
+           f, l, name, s, v);
+    return 0;
+  }
+  return flag;
+}
+
+void assert_state::check_value (const char *s, int v, const char *name,
+                               const char *f, const char *l, int *flag)
+{
+  if (strncmp(s, "<=", 2) == 0)
+    *flag = check_value_error(v <= atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, ">=", 2) == 0)
+    *flag = check_value_error(v >= atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, "==", 2) == 0)
+    *flag = check_value_error(v == atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, "!=", 2) == 0)
+    *flag = check_value_error(v != atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, "<", 1) == 0)
+    *flag = check_value_error(v < atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, ">", 1) == 0)
+    *flag = check_value_error(v > atoi(&s[2]), v, s, name, f, l, *flag);
+  else if (strncmp(s, "=", 1) == 0)
+    *flag = check_value_error(v == atoi(&s[1]), v, s, name, f, l, *flag);
+  else
+    *flag = check_value_error(v == atoi(s), v, s, name, f, l, *flag);
+}
+
+void assert_state::check_sp (int sp)
+{
+  if (check_sp_flag)
+    check_value(val_sp, sp, "sp", file_sp, line_sp, &check_sp_flag);
+}
+
+void assert_state::check_fi (int fi)
+{
+  if (check_fi_flag)
+    check_value(val_fi, fi, "fi", file_fi, line_fi, &check_fi_flag);
+}
+
+void assert_state::check_br (int br)
+{
+  if (check_br_flag)
+    check_value(val_br, br, "br", file_br, line_br, &check_br_flag);
+}
+
+void assert_state::check_ce (int ce)
+{
+  if (check_ce_flag)
+    check_value(val_ce, ce, "ce", file_ce, line_ce, &check_ce_flag);
+}
+
 class html_printer : public printer {
   files                file_list;
   simple_output        html;
@@ -1575,12 +1962,24 @@
   int                  max_linelength;
   int                  linelength;
   int                  pageoffset;
-  int                  indentation;
-  int                  prev_indent;
+  int                  troff_indent;
+  int                  device_indent;
+  int                  temp_indent;
   int                  pointsize;
   int                  vertical_spacing;
   int                  line_number;
   color               *background;
+  int                  seen_indent;
+  int                  next_indent;
+  int                  seen_pageoffset;
+  int                  next_pageoffset;
+  int                  seen_linelength;
+  int                  next_linelength;
+  int                  seen_center;
+  int                  next_center;
+  int                  seen_space;
+  int                  seen_break;
+  assert_state         as;
 
   void  flush_sbuf                    ();
   void  set_style                     (const style &);
@@ -1610,11 +2009,13 @@
   void  start_size                    (int from, int to);
   void  do_font                       (text_glob *g);
   void  do_center                     (char *arg);
+  void  do_check_center               (void);
   void  do_break                      (void);
+  void  do_space                      (char *arg);
   void  do_eol                        (void);
   void  do_eol_ce                     (void);
   void  do_title                      (void);
-  void  do_fill                       (int on);
+  void  do_fill                       (char *arg);
   void  do_heading                    (char *arg);
   void  write_header                  (void);
   void  determine_header_level        (int level);
@@ -1632,6 +2033,7 @@
   void  do_links                      (void);
   void  do_flush                      (void);
   void  do_job_name                   (char *name);
+  void  do_head                       (char *name);
   void  insert_split_file             (void);
   int   is_in_middle                  (int left, int right);
   void  do_sup_or_sub                 (text_glob *g);
@@ -1667,6 +2069,11 @@
   void write_navigation               (const string &top, const string &prev,
                                       const string &next, const string 
&current);
   void emit_link                      (const string &to, const char *name);
+  int  get_troff_indent               (void);
+  void restore_troff_indent           (void);
+  void handle_assertion               (int minv, int minh, int maxv, int maxh, 
const char *s);
+  void handle_state_assertion         (text_glob *g);
+  void do_end_para                    (text_glob *g);
   // ADD HERE
 
 public:
@@ -1674,6 +2081,8 @@
   ~html_printer         ();
   void set_char         (int i, font *f, const environment *env, int w, const 
char *name);
   void set_numbered_char(int num, const environment *env, int *widthp);
+  int set_char_and_width(const char *nm, const environment *env,
+                        int *widthp, font **f);
   void draw             (int code, int *p, int np, const environment *env);
   void begin_page       (int);
   void end_page         (int);
@@ -1744,6 +2153,24 @@
 }
 
 /*
+ *  restore_troff_indent - is called when we have temporarily shutdown
+ *                         indentation (typically done when we have
+ *                         centered an image).
+ */
+
+void html_printer::restore_troff_indent (void)
+{
+  troff_indent = next_indent;
+  if (troff_indent > 0) {
+    /*
+     *  force device indentation
+     */
+    device_indent = 0;
+    do_indent(get_troff_indent(), pageoffset, linelength);
+  }
+}
+
+/*
  *  emit_raw - writes the raw html information directly to the device.
  */
 
@@ -1755,16 +2182,17 @@
     current_paragraph->do_emittext(g->text_string, g->text_length);
   } else {
     current_paragraph->done_para();
+    shutdown_table();
     switch (next_tag) {
 
     case CENTERED:
       current_paragraph->do_para("align=center");
       break;
     case LEFT:
-      current_paragraph->do_para(&html, "align=left", indentation, pageoffset, 
linelength);
+      current_paragraph->do_para(&html, "align=left", get_troff_indent(), 
pageoffset, linelength);
       break;
     case RIGHT:
-      current_paragraph->do_para(&html, "align=right", indentation, 
pageoffset, linelength);
+      current_paragraph->do_para(&html, "align=right", get_troff_indent(), 
pageoffset, linelength);
       break;
     default:
       fatal("unknown enumeration");
@@ -1773,14 +2201,7 @@
     current_paragraph->done_para();
     next_tag        = INLINE;
     supress_sub_sup = TRUE;
-    if (indentation > 0) {
-      /*
-       *  restore indentation
-       */
-      int newin = indentation;
-      indentation = 0;
-      do_indent(newin, pageoffset, linelength);
-    }
+    restore_troff_indent();
   }
 }
 
@@ -1790,18 +2211,8 @@
 
 void html_printer::do_center (char *arg)
 {
-  int n = atoi(arg);
-  current_paragraph->do_break();
-
-  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();
-  }
+  next_center = atoi(arg);
+  seen_center = TRUE;
 }
 
 /*
@@ -1912,7 +2323,6 @@
 {
   text_glob    *t;
   int           removed_from_head;
-  int           eol_ce = 0;
 
   if (page_number == 1) {
     int found_title_start  = FALSE;
@@ -1934,24 +2344,15 @@
          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_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()) {
+       } else if (t->is_eo_tl()) {
          /* 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;
+         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 (found_title_start) {
          title.text += " " + string(t->text_string, t->text_length);
          page_contents->glyphs.sub_move_right();         /* move onto next 
word */
@@ -1967,7 +2368,6 @@
        }
       } while ((! page_contents->glyphs.is_equal_to_head()) || 
(removed_from_head));
     }
-    outstanding_eol(eol_ce);
   }
 }
 
@@ -2001,7 +2401,7 @@
 
       // lastly we generate a tag
 
-      html.nl().put_string("<a name=\"");
+      html.nl().nl().put_string("<a name=\"");
       if (simple_anchors) {
        string buffer(ANCHOR_TEMPLATE);
 
@@ -2057,7 +2457,7 @@
                               header.no_of_headings, header.no_of_headings,
                               header.no_of_headings, header.no_of_headings);
 
-    current_paragraph->do_para(&html, "", indentation, pageoffset, linelength);
+    current_paragraph->do_para(&html, "", get_troff_indent(), pageoffset, 
linelength);
   }
 }
 
@@ -2107,9 +2507,16 @@
          l = g;
          header.header_buffer += img;
        }
-      } else if (! (g->is_a_line() || g->is_a_tag())) {
+      }
+      else if (g->is_in() || g->is_ti() || g->is_po() || g->is_ce() || 
g->is_ll())
+       troff_tag(g);
+      else if (g->is_fi())
+       fill_on = 1;
+      else if (g->is_nf())
+       fill_on = 0;
+      else if (! (g->is_a_line() || g->is_a_tag())) {
        /*
-        *  we ignore tag commands when constructing a heading
+        *  we ignore the other tag commands when constructing a heading
         */
        if (l != 0)
          header.header_buffer += " ";
@@ -2120,7 +2527,7 @@
       page_contents->glyphs.move_right();
       g = page_contents->glyphs.get_data();
     } while ((! page_contents->glyphs.is_equal_to_head()) &&
-            (! g->is_br()));
+            (! g->is_eo_h()));
   }
 
   determine_header_level(level);
@@ -2170,8 +2577,8 @@
   if (max_linelength == -1)
     max_linelength = atoi(arg);
 
-  if (fill_on)
-    do_indent(indentation, pageoffset, atoi(arg));
+  next_linelength = atoi(arg);
+  seen_linelength = TRUE;
 }
 
 /*
@@ -2180,8 +2587,20 @@
 
 void html_printer::do_pageoffset (char *arg)
 {
-  if (fill_on)
-    do_indent(indentation, atoi(arg), linelength);
+  next_pageoffset = atoi(arg);
+  seen_pageoffset = TRUE;
+}
+
+/*
+ *  get_troff_indent - returns the indent value.
+ */
+
+int html_printer::get_troff_indent (void)
+{
+  if (end_tempindent > 0)
+    return temp_indent;
+  else
+    return troff_indent;
 }
 
 /*
@@ -2190,8 +2609,8 @@
 
 void html_printer::do_indentation (char *arg)
 {
-  if (fill_on)
-    do_indent(atoi(arg), pageoffset, linelength);
+  next_indent = atoi(arg);
+  seen_indent = TRUE;
 }
 
 /*
@@ -2201,9 +2620,12 @@
 void html_printer::do_tempindent (char *arg)
 {
   if (fill_on) {
-    end_tempindent = 1;
-    prev_indent    = indentation;
-    do_indent(atoi(arg), pageoffset, linelength);
+    /*
+     *  we set the end_tempindent to 2 as the first .br
+     *  activates the .ti and the second terminates it.
+     */
+    end_tempindent = 2;
+    temp_indent = atoi(arg);
   }
 }
 
@@ -2229,17 +2651,18 @@
 
 void html_printer::do_indent (int in, int pageoff, int linelen)
 {
-  if ((indentation != -1) &&
-      (pageoffset+indentation != in+pageoff)) {
+  if ((device_indent != -1) &&
+      (pageoffset+device_indent != in+pageoff)) {
     
     current_paragraph->done_para();
       
-    indentation = in;
+    device_indent = in;
     pageoffset  = pageoff;
     if (linelen <= max_linelength)
       linelength  = linelen;
 
-    current_paragraph->do_para(&html, "", indentation, pageoffset, 
max_linelength);
+    current_paragraph->do_para(&html, "", device_indent,
+                              pageoffset, max_linelength);
   }
 }
 
@@ -2258,24 +2681,56 @@
 
 void html_printer::do_pointsize (char *arg)
 {
-  pointsize = atoi(arg);
+  /*
+   *  firstly check to see whether this point size is really associated with a 
.tl tag
+   */
+
+  if (! page_contents->glyphs.is_empty()) {
+    text_glob *g = page_contents->glyphs.get_data();
+    text_glob *t = page_contents->glyphs.get_data();
+
+    while (t->is_a_tag() && (! page_contents->glyphs.is_equal_to_head())) {
+      if (t->is_tl()) {
+       /*
+        *  found title therefore ignore this .ps tag
+        */
+       while (t != g) {
+         page_contents->glyphs.move_left();
+         t = page_contents->glyphs.get_data();
+       }
+       return;
+      }
+      page_contents->glyphs.move_right();
+      t = page_contents->glyphs.get_data();
+    }
+    /*
+     *  move back to original position
+     */
+    while (t != g) {
+      page_contents->glyphs.move_left();
+      t = page_contents->glyphs.get_data();
+    }
+    /*
+     *  collect legal pointsize
+     */
+    pointsize = atoi(arg);
+  }
 }
 
 /*
  *  do_fill - records whether troff has requested that text be filled.
  */
 
-void html_printer::do_fill (int on)
+void html_printer::do_fill (char *arg)
 {
-  current_paragraph->do_break();
-  output_hpos = indentation+pageoffset;
+  int on = atoi(arg);
+      
+  output_hpos = get_troff_indent()+pageoffset;
   supress_sub_sup = TRUE;
 
   if (fill_on != on) {
     if (on)
       current_paragraph->do_para("");
-    else
-      current_paragraph->do_pre();
     fill_on = on;
   }
 }
@@ -2292,7 +2747,49 @@
       current_paragraph->do_break();
     }
   }
-  output_hpos = indentation+pageoffset;
+  output_hpos = get_troff_indent()+pageoffset;
+}
+
+/*
+ *  do_check_center - checks to see whether we have seen a `.ce' tag
+ *                    during the previous line.
+ */
+
+void html_printer::do_check_center(void)
+{
+  if (seen_center) {
+    seen_center = FALSE;
+    if (next_center > 0) {
+      if (end_center == 0) {
+       current_paragraph->done_para();
+       supress_sub_sup = TRUE;
+       current_paragraph->do_para("align=center");
+      } else
+       if (strcmp("align=center",
+                  current_paragraph->get_alignment()) != 0) {
+         /*
+          *  different alignment, so shutdown paragraph and open
+          *  a new one.
+          */
+         current_paragraph->done_para();
+         supress_sub_sup = TRUE;
+         current_paragraph->do_para("align=center");
+       } else
+         /*
+          *  same alignment, if we have emitted text then issue a break.
+          */
+         if (current_paragraph->emitted_text())
+           current_paragraph->do_break();
+    } else
+      /*
+       *  next_center == 0
+       */
+      if (end_center > 0) {
+       current_paragraph->done_para();
+       supress_sub_sup = TRUE;
+      }
+    end_center = next_center;
+  }
 }
 
 /*
@@ -2374,19 +2871,60 @@
 }
 
 /*
+ *  do_head - adds a string to head_info which is to be included into
+ *            the <head> </head> section of the html document.
+ */
+
+void html_printer::do_head (char *name)
+{
+  head_info += string(name);
+  head_info += '\n';
+}
+
+/*
  *  do_break - handles the ".br" request and also
- *             undoes an outstanding ".ti" command.
+ *             undoes an outstanding ".ti" command
+ *             and calls indent if the indentation
+ *             related registers have changed.
  */
 
 void html_printer::do_break (void)
 {
+  int seen_temp_indent = FALSE;
+
   current_paragraph->do_break();
   if (end_tempindent > 0) {
     end_tempindent--;
-    if (end_tempindent == 0)
-      do_indent(prev_indent, pageoffset, linelength);
+    if (end_tempindent > 0)
+      seen_temp_indent = TRUE;
+  }
+  if (seen_indent || seen_pageoffset || seen_linelength || seen_temp_indent) {
+    if (seen_indent && (! seen_temp_indent))
+      troff_indent = next_indent;
+    if (! seen_pageoffset)
+      next_pageoffset = pageoffset;
+    if (! seen_linelength)
+      next_linelength = linelength;
+    do_indent(get_troff_indent(), next_pageoffset, next_linelength);
+  }
+  seen_indent     = seen_temp_indent;
+  seen_linelength = FALSE;
+  seen_pageoffset = FALSE;
+  do_check_center();
+  output_hpos     = get_troff_indent()+pageoffset;
+  supress_sub_sup = TRUE;
+}
+
+void html_printer::do_space (char *arg)
+{
+  int n = atoi(arg);
+
+  seen_space = atoi(arg);
+  as.check_sp(seen_space);
+  while (n>0) {
+    current_paragraph->do_space();
+    n--;
   }
-  output_hpos = indentation+pageoffset;
   supress_sub_sup = TRUE;
 }
 
@@ -2401,8 +2939,11 @@
   if (t != NULL) {
     current_paragraph->done_pre();
     current_paragraph->done_para();
+    current_paragraph->remove_para_space();
 
+#if defined(DEBUG_TABLES)
     html.simple_comment("TABS");
+#endif
 
     t->set_linelength(max_linelength);
     t->add_indent(pageoffset);
@@ -2424,15 +2965,7 @@
   }
 
   table = NULL;
-
-  if (indentation > 0) {
-    /*
-     *  restore indentation
-     */
-    int newin = indentation;
-    indentation = 0;
-    do_indent(newin, pageoffset, linelength);
-  }
+  restore_troff_indent();
 }
 
 /*
@@ -2445,7 +2978,7 @@
     while (isspace(*s))
       s++;
     s++;
-    int col = table->find_column(atoi(s) + pageoffset + indentation);
+    int col = table->find_column(atoi(s) + pageoffset + get_troff_indent());
     if (col > 0) {
       current_paragraph->done_para();
       table->emit_col(col);
@@ -2460,7 +2993,7 @@
 void html_printer::do_tab0 (void)
 {
   if (table) {
-    int col = table->find_column(pageoffset+indentation);
+    int col = table->find_column(pageoffset+get_troff_indent());
     if (col > 0) {
       current_paragraph->done_para();
       table->emit_col(col);
@@ -2481,7 +3014,8 @@
 }
 
 /*
- *  troff_tag - processes the troff tag and manipulates the troff state 
machine.
+ *  troff_tag - processes the troff tag and manipulates the troff
+ *              state machine.
  */
 
 void html_printer::troff_tag (text_glob *g)
@@ -2491,17 +3025,18 @@
    */
   char *t=(char *)g->text_string+9;
 
-  if (g->is_eol()) {
+  if (strncmp(g->text_string, "html</p>:", 9) == 0) {
+    do_end_para(g);
+  } else if (g->is_eol()) {
     do_eol();
   } else if (g->is_eol_ce()) {
     do_eol_ce();
   } else if (strncmp(t, ".sp", 3) == 0) {
-    if (g->get_arg() > 0)
-      current_paragraph->do_space();
-    else
-      current_paragraph->do_break();
-    supress_sub_sup = TRUE;
+    char *a = (char *)t+3;
+    do_space(a);
   } else if (strncmp(t, ".br", 3) == 0) {
+    seen_break = 1;
+    as.check_br(1);
     do_break();
   } else if (strcmp(t, ".centered-image") == 0) {
     do_centered_image();
@@ -2516,7 +3051,7 @@
     char *a = (char *)t+3;
     supress_sub_sup = TRUE;
     do_center(a);
-  } else if (strncmp(t, ".tl", 3) == 0) {
+  } else if (g->is_tl()) {
     supress_sub_sup = TRUE;
     title.with_h1 = TRUE;
     do_title();
@@ -2525,9 +3060,8 @@
     title.with_h1 = FALSE;
     do_title();
   } else if (strncmp(t, ".fi", 3) == 0) {
-    do_fill(TRUE);
-  } else if (strncmp(t, ".nf", 3) == 0) {
-    do_fill(FALSE);
+    char *a = (char *)t+3;
+    do_fill(a);
   } else if ((strncmp(t, ".SH", 3) == 0) || (strncmp(t, ".NH", 3) == 0)) {
     char *a = (char *)t+3;
     do_heading(a);
@@ -2554,6 +3088,9 @@
   } else if (strncmp(t, ".job-name", 9) == 0) {
     char *a = (char *)t+9;
     do_job_name(a);
+  } else if (strncmp(t, ".head", 5) == 0) {
+    char *a = (char *)t+5;
+    do_head(a);
   } else if (strcmp(t, ".no-auto-rule") == 0) {
     auto_rule = FALSE;
   } else if (strcmp(t, ".tab-ts") == 0) {
@@ -2592,17 +3129,34 @@
     page_contents->glyphs.start_from_head();
     do {
       g = page_contents->glyphs.get_data();
+      if (strcmp(g->text_string, "Here") == 0)
+       stop();
+
+#if 0
+      fprintf(stderr, "[%s:%d:%d:%d:%d]",
+             g->text_string, g->minv, g->minh, g->maxv, g->maxh) ;
+      fflush(stderr);
+#endif
+
+      handle_state_assertion(g);
 
       if (strcmp(g->text_string, "XXXXXXX") == 0)
        stop();
 
-      if (g->is_a_tag()) {
+      if (g->is_a_tag())
        troff_tag(g);
-      } else if (g->is_a_line()) {
+      else if (g->is_a_line())
        emit_line(g);
-      } else {
+      else {
+       as.check_sp(seen_space);
+       as.check_br(seen_break);
+       seen_break = 0;
+       seen_space = 0;
        emit_html(g);
       }
+
+      as.check_fi(fill_on);
+      as.check_ce(end_center);
       /*
        *  after processing the title (and removing it) the glyph list might be 
empty
        */
@@ -2621,11 +3175,16 @@
 int html_printer::calc_nf (text_glob *g, int nf)
 {
   if (g != NULL) {
-    if (g->is_fi())
+    if (g->is_fi()) {
+      as.check_fi(TRUE);
       return FALSE;
-    if (g->is_nf())
+    }
+    if (g->is_nf()) {
+      as.check_fi(FALSE);
       return TRUE;
+    }
   }
+  as.check_fi(! nf);
   return nf;
 }
 
@@ -2636,16 +3195,15 @@
 void html_printer::calc_po_in (text_glob *g, int nf)
 {
   if (g->is_in())
-    indentation = g->get_arg();
+    troff_indent = 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;
+    temp_indent = g->get_arg();
+    end_tempindent = 2;
+  } else if (g->is_br() || (nf && g->is_eol())) {
+    if (end_tempindent > 0)
+      end_tempindent--;
   }
 }
 
@@ -2656,13 +3214,15 @@
 
 int html_printer::next_horiz_pos (text_glob *g, int nf)
 {
-  int next     = -1;
+  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)
+      if (g == NULL) {
        page_contents->glyphs.start_from_head();
+       as.reset();
+      }
       else {
        next = g->minh;
        page_contents->glyphs.move_left();
@@ -2760,10 +3320,11 @@
 
   if (! page_contents->glyphs.is_empty()) {
     page_contents->glyphs.start_from_head();
+    as.reset();
     line_start = TRUE;
     do {
       g = page_contents->glyphs.get_data();
-      
+      handle_state_assertion(g);
       nf = calc_nf(g, nf);
 
       if (line_start) {
@@ -2773,7 +3334,8 @@
        }
       }
 
-      line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && 
g->is_eol());
+      // line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && 
g->is_eol());
+      line_start = g->is_br() || (nf && g->is_eol());
       page_contents->glyphs.move_right();
     } while (! page_contents->glyphs.is_equal_to_head());
   }
@@ -2789,10 +3351,11 @@
 
   if (! page_contents->glyphs.is_empty()) {
     page_contents->glyphs.start_from_head();
+    as.reset();
     start_of_line = page_contents->glyphs.get_data();
     do {
       g = page_contents->glyphs.get_data();
-      
+      handle_state_assertion(g);
       nf = calc_nf(g, nf);
 
       if (g->is_tab())
@@ -2805,6 +3368,7 @@
        do {
          page_contents->glyphs.move_right();
          g = page_contents->glyphs.get_data();
+         handle_state_assertion(g);
          nf = calc_nf(g, nf);
          if (page_contents->glyphs.is_equal_to_head()) {
            if (seen_tab && !seen_col)
@@ -2872,7 +3436,8 @@
 }
 
 /*
- *  lookahead_for_tables - checks for .col tags and inserts table start/end 
tags
+ *  lookahead_for_tables - checks for .col tags and inserts table
+ *                         start/end tags
  */
 
 void html_printer::lookahead_for_tables (void)
@@ -2900,7 +3465,26 @@
   page_contents->dump_page();
   if (! page_contents->glyphs.is_empty()) {
     page_contents->glyphs.start_from_head();
+    as.reset();
     g = page_contents->glyphs.get_data();
+    if (g->is_br()) {
+      g = page_contents->glyphs.move_right_get_data();
+      handle_state_assertion(g);
+      if (page_contents->glyphs.is_equal_to_head()) {
+       if (tbl != NULL)
+         delete tbl;
+       return;
+      }
+
+      start_of_line = g;
+      seen_text = FALSE;
+      ncol = 0;
+      left = next_horiz_pos(g, nf);
+      if (found_col)
+       last = g;
+      found_col = FALSE;
+    }
+    
     do {
 #if defined(DEBUG_TABLES)
       fprintf(stderr, " [") ;
@@ -2936,10 +3520,10 @@
        colmin = g->get_tab_args(&align);
        align = 'L'; // for now as 'C' and 'R' are broken
        ncol = tbl->find_tab_column(colmin);
-       colmin += pageoffset + indentation;
+       colmin += pageoffset + get_troff_indent();
        colmax = tbl->get_tab_pos(ncol+1);
        if (colmax > 0)
-         colmax += pageoffset + indentation;
+         colmax += pageoffset + get_troff_indent();
       } else if (g->is_tab0()) {
        if (type_of_col == col_tag && start_of_table != NULL) {
          page_contents->glyphs.move_left();
@@ -2956,7 +3540,7 @@
        type_of_col = tab0_tag;
        ncol = 1;
        colmin = 0;
-       colmax = tbl->get_tab_pos(2) + pageoffset + indentation;
+       colmax = tbl->get_tab_pos(2) + pageoffset + get_troff_indent();
       } else if (! g->is_a_tag())
        update_min_max(type_of_col, &colmin, &colmax, g);
 
@@ -2975,6 +3559,10 @@
        last = NULL;
       } else if (g->is_ta()) {
        tab_defs = g->text_string;
+
+       if (type_of_col == col_tag)
+         tbl->tab_stops->check_init(tab_defs);
+
        if (!tbl->tab_stops->compatible(tab_defs)) {
          if (start_of_table != NULL) {
            add_table_end("*** TABS ***");
@@ -3008,16 +3596,19 @@
        *  move onto next glob, check whether we are starting a new line
        */
       g = page_contents->glyphs.move_right_get_data();
+      handle_state_assertion(g);
 
       if (g == NULL) {
        if (found_col) {
          page_contents->glyphs.start_from_head();
+         as.reset();
          last = g;
          found_col = FALSE;
        }
       } else if (g->is_br() || (nf && g->is_eol())) {
        do {
          g = page_contents->glyphs.move_right_get_data();
+         handle_state_assertion(g);
          nf = calc_nf(g, nf);
        } while ((g != NULL) && (g->is_br() || (nf && g->is_eol())));
        start_of_line = g;
@@ -3051,8 +3642,8 @@
 
   // and reset the registers
   pageoffset = old_pageoffset;
-  indentation = 0;
-  prev_indent = 0;
+  troff_indent = 0;
+  temp_indent = 0;
   end_tempindent = 0;
 }
 
@@ -3329,6 +3920,22 @@
 }
 
 /*
+ *  do_end_para - writes out the html text after shutting down the
+ *                current paragraph.
+ */
+
+void html_printer::do_end_para (text_glob *g)
+{
+  do_font(g);
+  current_paragraph->done_para();
+  html.put_string(g->text_string+9);
+  output_vpos     = g->minv;
+  output_hpos     = g->maxh;
+  output_vpos_max = g->maxv;
+  supress_sub_sup = FALSE;
+}
+
+/*
  *  emit_html - write out the html text
  */
 
@@ -3352,6 +3959,7 @@
   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)
@@ -3462,11 +4070,22 @@
   max_linelength(-1),
   linelength(0),
   pageoffset(0),
-  indentation(0),
-  prev_indent(0),
-  pointsize(0),
+  troff_indent(0),
+  device_indent(0),
+  temp_indent(0),
+  pointsize(base_point_size),
   line_number(0),
-  background(default_background)
+  background(default_background),
+  seen_indent(FALSE),
+  next_indent(0),
+  seen_pageoffset(FALSE),
+  next_pageoffset(0),
+  seen_linelength(FALSE),
+  next_linelength(0),
+  seen_center(FALSE),
+  next_center(0),
+  seen_space(0),
+  seen_break(0)
 {
   file_list.add_new_file(xtmpfile());
   html.set_file(file_list.get_file());
@@ -3618,11 +4237,13 @@
 }
 
 /*
- *  set_char - adds a character into the sbuf if it is a continuation with the 
previous
- *             word otherwise flush the current sbuf and add character anew.
+ *  set_char - adds a character into the sbuf if it is a continuation
+ *             with the previous word otherwise flush the current sbuf
+ *             and add character anew.
  */
 
-void html_printer::set_char(int i, font *f, const environment *env, int w, 
const char *name)
+void html_printer::set_char(int i, font *f, const environment *env,
+                           int w, const char *name)
 {
   style sty(f, env->size, env->height, env->slant, env->fontno, *env->col);
   if (sty.slant != 0) {
@@ -3636,6 +4257,8 @@
     return;
   
   flush_sbuf();
+  if (sbuf_style.f == NULL)
+    sbuf_style = sty;
   add_to_sbuf(i, name);
   sbuf_end_hpos = env->hpos + w;
   sbuf_start_hpos = env->hpos;
@@ -3687,6 +4310,38 @@
   set_char(i, f, env, w, 0);
 }
 
+int html_printer::set_char_and_width(const char *nm, const environment *env,
+                                    int *widthp, font **f)
+{
+  int i = font::name_to_index(nm);
+  int fn = env->fontno;
+  if (fn < 0 || fn >= nfonts) {
+    error("bad font position `%1'", fn);
+    return -1;
+  }
+  *f = font_table[fn];
+  if (*f == 0) {
+    error("no font mounted at `%1'", fn);
+    return -1;
+  }
+  if (!(*f)->contains(i)) {
+    if (nm[0] != '\0' && nm[1] == '\0')
+      error("font `%1' does not contain ascii character `%2'",
+           (*f)->get_name(),
+           nm[0]);
+    else
+      error("font `%1' does not contain special character `%2'",
+           (*f)->get_name(),
+           nm);
+    return -1;
+  }
+  int w = (*f)->get_width(i, env->size);
+  w = round_width(w);
+  if (widthp)
+    *widthp = w;
+  return i;
+}
+
 /*
  *  write_title - writes the title to this document
  */
@@ -3739,7 +4394,7 @@
   output_vpos            = -1;
   output_vpos_max        = -1;
   current_paragraph      = new html_text(&html);
-  do_indent(indentation, pageoffset, linelength);
+  do_indent(get_troff_indent(), pageoffset, linelength);
   current_paragraph->do_para("");
 }
 
@@ -3798,32 +4453,34 @@
   if (multiple_files) {
     write_rule();
     fputs("[ ", stdout);
-    if (prev != "" && prev != top) {
+    if ((strcmp(prev.contents(), "") != 0) && prev != top && prev != current) {
       emit_link(prev, "prev");
       need_bar = TRUE;
     }
-    if (next != "" && next != top) {
+    if ((strcmp(next.contents(), "") != 0) && next != top && next != current) {
       if (need_bar)
        fputs(" | ", stdout);
       emit_link(next, "next");
       need_bar = TRUE;
     }
-    if (top != "<standard input>" && top != "" && top != current) {
+    if (top != "<standard input>" && (strcmp(top.contents(), "") != 0) && top 
!= current) {
       if (need_bar)
        fputs(" | ", stdout);
       emit_link(top, "top");
-      fputs(" ]\n", stdout);
     }
+    fputs(" ]\n", stdout);
     write_rule();
   }
 }
 
 /*
- *  do_file_components - scan the file list copying each temporary file in 
turn.
- *                       This is used twofold:
+ *  do_file_components - scan the file list copying each temporary
+ *                       file in turn.  This is used twofold:
  *
- *                       firstly to emit section heading links, between file 
fragments if required
- *                       and secondly to generate jobname file fragments if 
required.
+ *                       firstly to emit section heading links,
+ *                       between file fragments if required and
+ *                       secondly to generate jobname file fragments
+ *                       if required.
  */
 
 void html_printer::do_file_components (void)
@@ -3904,6 +4561,8 @@
              "content=\"text/html; charset=US-ASCII\">\n", stdout);
   fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout);
   write_title(TRUE);
+  head_info += '\0';
+  fputs(head_info.contents(), stdout);
   fputs("</head>\n", stdout);
   do_body();
 
@@ -3928,9 +4587,119 @@
 }
 
 /*
- *  special - handle all x X requests from troff. For post-html they allow 
users
- *            to pass raw html commands, turn auto linked headings off/on and
- *            also allow troff to emit tags to indicate when a: .br, .sp etc 
occurs.
+ *  get_str - returns a dupicate of string, s. The duplicate
+ *            string is terminated at the next ',' or ']'.
+ */
+
+static char *get_str (const char *s, char **n)
+{
+  int i=0;
+  char *v;
+
+  while ((s[i] != (char)0) && (s[i] != ',') && (s[i] != ']'))
+    i++;
+  if (i>0) {
+    v = (char *)malloc(i+1);
+    memcpy(v, s, i+1);
+    v[i] = (char)0;
+    if (s[i] == ',')
+      (*n) = (char *)&s[i+1];
+    else
+      (*n) = (char *)&s[i];
+    return v;
+  }
+  if (s[i] == ',')
+    (*n) = (char *)&s[1];
+  else
+    (*n) = (char *)s;
+  return NULL;
+}
+
+/*
+ *  make_val - creates a string from if s is NULL.
+ */
+
+char *make_val (char *s, int v, char *id, char *f, char *l)
+{
+  if (s == NULL) {
+    char buf[30];
+
+    sprintf(buf, "%d", v);
+    return strdup(buf);
+  }
+  else {
+    /*
+     *  check that value, s, is the same as, v.
+     */
+    char *t = s;
+
+    while (*t == '=')
+      t++;
+    if (atoi(t) != v) {
+      if (f == NULL)
+       f = "stdin";
+      if (l == NULL)
+       l = "<none>";
+      fprintf(stderr, "%s:%s: grohtml assertion failed at id%s expecting %d 
and was given %s\n",
+             f, l, id, v, s);
+    }
+    return s;
+  }
+}
+
+/*
+ *  handle_assertion - handles the assertions created via .www:ASSERT
+ *                     in www.tmac. See www.tmac for examples.
+ *                     This method should be called as we are
+ *                     parsing the ditroff input. It checks the x, y
+ *                     position assertions. It does _not_ check the
+ *                     troff state assertions as these are unknown at this
+ *                     point.
+ */
+
+void html_printer::handle_assertion (int minv, int minh, int maxv, int maxh, 
const char *s)
+{
+  char *n;
+  char *cmd = get_str(s, &n);
+  char *id  = get_str(n, &n);
+  char *val = get_str(n, &n);
+  char *file= get_str(n, &n);
+  char *line= get_str(n, &n);
+
+  if (strcmp(cmd, "assertion:[x") == 0)
+    as.addx(cmd, id, make_val(val, minh, id, file, line), file, line);
+  else if (strcmp(cmd, "assertion:[y") == 0)
+    as.addy(cmd, id, make_val(val, minv, id, file, line), file, line);
+  else
+    if (strncmp(cmd, "assertion:[", 11) == 0)
+      page_contents->add_tag(&sbuf_style, string(s),
+                            line_number, minv, minh, maxv, maxh);
+}
+
+/*
+ *  build_state_assertion - builds the troff state assertions.
+ */
+
+void html_printer::handle_state_assertion (text_glob *g)
+{
+  if (g != NULL && g->is_a_tag() &&
+      (strncmp(g->text_string, "assertion:[", 11) == 0)) {
+    char *n   = (char *)&g->text_string[11];
+    char *cmd = get_str(n, &n);
+    char *val = get_str(n, &n);
+    char *id  = get_str(n, &n);  // unused
+    char *file= get_str(n, &n);
+    char *line= get_str(n, &n);
+
+    as.build(cmd, val, file, line);
+  }
+}
+
+/*
+ *  special - handle all x X requests from troff. For post-html they
+ *            allow users to pass raw html commands, turn auto linked
+ *            headings off/on and also allow troff to emit tags to
+ *            indicate when a: .br, .sp etc occurs.
  */
 
 void html_printer::special(char *s, const environment *env, char type)
@@ -3961,12 +4730,39 @@
       page_contents->add_and_encode(&sbuf_style, string(&s[5]),
                                    line_number,
                                    env->vpos-env->size*r/72, env->hpos,
-                                   env->vpos               , env->hpos);
+                                   env->vpos               , env->hpos,
+                                   FALSE);
 
       /*
-       * 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 amount.
+       * 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
+       * amount.
+       */
+    } else if (strncmp(s, "html</p>:", 9) == 0) {
+      int r=font::res;   /* resolution of the device */
+      font *f=sbuf_style.f;
+
+      if (f == NULL) {
+       int found=FALSE;
+
+       f = font::load_font("TR", &found);
+      }
+
+      /*
+       *  need to pass all of string through to html output during flush
+       */
+      page_contents->add_and_encode(&sbuf_style, string(s),
+                                   line_number,
+                                   env->vpos-env->size*r/72, env->hpos,
+                                   env->vpos               , env->hpos,
+                                   TRUE);
+
+      /*
+       * 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
+       * amount.
        */
     } else if (strncmp(s, "index:", 6) == 0) {
       cutoff_heading = atoi(&s[6]);
@@ -3977,6 +4773,11 @@
                             line_number,
                             env->vpos-env->size*r/72, env->hpos,
                             env->vpos               , env->hpos);
+    } else if (strncmp(s, "assertion:[", 11) == 0) {
+      int r=font::res;   /* resolution of the device */
+
+      handle_assertion(env->vpos-env->size*r/72, env->hpos,
+                      env->vpos, env->hpos, s);
     }
   }
 }
@@ -4011,7 +4812,7 @@
     { "version", no_argument, 0, 'v' },
     { NULL, 0, 0, 0 }
   };
-  while ((c = getopt_long(argc, argv, "a:g:o:i:I:j:D:F:vbdhlrnp", 
long_options, NULL))
+  while ((c = getopt_long(argc, argv, "a:g:o:i:I:j:D:F:s:vbdhlrnp", 
long_options, NULL))
         != EOF)
     switch(c) {
     case 'v':
@@ -4032,6 +4833,9 @@
     case 'F':
       font::command_line_font_dir(optarg);
       break;
+    case 's':
+      base_point_size = atoi(optarg);
+      break;
     case 'j':
       multiple_files = TRUE;
       job_name = optarg;
Index: groff/src/preproc/html/pre-html.cpp
diff -u groff/src/preproc/html/pre-html.cpp:1.11 
groff/src/preproc/html/pre-html.cpp:1.12
--- groff/src/preproc/html/pre-html.cpp:1.11    Fri Oct  8 07:08:08 2004
+++ groff/src/preproc/html/pre-html.cpp Tue Oct 12 21:39:31 2004
@@ -1546,7 +1546,7 @@
     { NULL, 0, 0, 0 }
   };
   while ((c = getopt_long(argc, argv,
-                         "+a:g:o:i:I:j:D:F:vbdhlrnp", long_options, NULL))
+                         "+a:g:o:i:I:j:D:F:s:vbdhlrnp", long_options, NULL))
         != EOF)
     switch(c) {
     case 'v':
@@ -1583,6 +1583,9 @@
     case 'F':
       font_path.command_line_dir(optarg);
       break;
+    case 's':
+      // handled by post-grohtml (use font size n as the html base font size)
+      break;
     case 'j':
       // handled by post-grohtml (set job name for multiple file output)
       break;
Index: groff/src/roff/troff/request.h
diff -u groff/src/roff/troff/request.h:1.9 groff/src/roff/troff/request.h:1.10
--- groff/src/roff/troff/request.h:1.9  Sat Apr 17 06:41:51 2004
+++ groff/src/roff/troff/request.h      Tue Oct 12 21:39:31 2004
@@ -45,15 +45,17 @@
 struct node;
 
 class macro : public request_or_macro {
-  macro_header *p;
   const char *filename;                // where was it defined?
   int lineno;
   int len;
   int empty_macro;
+  int is_a_diversion;
 public:
+  macro_header *p;
   macro();
   ~macro();
   macro(const macro &);
+  macro(int);
   macro &operator=(const macro &);
   void append(unsigned char);
   void append(node *);
@@ -67,6 +69,7 @@
   macro *to_macro();
   void print_size();
   int empty();
+  int is_diversion();
   friend class string_iterator;
   friend void chop_macro();
   friend void substring_request();




reply via email to

[Prev in Thread] Current Thread [Next in Thread]