diff options
Diffstat (limited to 'contrib/groff/src/devices/grohtml/html-text.cc')
-rw-r--r-- | contrib/groff/src/devices/grohtml/html-text.cc | 581 |
1 files changed, 358 insertions, 223 deletions
diff --git a/contrib/groff/src/devices/grohtml/html-text.cc b/contrib/groff/src/devices/grohtml/html-text.cc index 56d6c78..31e4311 100644 --- a/contrib/groff/src/devices/grohtml/html-text.cc +++ b/contrib/groff/src/devices/grohtml/html-text.cc @@ -1,5 +1,5 @@ // -*- C++ -*- -/* Copyright (C) 2000, 2001 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cc * @@ -40,10 +40,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "html-text.h" +// #define DEBUGGING html_text::html_text (simple_output *op) : stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE), - current_indentation(-1), pageoffset(-1), linelength(-1) + current_indentation(-1), pageoffset(-1), linelength(-1), + blank_para(TRUE), start_space(FALSE) { } @@ -52,6 +54,87 @@ html_text::~html_text () flush_text(); } + +#if defined(DEBUGGING) +static int debugStack = FALSE; + + +/* + * turnDebug - flip the debugStack boolean and return the new value. + */ + +static int turnDebug (void) +{ + debugStack = 1-debugStack; + return debugStack; +} + +/* + * dump_stack_element - display an element of the html stack, p. + */ + +void html_text::dump_stack_element (tag_definition *p) +{ + fprintf(stderr, " | "); + switch (p->type) { + + case P_TAG: if (p->indent == NULL) { + fprintf(stderr, "<P %s>", (char *)p->arg1); break; + } else { + fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break; + } + case I_TAG: fprintf(stderr, "<I>"); break; + case B_TAG: fprintf(stderr, "<B>"); break; + case SUB_TAG: fprintf(stderr, "<SUB>"); break; + case SUP_TAG: fprintf(stderr, "<SUP>"); break; + case TT_TAG: fprintf(stderr, "<TT>"); break; + case PRE_TAG: if (p->indent == NULL) { + fprintf(stderr, "<PRE>"); break; + } else { + fprintf(stderr, "<PRE [TABLE]>"); break; + } + case SMALL_TAG: fprintf(stderr, "<SMALL>"); break; + case BIG_TAG: fprintf(stderr, "<BIG>"); break; + case BREAK_TAG: fprintf(stderr, "<BREAK>"); break; + case COLOR_TAG: { + if (p->col.is_default()) + fprintf(stderr, "<COLOR (default)>"); + else { + unsigned int r, g, b; + + p->col.get_rgb(&r, &g, &b); + fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101); + } + break; + } + default: fprintf(stderr, "unknown tag"); + } + if (p->text_emitted) + fprintf(stderr, "[t] "); +} + +/* + * dump_stack - debugging function only. + */ + +void html_text::dump_stack (void) +{ + if (debugStack) { + tag_definition *p = stackptr; + + while (p != NULL) { + dump_stack_element(p); + p = p->next; + } + } + fprintf(stderr, "\n"); + fflush(stderr); +} +#else +void html_text::dump_stack (void) {} +#endif + + /* * end_tag - shuts down the tag. */ @@ -62,19 +145,21 @@ void html_text::end_tag (tag_definition *t) case I_TAG: out->put_string("</i>"); break; case B_TAG: out->put_string("</b>"); break; - case P_TAG: out->put_string("</p>").nl().enable_newlines(FALSE); break; + case P_TAG: out->put_string("</p>"); + if (t->indent != NULL) { + delete t->indent; + t->indent = NULL; + } + out->nl(); out->enable_newlines(FALSE); + blank_para = TRUE; break; case SUB_TAG: out->put_string("</sub>"); break; case SUP_TAG: out->put_string("</sup>"); break; case TT_TAG: out->put_string("</tt>"); break; - case PRE_TAG: out->put_string("</pre>"); - if (! is_present(TABLE_TAG)) { - out->nl(); - out->enable_newlines(TRUE); - } - break; + case PRE_TAG: out->put_string("</pre>"); out->nl(); out->enable_newlines(TRUE); + blank_para = TRUE; break; case SMALL_TAG: out->put_string("</small>"); break; case BIG_TAG: out->put_string("</big>"); break; - case TABLE_TAG: issue_table_end(); break; + case COLOR_TAG: out->put_string("</font>"); break; default: error("unrecognised tag"); @@ -99,6 +184,27 @@ void html_text::issue_tag (char *tagname, char *arg) } /* + * issue_color_begin - writes out an html color tag. + */ + +void html_text::issue_color_begin (color *c) +{ + unsigned int r, g, b; + char buf[6+1]; + + out->put_string("<font color=\"#"); + if (c->is_default()) + sprintf(buf, "000000"); + else { + c->get_rgb(&r, &g, &b); + // we have to scale 0..0xFFFF to 0..0xFF + sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); + } + out->put_string(buf); + out->put_string("\">"); +} + +/* * start_tag - starts a tag. */ @@ -106,60 +212,42 @@ void html_text::start_tag (tag_definition *t) { switch (t->type) { - case I_TAG: issue_tag("<i", t->arg1); break; - case B_TAG: issue_tag("<b", t->arg1); break; - case P_TAG: issue_tag("\n<p", t->arg1); + case I_TAG: issue_tag("<i", (char *)t->arg1); break; + case B_TAG: issue_tag("<b", (char *)t->arg1); break; + case P_TAG: if (t->indent == NULL) { + out->nl(); + issue_tag("\n<p", (char *)t->arg1); + } else { + out->nl(); + out->simple_comment("INDENTATION"); + t->indent->begin(FALSE); + start_space = FALSE; + issue_tag("<p", (char *)t->arg1); + } + out->enable_newlines(TRUE); break; - case SUB_TAG: issue_tag("<sub", t->arg1); break; - case SUP_TAG: issue_tag("<sup", t->arg1); break; - case TT_TAG: issue_tag("<tt", t->arg1); break; - case PRE_TAG: out->nl(); issue_tag("<pre", t->arg1); + case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break; + case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break; + case TT_TAG: issue_tag("<tt", (char *)t->arg1); break; + case PRE_TAG: if (t->indent != NULL) { + out->nl(); + out->simple_comment("INDENTATION"); + t->indent->begin(FALSE); + start_space = FALSE; + } + out->enable_newlines(TRUE); + out->nl(); issue_tag("<pre", (char *)t->arg1); out->enable_newlines(FALSE); break; - case SMALL_TAG: issue_tag("<small", t->arg1); break; - case BIG_TAG: issue_tag("<big", t->arg1); break; - case TABLE_TAG: issue_table_begin(t); break; + case SMALL_TAG: issue_tag("<small", (char *)t->arg1); break; + case BIG_TAG: issue_tag("<big", (char *)t->arg1); break; case BREAK_TAG: break; + case COLOR_TAG: issue_color_begin(&t->col); break; default: error("unrecognised tag"); } } -int html_text::table_is_void (tag_definition *t) -{ - if (linelength > 0) { - return( current_indentation*100/linelength <= 0 ); - } else { - return( FALSE ); - } -} - -void html_text::issue_table_begin (tag_definition *t) -{ - if (linelength > 0) { - int width=current_indentation*100/linelength; - - if (width > 0) { - out->put_string("<table width=\"100%\" border=0 rules=\"none\" frame=\"void\"\n cols=\"2\" cellspacing=\"0\" cellpadding=\"0\">").nl(); - out->put_string("<tr valign=\"top\" align=\"left\">").nl(); - if ((t->arg1 == 0) || (strcmp(t->arg1, "") == 0)) - out->put_string("<td width=\"").put_number(width).put_string("%\"></td>"); - else { - out->put_string("<td width=\"").put_number(width).put_string("%\">").nl(); - out->put_string(t->arg1).put_string("</td>"); - t->arg1[0] = (char)0; - } - out->put_string("<td width=\"").put_number(100-width).put_string("%\">").nl(); - } - } -} - -void html_text::issue_table_end (void) -{ - out->put_string("</td></table>").nl(); - out->enable_newlines(TRUE); -} - /* * flush_text - flushes html tags which are outstanding on the html stack. */ @@ -190,116 +278,94 @@ int html_text::is_present (HTML_TAG t) tag_definition *p=stackptr; while (p != NULL) { - if (t == p->type) { - return( TRUE ); - } + if (t == p->type) + return TRUE; p = p->next; } - return( FALSE ); + return FALSE; } +extern void stop(); + /* - * push_para - adds a new entry onto the html paragraph stack. + * do_push - places, tag_definition, p, onto the stack */ -void html_text::push_para (HTML_TAG t, char *arg) +void html_text::do_push (tag_definition *p) { - tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + HTML_TAG t = p->type; - p->type = t; - p->arg1 = arg; - p->text_emitted = FALSE; +#if defined(DEBUGGING) + if (t == PRE_TAG) + stop(); + debugStack = TRUE; + fprintf(stderr, "\nentering do_push ("); + dump_stack_element(p); + fprintf(stderr, ")\n"); + dump_stack(); + fprintf(stderr, ")\n"); + fflush(stderr); +#endif /* - * if t is a P_TAG or TABLE_TAG or PRE_TAG make sure it goes on the end of the stack. - * But we insist that a TABLE_TAG is always after a PRE_TAG - * and that a P_TAG is always after a TABLE_TAG + * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack. */ - if (((t == P_TAG) || (t == PRE_TAG) || (t == TABLE_TAG)) && - (lastptr != NULL)) { - if (((lastptr->type == TABLE_TAG) && (t == PRE_TAG)) || - ((lastptr->type == P_TAG) && (t == TABLE_TAG))) { - /* - * insert p before the lastptr - */ - if (stackptr == lastptr) { - /* - * only on element of the stack - */ - p->next = stackptr; - stackptr = p; - } else { - /* - * more than one element is on the stack - */ - tag_definition *q = stackptr; - - while (q->next != lastptr) { - q = q->next; - } - q->next = p; - p->next = lastptr; - } - } else { - /* - * store, p, at the end - */ - lastptr->next = p; - lastptr = p; - p->next = NULL; - } + if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) { + /* + * store, p, at the end + */ + lastptr->next = p; + lastptr = p; + p->next = NULL; } else { p->next = stackptr; if (stackptr == NULL) lastptr = p; stackptr = p; } + +#if defined(DEBUGGING) + dump_stack(); + fprintf(stderr, "exiting do_push\n"); +#endif } /* - * do_indent - remember the indent parameters and if - * indent is > pageoff and indent has changed - * then we start a html table to implement the indentation. + * push_para - adds a new entry onto the html paragraph stack. */ -void html_text::do_indent (char *arg, int indent, int pageoff, int linelen) +void html_text::push_para (HTML_TAG t, void *arg, html_indent *in) { - if ((current_indentation != -1) && - (pageoffset+current_indentation != indent+pageoff)) { - /* - * actual indentation of text has changed, we need to put - * a table tag onto the stack. - */ - do_table(arg); - } - current_indentation = indent; - pageoffset = pageoff; - linelength = linelen; + tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + + p->type = t; + p->arg1 = arg; + p->text_emitted = FALSE; + p->indent = in; + + if (t == PRE_TAG && is_present(PRE_TAG)) + fatal("cannot have multiple PRE_TAGs"); + + do_push(p); } -void html_text::do_table (char *arg) +void html_text::push_para (HTML_TAG t) { - int in_pre = is_in_pre(); - // char *para_type = done_para(); - done_pre(); - shutdown(TABLE_TAG); // shutdown a previous table, if present - remove_break(); - if (in_pre) { - do_pre(); - } - // do_para(para_type); - push_para(TABLE_TAG, arg); + push_para(t, (void *)"", NULL); } -/* - * done_table - terminates a possibly existing table. - */ - -void html_text::done_table (void) +void html_text::push_para (color *c) { - shutdown(TABLE_TAG); - space_emitted = TRUE; + tag_definition *p=(tag_definition *)malloc(sizeof(tag_definition)); + + p->type = COLOR_TAG; + p->arg1 = NULL; + p->col = *c; + p->text_emitted = FALSE; + p->indent = NULL; + + do_push(p); } /* @@ -308,11 +374,8 @@ void html_text::done_table (void) void html_text::do_italic (void) { - done_bold(); - done_tt(); - if (! is_present(I_TAG)) { - push_para(I_TAG, ""); - } + if (! is_present(I_TAG)) + push_para(I_TAG); } /* @@ -321,11 +384,8 @@ void html_text::do_italic (void) void html_text::do_bold (void) { - done_italic(); - done_tt(); - if (! is_present(B_TAG)) { - push_para(B_TAG, ""); - } + if (! is_present(B_TAG)) + push_para(B_TAG); } /* @@ -334,11 +394,8 @@ void html_text::do_bold (void) void html_text::do_tt (void) { - done_bold(); - done_italic(); - if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) { - push_para(TT_TAG, ""); - } + if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) + push_para(TT_TAG); } /* @@ -347,13 +404,15 @@ void html_text::do_tt (void) void html_text::do_pre (void) { - done_bold(); - done_italic(); done_tt(); - (void)done_para(); - if (! is_present(PRE_TAG)) { - push_para(PRE_TAG, ""); - } + if (is_present(P_TAG)) { + html_indent *i = remove_indent(P_TAG); + (void)done_para(); + if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, i); + } else if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, NULL); + dump_stack(); } /* @@ -363,16 +422,26 @@ void html_text::do_pre (void) int html_text::is_in_pre (void) { - return( is_present(PRE_TAG) ); + return is_present(PRE_TAG); +} + +/* + * do_color - initiates a new color tag. + */ + +void html_text::do_color (color *c) +{ + shutdown(COLOR_TAG); // shutdown a previous color tag, if present + push_para(c); } /* - * is_in_table - returns TRUE if we are currently within a table. + * done_color - shutdown an outstanding color tag, if it exists. */ -int html_text::is_in_table (void) +void html_text::done_color (void) { - return( is_present(TABLE_TAG) ); + shutdown(COLOR_TAG); } /* @@ -388,6 +457,7 @@ char *html_text::shutdown (HTML_TAG t) tag_definition *temp =NULL; int notext =TRUE; + dump_stack(); while ((stackptr != NULL) && (stackptr->type != t)) { notext = (notext && (! stackptr->text_emitted)); if (! notext) { @@ -417,12 +487,14 @@ char *html_text::shutdown (HTML_TAG t) end_tag(stackptr); } if (t == P_TAG) { - arg = stackptr->arg1; + arg = (char *)stackptr->arg1; } p = stackptr; stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; + if (p->indent != NULL) + delete p->indent; free(p); } @@ -430,13 +502,16 @@ char *html_text::shutdown (HTML_TAG t) * and restore unaffected tags */ while (temp != NULL) { - push_para(temp->type, temp->arg1); + if (temp->type == COLOR_TAG) + push_para(&temp->col); + else + push_para(temp->type, temp->arg1, temp->indent); p = temp; temp = temp->next; free(p); } } - return( arg ); + return arg; } /* @@ -519,37 +594,9 @@ void html_text::done_big (void) void html_text::check_emit_text (tag_definition *t) { if ((t != NULL) && (! t->text_emitted)) { - /* - * we peep and see whether there is a <p> before the <table> - * in which case we skip the <p> - */ - if (t->type == TABLE_TAG) { - if (table_is_void(t)) { - tag_definition *n = t->next; - remove_def(t); - check_emit_text(n); - } else { - /* - * a table which will be emitted, is there a <p> succeeding it? - */ - if ((t->next != NULL) && - (t->next->type == P_TAG) && - ((t->next->arg1 == 0) || strcmp(t->next->arg1, "") == 0)) { - /* - * yes skip the <p> - */ - check_emit_text(t->next->next); - } else { - check_emit_text(t->next); - } - t->text_emitted = TRUE; - start_tag(t); - } - } else { - check_emit_text(t->next); - t->text_emitted = TRUE; - start_tag(t); - } + check_emit_text(t->next); + t->text_emitted = TRUE; + start_tag(t); } } @@ -557,7 +604,7 @@ void html_text::check_emit_text (tag_definition *t) * do_emittext - tells the class that text was written during the current tag. */ -void html_text::do_emittext (char *s, int length) +void html_text::do_emittext (const char *s, int length) { if ((! is_present(P_TAG)) && (! is_present(PRE_TAG))) do_para(""); @@ -577,25 +624,47 @@ void html_text::do_emittext (char *s, int length) } out->put_string(s, length); space_emitted = FALSE; + blank_para = FALSE; } /* - * do_para- starts a new paragraph + * do_para - starts a new paragraph */ -void html_text::do_para (char *arg) +void html_text::do_para (const char *arg, html_indent *in) { - done_pre(); if (! is_present(P_TAG)) { - remove_sub_sup(); - if ((arg != 0) && (strcmp(arg, "") != 0)) { - remove_tag(TABLE_TAG); + if (is_present(PRE_TAG)) { + html_indent *i = remove_indent(PRE_TAG); + done_pre(); + if (i == in || in == NULL) + in = i; + else + delete i; } - push_para(P_TAG, arg); + remove_sub_sup(); + push_para(P_TAG, (void *)arg, in); space_emitted = TRUE; } } +void html_text::do_para (const char *arg) +{ + do_para(arg, NULL); +} + +void html_text::do_para (simple_output *op, const char *arg1, + int indentation, int pageoffset, int linelength) +{ + html_indent *indent; + + if (indentation == 0) + indent = NULL; + else + indent = new html_indent(op, indentation, pageoffset, linelength); + do_para(arg1, indent); +} + /* * done_para - shuts down a paragraph tag. */ @@ -603,7 +672,27 @@ void html_text::do_para (char *arg) char *html_text::done_para (void) { space_emitted = TRUE; - return( shutdown(P_TAG) ); + return shutdown(P_TAG); +} + +/* + * remove_indent - returns the indent associated with, tag. + * The indent associated with tag is set to NULL. + */ + +html_indent *html_text::remove_indent (HTML_TAG tag) +{ + tag_definition *p=stackptr; + + while (p != NULL) { + if (tag == p->type) { + html_indent *i = p->indent; + p->indent = NULL; + return i; + } + p = p->next; + } + return NULL; } /* @@ -613,11 +702,19 @@ char *html_text::done_para (void) void html_text::do_space (void) { if (is_in_pre()) { - do_emittext("", 0); + if (blank_para) + start_space = TRUE; + else { + do_emittext("", 0); + out->nl(); + } } else { - do_para(done_para()); + html_indent *i = remove_indent(P_TAG); + + do_para(done_para(), i); + space_emitted = TRUE; + start_space = TRUE; } - space_emitted = TRUE; } /* @@ -629,7 +726,7 @@ void html_text::do_break (void) if (! is_present(PRE_TAG)) { if (emitted_text()) { if (! is_present(BREAK_TAG)) { - push_para(BREAK_TAG, ""); + push_para(BREAK_TAG); } } } @@ -654,7 +751,25 @@ void html_text::do_newline (void) int html_text::emitted_text (void) { - return( ! space_emitted); + return !space_emitted; +} + +/* + * ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph. + */ + +int html_text::ever_emitted_text (void) +{ + return !blank_para; +} + +/* + * starts_with_space - returns TRUE if we have start this paragraph with a .sp + */ + +int html_text::starts_with_space (void) +{ + return start_space; } /* @@ -758,9 +873,9 @@ int html_text::remove_break (void) if (stackptr == NULL) lastptr = NULL; q = stackptr; - } else if (l == 0) { + } else if (l == 0) error("stack list pointers are wrong"); - } else { + else { l->next = p->next; q = p->next; if (l->next == NULL) @@ -772,13 +887,35 @@ int html_text::remove_break (void) * now determine whether text was issued before <br> */ while (q != 0) { - if (q->text_emitted) { - return( TRUE ); - } else { + if (q->text_emitted) + return TRUE; + else q = q->next; + } + return FALSE; +} + +/* + * remove_para_align - removes a paragraph which has a text + * argument. If the paragraph has no text + * argument then it is left alone. + */ + +void html_text::remove_para_align (void) +{ + if (is_present(P_TAG)) { + tag_definition *p=stackptr; + + while (p != NULL) { + if (p->type == P_TAG && p->arg1 != NULL) { + html_indent *i = remove_indent(P_TAG); + done_para(); + do_para("", i); + return; + } + p = p->next; } } - return( FALSE ); } /* @@ -789,11 +926,10 @@ int html_text::remove_break (void) void html_text::do_small (void) { - if (is_present(BIG_TAG)) { + if (is_present(BIG_TAG)) done_big(); - } else { - push_para(SMALL_TAG, ""); - } + else + push_para(SMALL_TAG); } /* @@ -802,11 +938,10 @@ void html_text::do_small (void) void html_text::do_big (void) { - if (is_present(SMALL_TAG)) { + if (is_present(SMALL_TAG)) done_small(); - } else { - push_para(BIG_TAG, ""); - } + else + push_para(BIG_TAG); } /* @@ -815,7 +950,7 @@ void html_text::do_big (void) void html_text::do_sup (void) { - push_para(SUP_TAG, ""); + push_para(SUP_TAG); } /* @@ -824,6 +959,6 @@ void html_text::do_sup (void) void html_text::do_sub (void) { - push_para(SUB_TAG, ""); + push_para(SUB_TAG); } |