2007-09-19 Gaius Mulley * doc/groff.texinfo: Document new .O register and add cross reference entries. * src/devices/grohtml/grohtml.man: Document new -V and -y options. * src/devices/grohtml/html-table.cpp: Modified and related tags to comply with xhtml 1.1. (emit_colspan, emit_td): New methods. (emit_col): Use emit_td. (emit_table_header): Use emit_colspan if dialect xhtml is specified. * src/devices/grohtml/html-table.h: Declare emit_colspan, emit_td. * src/devices/grohtml/html-text.cpp: Add new variable (dialect). Modified tags to comply with xhtml if this dialect was requested. * src/devices/grohtml/html-text.h: Declare html_dialect enum and allow it to be passed into the constructor html_text. * src/devices/grohtml/post-html.cpp: Add variables (valid_flag, groff_sig, dialect). Modify header tag to be xhtml compliant. (handle_valid_flag, do_math, write_html_anchor, write_xhtml_anchor): Added methods to html_printer. (emit_line, emit_raw, do_check_center, write_title, write_rule, writeHeadMetaStyle): Altered to be xhtml compliant. (insert_split_file, do_file_components): Create xhtml file components if necessary and also produces a groff signature if requested. (~html_printer): Call writeHeadMetaStyle at appropriate places depending upon html_dialect. (handle_valid_flag): New method. (main): Added options, x, V and y. (troff_tag): Call do_math. (do_math): New method. * src/preproc/eqn/box.cpp: Create a distinction between the mathml device and the xhtml device. (do_text): Issue a newline at the end of the equation if device xhtml specified. (toplevel): Prefix the output of an equation by the .MATHML macro. (output_string): Suppress \n if xhtml was specified. * src/preproc/eqn/main.cpp: Introduce xhtml flag. (inline_equation): Skip leading spaces after inline equation for xhtml device. (main): Set xhtml flag if -Tmathml:xhtml is specified. * src/preproc/eqn/eqn.h: Declare xhtml flag as external. * src/preproc/eqn/text.cpp: Fix typo, added ';' to 'nu'. * src/preproc/html/pre-html.cpp: Define (html_dialect, eqn_flag). (html_system): Improve debugging support. (alterDeviceTo): Test for -Txhtml when altering device to the image device and reset to -Txhtml. (addZ, addArg): Renamed addZ to addArg and introduced a general parameter. (print_args): New debugging function. (run_output_filter): Use print_args and addArg rather than addZ. (do_html): Add -rxhtml=1 command line parameter as an argument to the html generation of text when xhtml is needed. Include -e on the command line if mathml is required. (scanArguments): Allow -e, -V, -y and -x options. -V, -y are handled by the back end. -e sets eqn_flag. -x determines html dialect. * src/roff/groff/groff.cpp: (clear_name) New method. (main): Set eflag is -e is present on command line. Set is_xhtml if -Txhtml is present. Pass '-x x' to the html pre and post processors. Pass '-e' to the html pre processor if required. Pass '-Tmathml:xhtml' to eqn if xhtml is requested. * src/roff/troff/input.cpp: (init_input_requests): Introduce new number register \n[.O]. * tmac/s.tmac: (LP): Use .nop for semantic sugar. (cov*ab-init) reformat. (@EQ): Use EQN-HTML-IMAGE and friends rather than HTML-IMAGE. (CHECK-FOOTER-AND-KEEP): Define FS, FE such that they use for the html device rather than generate images for footnotes. * tmac/troffrc-end: Define EQN-HTML-IMAGE, EQN-HTML-IMAGE-END, EQN-HTML-IMAGE-RIGHT, EQN-HTML-IMAGE-LEFT, EQN-HTML-IMAGE-INLINE, EQN-HTML-DO-IMAGE, EQN-HTML-IMAGE-END as null strings. * tmac/www.tmac: (HTML): New macro. (MATH): New macro. (PIMG), (MPIMG), (HR) use xhtml compliant syntax. (www-emit-ltag): New macro. (ULS): Ensure that tags are balanced in order by use of www-emit-ltag. (ULE): Likewise uses www-emit-ltag and shuts down paragraphs in order. (OLS, OLE, DLS, DLE): Ditto. Define EQ and EN to EQN-HTML-IMAGE and EQN-HTML-IMAGE-END respectively. (EQN-HTML-IMAGE): New macro. (EQN-HTML-IMAGE-RIGHT): New macro. (EQN-HTML-IMAGE-LEFT): New macro. (EQN-HTML-IMAGE-INLINE): New macro. (EQN-HTML-DO-IMAGE): New macro. (EQN-HTML-IMAGE-END): New macro. (MATHML): New macro. --- groff-cvs/doc/groff.texinfo 2007-04-08 19:50:43.000000000 +0100 +++ groff-html/doc/groff.texinfo 2007-08-09 13:03:12.000000000 +0100 @@ -6474,6 +6474,16 @@ @acronym{ASCII} approximation of the output, this is set to@tie{}1, zero otherwise. @xref{Groff Options}. +@item \n[.O] +@vindex .O +This read only register is set to the suppression nesting level (see +escapes @code{\O} @xref{Suppressing output}. + +@tie{}1 (and to@tie{}0 otherwise) if the current +page is actually being printed, i.e., if the @option{-o} option is being +used to only print selected pages. @xref{Groff Options}, for more +information. + @item \n[.P] @vindex .P This register is set to@tie{}1 (and to@tie{}0 otherwise) if the current @@ -12852,9 +12862,13 @@ @item \O3 Begin a nesting level. At start-up, @code{gtroff} is at outer level. +The current level is contained within the read only register @code{.O} +@xref{Built-in Registers}. @item \O4 End a nesting level. +The current level is contained within the read only register @code{.O} +@xref{Built-in Registers}. @item \O[5@var{P}@var{filename}] This escape is @code{grohtml} specific. Provided that this escape --- groff-cvs/src/devices/grohtml/grohtml.man 2006-12-31 17:34:32.000000000 +0000 +++ groff-html/src/devices/grohtml/grohtml.man 2007-09-19 11:48:59.000000000 +0100 @@ -58,6 +58,7 @@ .OP \-o \%image-vertical-offset .OP \-s size .OP \-S level +.OP \-x html dialect .RI "[\ " files\|.\|.\|. "\ ]" .br .ad \na @@ -130,6 +131,21 @@ .IR dir . . .TP +.B \-e +This option should not be directly invoked by the user as it is +an internal option utilized by +.B groff +when +.B -Thtml , +or +.B -Txhtml +is specified. It is used by the +.B grohtml +preprocessor to determine whether eqn should attempt to produce +MATHML (if +.B -Txhtml +is specified). +.TP .BI \-F dir Prepend directory .IB dir /dev name @@ -241,6 +257,31 @@ .B \-v Print the version number. . +.TP +.B \-V +create a xhtml validator button at the bottom of each page of the document. +. +.TP +.B \-x dialect +html dialect. Currently dialect should be either '4' or 'x' which +indicates whether +.B grohtml +should generate HTML4 or XHTML respectively. +This option should not be directly invoked by the user as it is +an internal option utilized by +.B groff +when +.BR -Thtml , +or +.B -Txhtml +is specified. +.TP +.B \-y +produce a right justified groff signature at the end of the document. +This is only generated if the +.B \-V +flag is also specified. +. . .SH USAGE There are styles called --- groff-cvs/src/devices/grohtml/html-table.cpp 2005-05-26 22:01:58.000000000 +0100 +++ groff-html/src/devices/grohtml/html-table.cpp 2007-08-31 17:22:14.000000000 +0100 @@ -41,6 +41,9 @@ # define FALSE (1==0) #endif +extern html_dialect dialect; + + tabs::tabs () : tab(NULL) { @@ -294,7 +297,7 @@ } p = c; } - if (p != NULL && p->right > 0) + if (p != NULL && p->right > 0 && linelength > p->right) add_column(p->no+1, p->right, linelength, 'L'); } @@ -337,10 +340,12 @@ out->nl(); out->put_string("
put_string(">") .nl(); + if (dialect == xhtml) + emit_colspan(); out->put_string("put_string(" style=\"margin-top: "); @@ -375,6 +380,82 @@ } /* + * emit_colspan - emits a series of colspan entries defining the + * table columns. + */ + +void html_table::emit_colspan (void) +{ + cols *b = columns; + cols *c = columns; + int width = 0; + + out->put_string(""); + while (c != NULL) { + if (b != NULL && b != c && is_gap(b)) + /* + * blank column for gap + */ + out->put_string("") + .nl(); + + width = (get_right(c)*100 + get_effective_linelength()/2) + / get_effective_linelength() + - (c->left*100 + get_effective_linelength()/2) + /get_effective_linelength(); + switch (c->alignment) { + case 'C': + out->put_string("") + .nl(); + break; + case 'R': + out->put_string("") + .nl(); + break; + default: + out->put_string("") + .nl(); + } + b = c; + c = c->next; + } + out->put_string("").nl(); +} + +/* + * emit_td - writes out a ") - .nl(); + emit_td(is_gap(b), ">"); b = b->next; } @@ -421,17 +498,9 @@ / get_effective_linelength() - (b->left*100 + get_effective_linelength()/2) /get_effective_linelength(); - if (width) - out->put_string("") - .nl(); + emit_td(width, ">"); // have we a gap? - if (is_gap(b)) - out->put_string("") - .nl(); + emit_td(is_gap(b), ">"); b = b->next; } width = (get_right(b)*100 + get_effective_linelength()/2) @@ -440,22 +509,13 @@ /get_effective_linelength(); switch (b->alignment) { case 'C': - out->put_string("").nl(); +#if 1 + if (last_col != NULL) { + out->put_string(""); + last_col = NULL; + } +#endif + out->put_string("").nl(); } } --- groff-cvs/src/devices/grohtml/html-table.h 2005-05-26 22:01:58.000000000 +0100 +++ groff-html/src/devices/grohtml/html-table.h 2007-08-09 13:03:12.000000000 +0100 @@ -93,6 +93,8 @@ void finish_row (void); int get_effective_linelength (void); void set_space (int space); + void emit_colspan (void); + void emit_td (int percentage, const char *s = ">"); tabs *tab_stops; /* tab stop positions */ simple_output *out; @@ -121,7 +123,7 @@ // the indent is shutdown when it is deleted private: - void end (void); + void end (void); int is_used; int pg; // values of the registers as passed via initialization int ll; --- groff-cvs/src/devices/grohtml/html-text.cpp 2005-05-26 22:01:58.000000000 +0100 +++ groff-html/src/devices/grohtml/html-text.cpp 2007-09-10 12:08:15.000000000 +0100 @@ -44,10 +44,11 @@ #undef DEBUGGING // #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), - blank_para(TRUE), start_space(FALSE) +html_text::html_text (simple_output *op, html_dialect d) : + stackptr(NULL), lastptr(NULL), out(op), dialect(d), + space_emitted(TRUE), current_indentation(-1), + pageoffset(-1), linelength(-1), blank_para(TRUE), + start_space(FALSE) { } @@ -165,8 +166,12 @@ delete t->indent; t->indent = NULL; break; - case SMALL_TAG: out->put_string(""); break; - case BIG_TAG: out->put_string(""); break; + case SMALL_TAG: if (dialect != xhtml || (! is_in_pre ())) + out->put_string(""); + break; + case BIG_TAG: if (dialect != xhtml || (! is_in_pre ())) + out->put_string(""); + break; case COLOR_TAG: out->put_string(""); break; default: @@ -196,8 +201,10 @@ out->put_string(STYLE_VERTICAL_SPACE); out->put_string("\""); } +#if 0 if (space == TRUE || space == FALSE) out->put_string(" valign=\"top\""); +#endif out->put_string(">"); } @@ -258,8 +265,12 @@ issue_tag("", (char *)t->arg1); } out->enable_newlines(FALSE); break; - case SMALL_TAG: issue_tag("arg1); break; - case BIG_TAG: issue_tag("arg1); break; + case SMALL_TAG: if (dialect != xhtml || (! is_in_pre ())) + issue_tag("arg1); + break; + case BIG_TAG: if (dialect != xhtml || (! is_in_pre ())) + issue_tag("arg1); + break; case BREAK_TAG: break; case COLOR_TAG: issue_color_begin(&t->col); break; @@ -652,9 +663,11 @@ int text = remove_break(); check_emit_text(stackptr); if (text) { - if (is_present(PRE_TAG)) { + if (is_present(PRE_TAG)) out->nl(); - } else + else if (dialect == xhtml) + out->put_string("
").nl(); + else out->put_string("
").nl(); } } else --- groff-cvs/src/devices/grohtml/html-text.h 2005-05-26 22:01:58.000000000 +0100 +++ groff-html/src/devices/grohtml/html-text.h 2007-08-09 13:03:12.000000000 +0100 @@ -32,6 +32,12 @@ #define STYLE_VERTICAL_SPACE "1em" /* + * supported html dialects. + */ + +typedef enum {xhtml, html4} html_dialect; + +/* * html tags */ @@ -56,7 +62,7 @@ class html_text { public: - html_text (simple_output *op); + html_text (simple_output *op, html_dialect d); ~html_text (void); void flush_text (void); void do_emittext (const char *s, int length); @@ -105,6 +111,7 @@ tag_definition *stackptr; /* the current paragraph state */ tag_definition *lastptr; /* the end of the stack */ simple_output *out; + html_dialect dialect; /* which dialect of html? */ int space_emitted; /* just emitted a space? */ int current_indentation; /* current .in value */ int pageoffset; /* .po value */ --- groff-cvs/src/devices/grohtml/post-html.cpp 2006-05-05 22:03:50.000000000 +0100 +++ groff-html/src/devices/grohtml/post-html.cpp 2007-09-19 11:39:48.000000000 +0100 @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 +/* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 * Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote post-html.cpp @@ -90,6 +90,10 @@ static int split_level = 2; /* what heading level to split at? */ static string head_info; /* user supplied information to be placed */ /* into */ +static int valid_flag = FALSE; /* has user requested a valid flag at the */ + /* end of each page? */ +static int groff_sig = FALSE; /* "This document was produced using" */ +html_dialect dialect = html4; /* which html dialect should grohtml output */ /* @@ -1570,6 +1574,8 @@ headers.start_from_head(); header_filename.start_from_head(); + if (dialect == xhtml) + fputs("

", f); do { g = headers.get_data(); fputs("", f); fputs(g->text_string, f); - fputs("
\n", f); + fputs("", f); + if (dialect == xhtml) + fputs("
\n", f); + else + fputs("
\n", f); headers.move_right(); if (multiple_files && (! header_filename.is_empty())) header_filename.move_right(); } while (! headers.is_equal_to_head()); fputs("\n", f); + if (dialect == xhtml) + fputs("

\n", f); } } } @@ -2091,6 +2103,10 @@ int round_width (int x); void handle_tag_within_title (text_glob *g); void writeHeadMetaStyle (void); + void handle_valid_flag (void); + void do_math (text_glob *g); + void write_html_anchor (text_glob *h); + void write_xhtml_anchor (text_glob *h); // ADD HERE public: @@ -2167,7 +2183,10 @@ void html_printer::emit_line (text_glob *) { // --fixme-- needs to know the length in percentage - html.put_string("
"); + if (dialect == xhtml) + html.put_string("
"); + else + html.put_string("
"); } /* @@ -2206,13 +2225,22 @@ switch (next_tag) { case CENTERED: - current_paragraph->do_para("align=center", space); + if (dialect == html4) + current_paragraph->do_para("align=\"center\"", space); + else + current_paragraph->do_para("class=\"center\"", space); break; case LEFT: - current_paragraph->do_para(&html, "align=left", get_troff_indent(), pageoffset, linelength, space); + if (dialect == html4) + current_paragraph->do_para(&html, "align=\"left\"", get_troff_indent(), pageoffset, linelength, space); + else + current_paragraph->do_para(&html, "class=\"left\"", get_troff_indent(), pageoffset, linelength, space); break; case RIGHT: - current_paragraph->do_para(&html, "align=right", get_troff_indent(), pageoffset, linelength, space); + if (dialect == html4) + current_paragraph->do_para(&html, "align=\"right\"", get_troff_indent(), pageoffset, linelength, space); + else + current_paragraph->do_para(&html, "class=\"right\"", get_troff_indent(), pageoffset, linelength, space); break; default: fatal("unknown enumeration"); @@ -2310,7 +2338,7 @@ } if (exists(filename)) *s += string(""; + + "alt=\"Image " + filename + "\">"; return *s; } @@ -2409,14 +2437,60 @@ } } +/* + * write_html_anchor - writes out an anchor. The style of the anchor + * dependant upon simple_anchor. + */ + +void html_printer::write_html_anchor (text_glob *h) +{ + if (dialect == html4) { + if (h != NULL) { + html.put_string("").nl(); + } + } +} + +/* + * write_xhtml_anchor - writes out an anchor. The style of the anchor + * dependant upon simple_anchor. + */ + +void html_printer::write_xhtml_anchor (text_glob *h) +{ + if (dialect == xhtml) { + if (h != NULL) { + html.put_string(" id=\""); + if (simple_anchors) { + string buffer(ANCHOR_TEMPLATE); + + buffer += as_string(header.no_of_headings); + buffer += '\0'; + html.put_string(buffer.contents()); + } else + html.put_string(header.header_buffer); + html.put_string("\""); + } + } +} + void html_printer::write_header (void) { if (! header.header_buffer.empty()) { + text_glob *a = NULL; int space = current_paragraph->retrieve_para_space() || seen_space; - if (header.header_level > 7) { + if (header.header_level > 7) header.header_level = 7; - } // firstly we must terminate any font and type faces current_paragraph->done_para(); @@ -2427,33 +2501,22 @@ header.no_of_headings++; style st; - text_glob *h=new text_glob(); - h->text_glob_html(&st, + a = new text_glob(); + a->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, + // and add this header to the header list + header.headers.add(a, header.no_of_headings, header.no_of_headings, header.no_of_headings, - header.no_of_headings, header.no_of_headings); // and add this header to the header list - - // lastly we generate a tag - - html.nl().nl().put_string("").nl(); + header.no_of_headings, header.no_of_headings); } + html.nl().nl(); + if (manufacture_headings) { // line break before a header if (!current_paragraph->emitted_text()) @@ -2462,11 +2525,14 @@ if (header.header_level<4) { html.put_string(""); html.put_string(header.header_buffer); - html.put_string("").nl(); + html.put_string("").nl(); + write_html_anchor(a); + html.put_string("").nl(); } else { html.put_string(""); - html.put_string(header.header_buffer); + html.put_string(header.header_buffer).nl(); + write_html_anchor(a); html.put_string("").nl(); } } @@ -2474,8 +2540,10 @@ // and now we issue the real header html.put_string(""); - html.put_string(header.header_buffer); + html.put_string(header.header_buffer).nl(); + write_html_anchor(a); html.put_string("").nl(); @@ -2810,10 +2878,15 @@ int space = current_paragraph->retrieve_para_space() || seen_space; current_paragraph->done_para(); supress_sub_sup = TRUE; - current_paragraph->do_para("align=center", space); + if (dialect == html4) + current_paragraph->do_para("align=\"center\"", space); + else + current_paragraph->do_para("class=\"center\"", space); } else - if (strcmp("align=center", - current_paragraph->get_alignment()) != 0) { + if ((strcmp("align=\"center\"", + current_paragraph->get_alignment()) != 0) && + (strcmp("class=\"center\"", + current_paragraph->get_alignment()) != 0)) { /* * different alignment, so shutdown paragraph and open * a new one. @@ -2821,7 +2894,10 @@ int space = current_paragraph->retrieve_para_space() || seen_space; current_paragraph->done_para(); supress_sub_sup = TRUE; - current_paragraph->do_para("align=center", space); + if (dialect == html4) + current_paragraph->do_para("align=\"center\"", space); + else + current_paragraph->do_para("class=\"center\"", space); } else /* * same alignment, if we have emitted text then issue a break. @@ -2898,7 +2974,10 @@ split_file += string("-"); split_file += as_string(header.no_of_level_one_headings); - split_file += string(".html"); + if (dialect == xhtml) + split_file += string(".xhtml"); + else + split_file += string(".html"); split_file += '\0'; file_list.set_file_name(split_file); @@ -3092,9 +3171,15 @@ * firstly skip over devtag: */ char *t=(char *)g->text_string+strlen("devtag:"); - if (strncmp(g->text_string, "html

:", strlen("html

:")) == 0) { do_end_para(g); + } else if (strncmp(g->text_string, "html:", strlen("html:")) == 0) { + if (current_paragraph->emitted_text()) + html.put_string(g->text_string+9); + else + do_end_para(g); + } else if (strncmp(g->text_string, "math:", strlen("math:")) == 0) { + do_math(g); } else if (g->is_eol()) { do_eol(); } else if (g->is_eol_ce()) { @@ -3177,6 +3262,21 @@ } /* + * do_math - prints out the equation + */ + +void html_printer::do_math (text_glob *g) +{ + int l = strlen("math:"); + + do_font(g); + if (current_paragraph->emitted_text()) + html.put_string(g->text_string+9); + else + do_end_para(g); +} + +/* * is_in_middle - returns TRUE if the positions left..right are in the center of the page. */ @@ -4720,7 +4820,10 @@ } else { title.has_been_written = TRUE; if (title.with_h1) { - html.put_string("

"); + if (dialect == xhtml) + html.put_string("

"); + else + html.put_string("

"); html.put_string(title.text); html.put_string("

").nl().nl(); } @@ -4737,8 +4840,12 @@ static void write_rule (void) { - if (auto_rule) - fputs("
\n", stdout); + if (auto_rule) { + if (dialect == xhtml) + fputs("
\n", stdout); + else + fputs("
\n", stdout); + } } void html_printer::begin_page(int n) @@ -4757,7 +4864,7 @@ output_hpos = -1; output_vpos = -1; output_vpos_max = -1; - current_paragraph = new html_text(&html); + current_paragraph = new html_text(&html, dialect); do_indent(get_troff_indent(), pageoffset, linelength); current_paragraph->do_para("", FALSE); } @@ -4815,7 +4922,13 @@ int need_bar = FALSE; if (multiple_files) { + current_paragraph->done_para(); write_rule(); + if (groff_sig) + fputs("\n\n
tag with a corresponding width + * if the dialect is html4. + */ + +void html_table::emit_td (int percentage, const char *s) +{ + if (percentage) { + if (dialect == html4) { + out->put_string("put_string(s); + out->nl(); + } + else { + out->put_string("put_string(s); + out->nl(); + } + } +} + +/* * emit_col - moves onto column, n. */ @@ -405,11 +486,7 @@ // have we a gap? if (last_col != NULL) { - if (is_gap(b)) - out->put_string("") - .nl(); + emit_td(width, " align=center>"); break; case 'R': - out->put_string("") - .nl(); + emit_td(width, " align=right>"); break; default: - out->put_string("") - .nl(); + emit_td(width); } // remember column, b last_col = b; @@ -477,7 +537,13 @@ if (n > 0) emit_col(n); - out->put_string("
\n" + "\n" + "
", stdout); fputs("[ ", stdout); if ((strcmp(prev.contents(), "") != 0) && prev != top && prev != current) { emit_link(prev, "prev"); @@ -4833,6 +4946,16 @@ emit_link(top, "top"); } fputs(" ]\n", stdout); + handle_valid_flag(); + + if (groff_sig) { + fputs("" + "This document was produced using " + "" + "groff-", stdout); + fputs(Version_string, stdout); + fputs(".
\n", stdout); + } write_rule(); } } @@ -4857,7 +4980,10 @@ file_list.start_of_list(); top = string(job_name); - top += string(".html"); + if (dialect == xhtml) + top += string(".xhtml"); + else + top += string(".html"); top += '\0'; next = file_list.next_file_name(); next += '\0'; @@ -4891,8 +5017,27 @@ } if (fragment_no > 1) write_navigation(top, prev, next, current); - else + else { + current_paragraph->done_para(); write_rule(); + if (valid_flag && dialect == xhtml) { + if (groff_sig) + fputs("\n\n\n" + "\n" + "
", stdout); + handle_valid_flag(); + if (groff_sig) { + fputs("" + "This document was produced using " + "" + "groff-", stdout); + fputs(Version_string, stdout); + fputs(".
\n", stdout); + } + write_rule(); + } + } } /* @@ -4902,21 +5047,43 @@ void html_printer::writeHeadMetaStyle (void) { - fputs("\n", stdout); - - fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - fputs("\n", stdout); - - fputs("\n", stdout); } @@ -4932,6 +5099,10 @@ current_paragraph->flush_text(); html.end_line(); html.set_file(stdout); + + if (dialect == xhtml) + writeHeadMetaStyle(); + html.begin_comment("Creator : ") .put_string("groff ") .put_string("version ") @@ -4943,7 +5114,8 @@ .put_string(ctime(&t), strlen(ctime(&t))-1) .end_comment(); - writeHeadMetaStyle(); + if (dialect == html4) + writeHeadMetaStyle(); write_title(TRUE); head_info += '\0'; @@ -5123,9 +5295,12 @@ * requesting that the formatting move right by the appropriate * amount. */ - } else if (strncmp(s, "html

:", 9) == 0) { + } else if ((strncmp(s, "html

:", 9) == 0) || + (strncmp(s, "html:", 9) == 0) || + (strncmp(s, "math:", 9) == 0)) { int r=font::res; /* resolution of the device */ font *f=sbuf_style.f; + string t; if (f == NULL) { int found=FALSE; @@ -5133,6 +5308,17 @@ f = font::load_font("TR", &found); } + if (strncmp(s, "math:", 9) == 0) { + if (strncmp((char *)&s[9], "", 6) == 0) { + s[9] = '\0'; + t = s; + t += ""; + t += (char *)&s[15]; + t += '\0'; + s = (char *)&t[0]; + } + } + /* * need to pass all of string through to html output during flush */ @@ -5148,6 +5334,7 @@ * requesting that the formatting move right by the appropriate * amount. */ + } else if (strncmp(s, "index:", 6) == 0) { cutoff_heading = atoi(&s[6]); } else if (strncmp(s, "assertion:[", 11) == 0) { @@ -5211,6 +5398,21 @@ return n * r; } +/* + * handle_valid_flag - emits a valid xhtml 1.1 button, providing -V and -x + * were supplied on the command line. + */ + +void html_printer::handle_valid_flag (void) +{ + if (valid_flag && dialect == xhtml) + fputs("

" + "\n" + "

\n", stdout); +} + int main(int argc, char **argv) { program_name = argv[0]; @@ -5222,7 +5424,7 @@ { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "a:bdD:F:g:hi:I:j:lno:prs:S:v", + while ((c = getopt_long(argc, argv, "a:bdD:eF:g:hi:I:j:lno:prs:S:vVx:y", long_options, NULL)) != EOF) switch(c) { @@ -5240,6 +5442,9 @@ case 'D': /* handled by pre-html */ break; + case 'e': + /* handled by pre-html */ + break; case 'F': font::command_line_font_dir(optarg); break; @@ -5285,6 +5490,21 @@ printf("GNU post-grohtml (groff) version %s\n", Version_string); exit(0); break; + case 'V': + valid_flag = TRUE; + break; + case 'x': + if (strcmp(optarg, "x") == 0) { + dialect = xhtml; + simple_anchors = TRUE; + } else if (strcmp(optarg, "4") == 0) + dialect = html4; + else + printf("unsupported html dialect %s (defaulting to html4)\n", optarg); + break; + case 'y': + groff_sig = TRUE; + break; case CHAR_MAX + 1: // --help usage(stdout); exit(0); @@ -5307,6 +5527,6 @@ static void usage(FILE *stream) { - fprintf(stream, "usage: %s [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n", + fprintf(stream, "usage: %s [-vbelnhVy] [-D dir] [-I image_stem] [-F dir] [-x x] [files ...]\n", program_name); } --- groff-cvs/src/preproc/eqn/box.cpp 2007-03-21 13:30:59.000000000 +0000 +++ groff-html/src/preproc/eqn/box.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -237,7 +237,7 @@ { if (output_format == troff) printf("\\*(" LINE_STRING "\n"); - else if (output_format == mathml) + else if (output_format == mathml && (! xhtml)) putchar('\n'); } @@ -254,8 +254,11 @@ printf(".as " LINE_STRING " \"%s\n", s); printf(".ec\n"); } - else if (output_format == mathml) + else if (output_format == mathml) { fputs(s, stdout); + if (xhtml && strlen(s)>0) + printf("\n"); + } } void set_minimum_size(int n) @@ -349,6 +352,8 @@ b->uid, body_height, b->uid, body_depth); } else if (output_format == mathml) { + if (xhtml) + printf(".MATHML "); printf(""); b->output(); printf(""); --- groff-cvs/src/preproc/eqn/eqn.h 2007-02-05 15:24:56.000000000 +0000 +++ groff-html/src/preproc/eqn/eqn.h 2007-08-09 13:03:12.000000000 +0100 @@ -41,6 +41,7 @@ extern int compatible_flag; extern int nroff; extern eqnmode_t output_format; +extern int xhtml; void init_lex(const char *str, const char *filename, int lineno); void lex_error(const char *message, --- groff-cvs/src/preproc/eqn/main.cpp 2007-02-05 15:24:56.000000000 +0000 +++ groff-html/src/preproc/eqn/main.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -45,6 +45,7 @@ int compatible_flag = 0; int no_newline_in_delim_flag = 0; int html = 0; +int xhtml = 0; eqnmode_t output_format; int read_line(FILE *fp, string *p) @@ -188,6 +189,13 @@ html_end_suppress(); printf("\n"); } + if (output_format == mathml) + printf("\n"); + if (xhtml) { + /* skip leading spaces */ + while (((*ptr) != '\0') && (*ptr == ' ')) + ptr++; + } start = delim_search(ptr, start_delim); if (start == 0) { char *nl = strchr(ptr, '\n'); @@ -314,6 +322,12 @@ output_format = mathml; load_startup_file = 0; } + else if (strcmp(device, "mathml:xhtml") == 0) { + device = "MathML"; + output_format = mathml; + load_startup_file = 0; + xhtml = 1; + } break; case 's': if (!set_gsize(optarg)) --- groff-cvs/src/preproc/eqn/text.cpp 2007-02-05 15:24:56.000000000 +0000 +++ groff-html/src/preproc/eqn/text.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -57,7 +57,7 @@ {"*L", "Λ"}, // ISOgrk3 {"*m", "μ"}, // ISOgrk3 {"*M", "M"}, - {"*n", "&nu"}, // ISOgrk3 + {"*n", "ν"}, // ISOgrk3 {"*N", "N"}, {"*o", "o"}, {"*O", "O"}, --- groff-cvs/src/preproc/html/pre-html.cpp 2006-06-27 01:52:39.000000000 +0100 +++ groff-html/src/preproc/html/pre-html.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -56,6 +56,10 @@ #include "nonposix.h" +#if 0 +# define DEBUGGING +#endif + /* Establish some definitions to facilitate discrimination between differing runtime environments. */ @@ -162,10 +166,6 @@ #define REGION_TEMPLATE_SHORT "rg" #define REGION_TEMPLATE_LONG "-regions-" -#if 0 -# define DEBUGGING -#endif - #if !defined(TRUE) # define TRUE (1==1) #endif @@ -177,6 +177,8 @@ CENTERED, LEFT, RIGHT, INLINE } IMAGE_ALIGNMENT; +typedef enum {xhtml, html4} html_dialect; + static int postscriptRes = -1; // postscript resolution, // dots per inch static int stdoutfd = 1; // output file descriptor - @@ -210,6 +212,7 @@ static char *htmlFileName = NULL; // output of pre-html output which // is sent to troff -Thtml #endif +static int eqn_flag = FALSE; // must we preprocess via eqn? static char *linebuf = NULL; // for scanning devps/DESC static int linebufsize = 0; @@ -217,6 +220,7 @@ const char *const FONT_ENV_VAR = "GROFF_FONT_PATH"; static search_path font_path(FONT_ENV_VAR, FONTPATH, 0, 0); +static html_dialect dialect = html4; /* @@ -313,28 +317,37 @@ void html_system(const char *s, int redirect_stdout) { - // Redirect standard error to the null device. This is more - // portable than using "2> /dev/null", since it doesn't require a - // Unixy shell. - int save_stderr = dup(2); - int save_stdout = dup(1); - int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666); - if (save_stderr > 2 && fdnull > 2) - dup2(fdnull, 2); - if (redirect_stdout && save_stdout > 1 && fdnull > 1) - dup2(fdnull, 1); - if (fdnull >= 0) - close(fdnull); - int status = system(s); - dup2(save_stderr, 2); - if (redirect_stdout) - dup2(save_stdout, 1); - if (status == -1) - fprintf(stderr, "Calling `%s' failed\n", s); - else if (status) - fprintf(stderr, "Calling `%s' returned status %d\n", s, status); - close(save_stderr); - close(save_stdout); +#if defined(DEBUGGING) + if (debug) { + fprintf(stderr, "executing: "); + fwrite(s, sizeof(char), strlen(s), stderr); + fflush(stderr); + } +#endif + { + // Redirect standard error to the null device. This is more + // portable than using "2> /dev/null", since it doesn't require a + // Unixy shell. + int save_stderr = dup(2); + int save_stdout = dup(1); + int fdnull = open(NULL_DEV, O_WRONLY|O_BINARY, 0666); + if (save_stderr > 2 && fdnull > 2) + dup2(fdnull, 2); + if (redirect_stdout && save_stdout > 1 && fdnull > 1) + dup2(fdnull, 1); + if (fdnull >= 0) + close(fdnull); + int status = system(s); + dup2(save_stderr, 2); + if (redirect_stdout) + dup2(save_stdout, 1); + if (status == -1) + fprintf(stderr, "Calling `%s' failed\n", s); + else if (status) + fprintf(stderr, "Calling `%s' returned status %d\n", s, status); + close(save_stderr); + close(save_stdout); + } } /* @@ -921,12 +934,6 @@ if (s == NULL) sys_fatal("make_message"); -#if defined(DEBUGGING) - if (debug) { - fwrite(s, sizeof(char), strlen(s), stderr); - fflush(stderr); - } -#endif html_system(s, 1); s = make_message("echo showpage | " @@ -945,12 +952,6 @@ psPageName); if (s == NULL) sys_fatal("make_message"); -#if defined(DEBUGGING) - if (debug) { - fwrite(s, sizeof(char), strlen(s), stderr); - fflush(stderr); - } -#endif html_system(s, 1); free(s); currentPageNo = pageno; @@ -1031,12 +1032,6 @@ if (s == NULL) sys_fatal("make_message"); -#if defined(DEBUGGING) - if (debug) { - fprintf(stderr, s); - fflush(stderr); - } -#endif html_system(s, 0); free(s); } @@ -1201,7 +1196,8 @@ if (toImage) { while (i < argc) { - if (strcmp(argv[i], "-Thtml") == 0) + if ((strcmp(argv[i], "-Thtml") == 0) || + (strcmp(argv[i], "-Txhtml") == 0)) argv[i] = (char *)IMAGE_DEVICE; i++; } @@ -1210,7 +1206,10 @@ else { while (i < argc) { if (strcmp(argv[i], IMAGE_DEVICE) == 0) - argv[i] = (char *)"-Thtml"; + if (dialect == xhtml) + argv[i] = (char *)"-Txhtml"; + else + argv[i] = (char *)"-Thtml"; i++; } argv[troff_arg] = (char *)"groff"; /* use groff -Z */ @@ -1218,10 +1217,10 @@ } /* - * addZ - Append -Z onto the command list for groff. + * addArg - Append newarg onto the command list for groff. */ -char **addZ(int argc, char *argv[]) +char **addArg(int argc, char *argv[], char *newarg) { char **new_argv = (char **)malloc((argc + 2) * sizeof(char *)); int i = 0; @@ -1233,7 +1232,7 @@ new_argv[i] = argv[i]; i++; } - new_argv[i] = (char *)"-Z"; + new_argv[i] = newarg; while (i < argc) { new_argv[i + 1] = argv[i]; i++; @@ -1278,12 +1277,29 @@ fprintf(stderr, "\n"); } -int char_buffer::run_output_filter(int filter, int /* argc */, char **argv) +/* + * print_args - print arguments as if they were issued on the command line. + */ + +void print_args(int argc, char *argv[]) +{ +#if defined(DEBUGGING) + if (debug) { + fprintf(stderr, "executing: "); + for (int i = 0; i < argc; i++) + fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, "\n"); + } +#endif +} + +int char_buffer::run_output_filter(int filter, int argc, char **argv) { int pipedes[2]; PID_T child_pid; int status; + print_args(argc, argv); if (pipe(pipedes) < 0) sys_fatal("pipe"); @@ -1441,7 +1457,7 @@ alterDeviceTo(argc, argv, 0); argv += troff_arg; // skip all arguments up to groff argc -= troff_arg; - argv = addZ(argc, argv); + argv = addArg(argc, argv, "-Z"); argc++; s = "-dwww-image-template="; @@ -1451,6 +1467,15 @@ argv = addRegDef(argc, argv, s.contents()); argc++; + if (dialect == xhtml) { + argv = addRegDef(argc, argv, "-rxhtml=1"); + argc++; + if (eqn_flag) { + argv = addRegDef(argc, argv, "-e"); + argc++; + } + } + #if defined(DEBUGGING) # define HTML_DEBUG_STREAM OUTPUT_STREAM(htmlFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) @@ -1488,6 +1513,15 @@ argv = addRegDef(argc, argv, "-P-pletter"); argc++; + if (dialect == xhtml) { + if (eqn_flag) { + argv = addRegDef(argc, argv, "-rxhtml=1"); + argc++; + } + argv = addRegDef(argc, argv, "-e"); + argc++; + } + #if defined(DEBUGGING) # define IMAGE_DEBUG_STREAM OUTPUT_STREAM(troffFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) @@ -1547,7 +1581,7 @@ { "version", no_argument, 0, 'v' }, { NULL, 0, 0, 0 } }; - while ((c = getopt_long(argc, argv, "+a:bdD:F:g:hi:I:j:lno:prs:S:v", + while ((c = getopt_long(argc, argv, "+a:bdD:eF:g:hi:I:j:lno:prs:S:vVx:y", long_options, NULL)) != EOF) switch(c) { @@ -1570,6 +1604,9 @@ case 'D': image_dir = optarg; break; + case 'e': + eqn_flag = TRUE; + break; case 'F': font_path.command_line_dir(optarg); break; @@ -1617,6 +1654,21 @@ case 'v': printf("GNU pre-grohtml (groff) version %s\n", Version_string); exit(0); + case 'V': + // handled by post-grohtml (create validator button) + break; + case 'x': + // html dialect + if (strcmp(optarg, "x") == 0) + dialect = xhtml; + else if (strcmp(optarg, "4") == 0) + dialect = html4; + else + printf("unsupported html dialect %s (defaulting to html4)\n", optarg); + break; + case 'y': + // handled by post-grohtml (create groff signature) + break; case CHAR_MAX + 1: // --help usage(stdout); exit(0); --- groff-cvs/src/roff/groff/groff.cpp 2006-09-03 13:52:20.000000000 +0100 +++ groff-html/src/roff/groff/groff.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -74,6 +74,7 @@ public: possible_command(); ~possible_command(); + void clear_name(); void set_name(const char *); void set_name(const char *, const char *); const char *get_name(); @@ -119,6 +120,8 @@ int Xflag = 0; int oflag = 0; int safer_flag = 1; + int is_xhtml = 0; + int eflag = 0; int opt; const char *command_prefix = getenv("GROFF_COMMAND_PREFIX"); const char *encoding = getenv("GROFF_ENCODING"); @@ -173,6 +176,7 @@ commands[GRAP_INDEX].set_name(command_prefix, "grap"); break; case 'e': + eflag = 1; commands[EQN_INDEX].set_name(command_prefix, "eqn"); break; case 's': @@ -237,10 +241,21 @@ safer_flag = 0; break; case 'T': - if (strcmp(optarg, "html") == 0) { + if (strcmp(optarg, "xhtml") == 0) { // force soelim to aid the html preprocessor commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); + Pargs += "-x"; + Pargs += '\0'; + Pargs += 'x'; + Pargs += '\0'; + is_xhtml = 1; + device = "html"; + break; } + if (strcmp(optarg, "html") == 0) + // force soelim to aid the html preprocessor + commands[SOELIM_INDEX].set_name(command_prefix, "soelim"); + if (strcmp(optarg, "Xps") == 0) { warning("-TXps option is obsolete: use -X -Tps instead"); device = "ps"; @@ -313,6 +328,8 @@ commands[TROFF_INDEX].set_name(predriver); // pass the device arguments to the predrivers as well commands[TROFF_INDEX].insert_args(Pargs); + if (eflag && is_xhtml) + commands[TROFF_INDEX].insert_arg("-e"); if (vflag) commands[TROFF_INDEX].insert_arg("-v"); } @@ -371,11 +388,21 @@ commands[SPOOL_INDEX].set_name(0); } commands[TROFF_INDEX].append_arg("-T", device); - // html renders equations as images via ps if (strcmp(device, "html") == 0) { - if (oflag) - fatal("`-o' option is invalid with device `html'"); - commands[EQN_INDEX].append_arg("-Tps:html"); + if (is_xhtml) { + if (oflag) + fatal("`-o' option is invalid with device `xhtml'"); + if (zflag) + commands[EQN_INDEX].append_arg("-Tmathml:xhtml"); + else if (eflag) + commands[EQN_INDEX].clear_name(); + } + else { + if (oflag) + fatal("`-o' option is invalid with device `html'"); + // html renders equations as images via ps + commands[EQN_INDEX].append_arg("-Tps:html"); + } } else commands[EQN_INDEX].append_arg("-T", device); @@ -542,6 +569,14 @@ name = strsave(s); } +void possible_command::clear_name() +{ + a_delete name; + a_delete argv; + name = NULL; + argv = NULL; +} + void possible_command::set_name(const char *s1, const char *s2) { a_delete name; --- groff-cvs/src/roff/troff/input.cpp 2007-03-19 08:04:29.000000000 +0000 +++ groff-html/src/roff/troff/input.cpp 2007-08-09 13:03:12.000000000 +0100 @@ -7756,6 +7756,7 @@ number_reg_dictionary.define(".$", new nargs_reg); number_reg_dictionary.define(".br", new break_flag_reg); number_reg_dictionary.define(".C", new constant_int_reg(&compatible_flag)); + number_reg_dictionary.define(".O", new variable_reg(&begin_level)); number_reg_dictionary.define(".c", new lineno_reg); number_reg_dictionary.define(".color", new constant_int_reg(&color_flag)); number_reg_dictionary.define(".F", new filename_reg); --- groff-cvs/tmac/s.tmac 2007-07-15 16:02:55.000000000 +0100 +++ groff-html/tmac/s.tmac 2007-09-19 10:28:23.000000000 +0100 @@ -221,6 +221,7 @@ . ps \\n[PS] .\} .. +. .de LP .if !'\\n[.z]'' \{\ . br @@ -229,8 +230,9 @@ .br .cov*ab-init .cov*print -\\*[\\$0]\\ +.nop \\*[\\$0]\\ .. +. .als IP LP .als PP LP .als XP LP @@ -241,6 +243,7 @@ .als MC LP .als RT LP .als XS LP +. .de cov*ab-init .als cov*ab-init @nop .als LP @LP @@ -265,6 +268,7 @@ .als AI par@AI .als TL par@TL .. +. .de @AB .if !'\\n(.z'' \{\ . br @@ -342,7 +346,7 @@ .cov*tl-au-print .sp 3 .if d cov*ab-div \{\ -. if !'\*(.T'html' . nf +. if !'\*(.T'html' .nf . cov*ab-div .\} .sp 3 @@ -1691,12 +1695,12 @@ .\} .di eqn*div .in 0 -.if \\n[eqn*type]=0 .HTML-IMAGE-LEFT +.if \\n[eqn*type]=0 .EQN-HTML-IMAGE-LEFT .if \\n[eqn*type]=1 \{\ . if '\*(.T'html' .RS -. HTML-IMAGE-INLINE +.EQN-HTML-IMAGE-INLINE .\} -.if \\n[eqn*type]=2 .HTML-IMAGE +.if \\n[eqn*type]=2 .EQN-HTML-IMAGE .nf .. .de @div-end!eqn*div @@ -1744,20 +1748,21 @@ . \} . el \{ .\" must terminate empty equations in html and ps4html as they contain -.\" the HTML-IMAGE-END suppression nodes +.\" the EQN-HTML-IMAGE-END suppression nodes . if \\n[dl] .chop eqn*div . if '\*(.T'html' \\*[eqn*div] . if r ps4html \\*[eqn*div] . \} . if !'\*(.T'html' .fi -. if \\n[eqn*type]=0 .HTML-IMAGE-END +. if \\n[eqn*type]=0 .EQN-HTML-IMAGE-END . if \\n[eqn*type]=1 \{\ -. HTML-IMAGE-END +. EQN-HTML-IMAGE-END . if '\*(.T'html' .RE . \} -. if \\n[eqn*type]=2 .HTML-IMAGE-END +. if \\n[eqn*type]=2 .EQN-HTML-IMAGE-END .\} .. +. .\" **************************** .\" ******** module tbl ******** .\" **************************** @@ -2065,35 +2070,21 @@ .ds ! \(r!\" upside down ! .. .de CHECK-FOOTER-AND-KEEP -.\" it might be better to als FS -> B1 and FE -> B2 -.\" however this produced wierd results, so I've moved back to a more reliable -.\" but less interesting solution --fixme-- -. if '\*(.T'html' \{\ -. rm KF -. als KF KS -. rm FS -. de FS -. br -. HTML-IMAGE -\\.. -. rm FE -. de FE -. br -. HTML-IMAGE-END -\\.. -. \} -. if r ps4html \{\ -. rm FS -. de FS -. br -. HTML-IMAGE +.if '\*(.T'html' \{\ +. rm KF +. als KF KS +. +. rm FS +. de FS +. sp +. HTML-NS \\.. -. rm FE -. de FE -. br -. HTML-IMAGE-END +. rm FE +. de FE +. HTML-NS +. sp \\.. -. \} +.\} .. .par@load-init .\" **************************** --- groff-cvs/tmac/troffrc-end 2004-12-16 13:09:54.000000000 +0000 +++ groff-html/tmac/troffrc-end 2007-08-09 13:03:12.000000000 +0100 @@ -8,12 +8,19 @@ .do if r ps4html .do mso www.tmac . .\" for all other devices blank out these macros -.do if !d HTML-IMAGE-INLINE .do ds HTML-IMAGE-INLINE -.do if !d HTML-IMAGE .do ds HTML-IMAGE -.do if !d HTML-IMAGE-RIGHT .do ds HTML-IMAGE-RIGHT -.do if !d HTML-IMAGE-LEFT .do ds HTML-IMAGE-LEFT -.do if !d HTML-IMAGE-END .do ds HTML-IMAGE-END -.do if !d DEVTAG .do ds DEVTAG -.do if !d HTML-DO-IMAGE .do ds HTML-DO-IMAGE +.do if !d HTML-IMAGE-INLINE .do ds HTML-IMAGE-INLINE +.do if !d HTML-IMAGE .do ds HTML-IMAGE +.do if !d HTML-IMAGE-RIGHT .do ds HTML-IMAGE-RIGHT +.do if !d HTML-IMAGE-LEFT .do ds HTML-IMAGE-LEFT +.do if !d HTML-IMAGE-END .do ds HTML-IMAGE-END +.do if !d DEVTAG .do ds DEVTAG +.do if !d HTML-DO-IMAGE .do ds HTML-DO-IMAGE +.do if !d EQN-HTML-IMAGE-END .do ds EQN-HTML-IMAGE-END +.do if !d EQN-HTML-IMAGE .do ds EQN-HTML-IMAGE +.do if !d EQN-HTML-IMAGE-RIGHT .do ds EQN-HTML-IMAGE-RIGHT +.do if !d EQN-HTML-IMAGE-LEFT .do ds EQN-HTML-IMAGE-LEFT +.do if !d EQN-HTML-IMAGE-INLINE .do ds EQN-HTML-IMAGE-INLINE +.do if !d EQN-HTML-DO-IMAGE .do ds EQN-HTML-DO-IMAGE +.do if !d EQN-HTML-IMAGE-END .do ds EQN-HTML-IMAGE-END . .\" Don't let blank lines creep in here. --- groff-cvs/tmac/www.tmac 2006-05-07 21:52:25.000000000 +0100 +++ groff-html/tmac/www.tmac 2007-09-19 11:23:35.000000000 +0100 @@ -301,6 +301,26 @@ . \} .. . +.\" +.\" emit a HTML tag. If text has been written in the paragraph +.\" then do not shut the paragraph down. +.\" If text was not written, remove the empty +.\" paragraph tag and emit the desired html tag. +.\" +.de HTML +. if \\n[www-html] .nop \&\X^html:\\$*^ +.. +. +.\" +.\" emit a MATH tag. If text has been written in the paragraph +.\" then do not shut the paragraph down. +.\" If text was not written, remove the empty +.\" paragraph tag and emit the desired math tag. +.\" +.de MATH +. if \\n[www-html] .nop \&\X^math:\\$*^ +.. +. .\" -------------------------------------------------------------------- .\" HX n .\" @@ -490,7 +510,8 @@ . if !'\\$4'' \ . nr www-height \\$4 . HTML Image \\$1 + "width=""\\n[www-width]""" \ + "height=""\\n[www-height]"""> . \} . el \ . nop \\*[www:open]\f[\\*[www:fontstyle]]\\$1\f[]\\*[www:close] @@ -537,22 +558,22 @@ . ie (\\n[www-width] == 0) \{\ . ie (\\n[www-height] == 0) \ . HTML

" + "alt=""Image \\$1""">

" . el \ . HTML

+ "height=""\\n[www-height]""">

. \} . el \{\ . ie (\\n[www-height] == 0) \ . HTML

+ "width=""\\n[www-width]""">

. el \ . HTML

+ "width=""\\n[www-width]""" \ + "height=""\\n[www-height]""">

. \} . \} . el \{\ @@ -687,7 +708,7 @@ . . nr www-width 1i . nr www-height 1i -. ds www-size-specs width=\\n[www-width] height=\\n[www-height]\" +. ds www-size-specs width=""\\n[www-width]" height="\\n[www-height]" . ie !'\\$2'' \{\ . nr www-is-absolute 0 . nr www-absolute 0 @@ -698,13 +719,13 @@ . nr www-width (\\n[www-absolute] * \\n[.l] / 100) . if \\n[www-html] \ . nr www-width (\\n[www-width] * 100 / 240) -. ds www-size-specs width=\\*[www-percentage]\" +. ds www-size-specs width=\"\\*[www-percentage]" . \} . el \{\ . nr www-width \\n[www-absolute] . if \\n[www-html] \ . nr www-width (\\n[www-width] * 100 / 240) -. ds www-size-specs width=\\n[www-width]\" +. ds www-size-specs width=\"\\n[www-width]" . \} . . nr www-height \\n[www-width] @@ -718,13 +739,13 @@ . nr www-height (\\n[www-absolute] * \\n[.p] / 100) . if \\n[www-html] \ . nr www-height (\\n[www-height] * 100 / 240) -. ds www-size-specs \\*[www-size-specs] height=\\*[www-percentage]\" +. ds www-size-specs "\\*[www-size-specs] height="\\*[www-percentage]" . \} . el \{\ . nr www-height \\n[www-absolute] . if \\n[www-html] \ . nr www-height (\\n[www-height] * 100 / 240) -. ds www-size-specs \\*[www-size-specs] height=\\*[www-height]\" +. ds www-size-specs "\\*[www-size-specs] "height="\\*[www-height]" . \} . \} . \} @@ -732,11 +753,11 @@ . \" height not specified; use width value . ie !\\n[www-is-absolute] \{\ . \" percentage value -. ds www-size-specs \\*[www-size-specs] height=\\*[www-percentage]\" +. ds www-size-specs "\\*[www-size-specs] "height="\\*[www-percentage]" . nr www-height \\n[www-width] . \} . el \{\ -. ds www-size-specs \\*[www-size-specs] height=\\*[www-width]\" +. ds www-size-specs "\\*[www-size-specs] "height="\\*[www-width]" . nr www-height \\n[www-width] . \} . \} @@ -745,13 +766,13 @@ . ie !\\n[www-image-just] \ . HTML + "hspace=""\\n[www-htmlimage-gap]""" \ + "align=""right"" \\*[www-size-specs]"""> . el \ . HTML + "hspace=""\\n[www-htmlimage-gap]""" \ + "align=""left"" \\*[www-size-specs]"""> . \} . el \{\ . tm www-width is \\n[www-width] @@ -851,7 +872,7 @@ .\" Produce a horizontal line. .\" .de HR -. HTML


+. HTML


.. . .\" -------------------------------------------------------------------- @@ -933,6 +954,7 @@ .de www-push-li . nr www-depth +1 . ds www-level\\n[www-depth] \\$1\" +. ds www-ltag\\n[www-depth] . als LI \\$1 .. . @@ -941,6 +963,18 @@ . als LI \\*[www-level\\n[www-depth]] .. . +.\" www-emit-ltag - shuts down a previous open list tag +.\" before issuing a new tag \\$1. +.\" It then records tag \\$1 is open. +. +.de www-emit-ltag +. if !'\\*[www-ltag\\n[www-depth]]'' \ +. HTML-NS +. if !'\\$1'' \ +. HTML-NS <\\$1> +. ds www-ltag\\n[www-depth] \\$1 +.. +. .\" .\" Auxiliary macro for ULS. .\" @@ -984,11 +1018,12 @@ .de ULS . www-push-li www-li-ul . www-push-ul-level -. ie \\n[www-html] \ +. ie \\n[www-html] \{\ +. www-emit-ltag . HTML

+. ie \\n[www-html] \{\ +. www-emit-ltag +. HTML

+. \} . el \{\ . nr www-li-indent -\w'\\*[www-ul-level\\n[www-ul-level]]'u . in \\n[www-li-indent]u @@ -1015,9 +1052,11 @@ .de OLS . www-push-li www-li-ol . www-push-ol-level -. ie \\n[www-html] \ +. ie \\n[www-html] \{\ +. www-emit-ltag . HTML

    " +. \} . el \ . nr www-li-indent +\w'\\*[www-ol-tmp]'u .. @@ -1028,8 +1067,10 @@ .\" End an ordered list. .\" .de OLE -. ie \\n[www-html] \ +. ie \\n[www-html] \{\ +. www-emit-ltag . HTML
+. \} . el \{\ . nr www-li-indent -\w'\\*[www-ol-tmp]'u . in \\n[www-li-indent]u @@ -1047,8 +1088,10 @@ .de DLS . www-push-li www-li-dl . nr www-dl-level +1 -. ie \\n[www-html] \ +. ie \\n[www-html] \{\ +. www-emit-ltag . HTML

+. \} . el \{\ . nr www-li-indent +\\n[www-dl-shift]u . in \\n[www-li-indent]u @@ -1061,8 +1104,10 @@ .\" End a definition list. .\" .de DLE -. ie \\n[www-html] \ +. ie \\n[www-html] \{\ +. www-emit-ltag . HTML
+. \} . el \{\ . nr www-li-indent -\\n[www-dl-shift]u . in \\n[www-li-indent]u @@ -1081,7 +1126,7 @@ .\" .de www-li-ul . ie \\n[www-html] \ -. HTML-NS
  • +. www-emit-ltag li . el \{\ . www:paraspace . in \\n[www-li-indent]u @@ -1095,7 +1140,7 @@ .\" .de www-li-ol . ie \\n[www-html] \ -. HTML-NS
  • +. www-emit-ltag li . el \{\ . www:paraspace . in \\n[www-li-indent]u @@ -1110,7 +1155,7 @@ .de www-li-dl . ie \\n[www-html] \{\ . HTML
    \\$1
    -. HTML-NS
    +. www-emit-ltag dd . \} . el \{\ . www:paraspace @@ -1179,8 +1224,8 @@ .\" .do if !d TS .do ds TS HTML-IMAGE\" .do if !d TE .do ds TE HTML-IMAGE-END\" -.do if !d EQ .do ds EQ HTML-IMAGE\" -.do if !d EN .do ds EN HTML-IMAGE-END\" +.do if !d EQ .do ds EQ EQN-HTML-IMAGE\" +.do if !d EN .do ds EN EQN-HTML-IMAGE-END\" . .\" .\" supplementary macros used by other macro sets @@ -1245,6 +1290,61 @@ . HTML-DO-IMAGE \\*[www-unique-name] i .. . +.\" EQN-HTML-IMAGE and friends check to see whether the equation is +.\" not in an image, in which case it allows html +.\" (mathml) to be generated (if -Txhtml was specified). +. +.de EQN-HTML-IMAGE +. \" generates a centered image +. www-make-unique-name +. EQN-HTML-DO-IMAGE \\*[www-unique-name] c +.. +. +.de EQN-HTML-IMAGE-RIGHT +. www-make-unique-name +. EQN-HTML-DO-IMAGE \\*[www-unique-name] r +.. +. +.de EQN-HTML-IMAGE-LEFT +. www-make-unique-name +. EQN-HTML-DO-IMAGE \\*[www-unique-name] l +.. +. +.de EQN-HTML-IMAGE-INLINE +. www-make-unique-name +. EQN-HTML-DO-IMAGE \\*[www-unique-name] i +.. +.\" -------------------------------------------------------------------- +.\" EQN-HTML-DO-IMAGE - tells troff to issue an image marker which can be +.\" read back by pre-html +.\" +.de EQN-HTML-DO-IMAGE +. ie r xhtml \{\ +. if !(\\n[.O] == 0) \{\ +. if r ps4html \ +. nop \O[5\\$2\\$1.png]\O[1]\O[3] +. if \\n[www-html] \ +. nop \O[5\\$2\\$1.png]\O[0]\O[3] +. \} +. \} +. el .HTML-DO-IMAGE \\$* +.. +. +.\" -------------------------------------------------------------------- +.\" EQN-HTML-IMAGE-END - terminates an image for html +.\" +.de EQN-HTML-IMAGE-END +. ie r xhtml \{\ +. if !(\\n[.O] == 0) \{\ +. if r ps4html \ +. nop \O[4]\O[2]\O[0] +. if \\n[www-html] \ +. nop \O[4]\O[2]\O[1] +. \} +. \} +. el .HTML-IMAGE-END +.. +. .\" -------------------------------------------------------------------- .\" JOBNAME .\" @@ -1389,6 +1489,13 @@ . ds www:close \\$2\" .. . +.\" MATHML - enable eqn mathml output to pass through to the device +.\" driver +. +.de MATHML +. if (\\n[.O] == 0) .MATH \\$* +.. +. .\" -------------------------------------------------------------------- .\" Final Setup .\" -------------------------------------------------------------------- --- groff-cvs/NEWS 2007-07-11 22:10:15.000000000 +0100 +++ groff-html/NEWS 2007-09-19 11:57:55.000000000 +0100 @@ -14,6 +14,13 @@ Groff ----- +o 'xhtml' support has been added to grohtml and can be specified by + -Txhtml. This option will also utilize the MathML capability of + eqn and combine the outputs of both in the final xhtml file. + Users can also specify the '-P-V' option together with '-Txhtml' + in groff. This has the effect of creating a 'xhtml' validator + button at the bottom of each page. + o Two new requests `device' and `devicem' have been added which are equivalents to the \X and \Y escapes, respectively.