Current Path : /usr/src/contrib/groff/src/devices/grohtml/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //usr/src/contrib/groff/src/devices/grohtml/html-text.cpp |
// -*- C++ -*- /* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 * Free Software Foundation, Inc. * * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp * * html-text.cpp * * provide a troff like state machine interface which * generates html text. */ /* This file is part of groff. groff is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. groff is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with groff; see the file COPYING. If not, write to the Free Software Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ #include "driver.h" #include "stringclass.h" #include "cset.h" #if !defined(TRUE) # define TRUE (1==1) #endif #if !defined(FALSE) # define FALSE (1==0) #endif #include "html-text.h" #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 () { 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. */ void html_text::end_tag (tag_definition *t) { switch (t->type) { case I_TAG: out->put_string("</i>"); break; case B_TAG: out->put_string("</b>"); break; case P_TAG: if (t->indent == NULL) { out->put_string("</p>"); } else { delete t->indent; t->indent = NULL; out->put_string("</p>"); } 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->enable_newlines(TRUE); blank_para = TRUE; if (t->indent != NULL) delete t->indent; t->indent = NULL; break; case SMALL_TAG: out->put_string("</small>"); break; case BIG_TAG: out->put_string("</big>"); break; case COLOR_TAG: out->put_string("</font>"); break; default: error("unrecognised tag"); } } /* * issue_tag - writes out an html tag with argument. * space == 0 if no space is requested * space == 1 if a space is requested * space == 2 if tag should not have a space style */ void html_text::issue_tag (const char *tagname, const char *arg, int space) { if ((arg == 0) || (strlen(arg) == 0)) out->put_string(tagname); else { out->put_string(tagname); out->put_string(" "); out->put_string(arg); } if (space == TRUE) { out->put_string(" style=\"margin-top: "); out->put_string(STYLE_VERTICAL_SPACE); out->put_string("\""); } if (space == TRUE || space == FALSE) out->put_string(" valign=\"top\""); out->put_string(">"); } /* * 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. */ void html_text::start_tag (tag_definition *t) { switch (t->type) { 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(); #if defined(DEBUGGING) out->simple_comment("INDENTATION"); #endif out->put_string("\n<p"); t->indent->begin(start_space); issue_tag("", (char *)t->arg1); } else { out->nl(); issue_tag("\n<p", (char *)t->arg1, start_space); } out->enable_newlines(TRUE); break; 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: out->enable_newlines(TRUE); out->nl(); out->put_string("<pre"); if (t->indent == NULL) issue_tag("", (char *)t->arg1, start_space); else { t->indent->begin(start_space); issue_tag("", (char *)t->arg1); } out->enable_newlines(FALSE); 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"); } } /* * flush_text - flushes html tags which are outstanding on the html stack. */ void html_text::flush_text (void) { int notext=TRUE; tag_definition *p=stackptr; while (stackptr != 0) { notext = (notext && (! stackptr->text_emitted)); if (! notext) { end_tag(stackptr); } p = stackptr; stackptr = stackptr->next; delete p; } lastptr = NULL; } /* * is_present - returns TRUE if tag is already present on the stack. */ int html_text::is_present (HTML_TAG t) { tag_definition *p=stackptr; while (p != NULL) { if (t == p->type) return TRUE; p = p->next; } 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(); /* * do_push - places, tag_definition, p, onto the stack */ void html_text::do_push (tag_definition *p) { HTML_TAG t = p->type; #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 PRE_TAG make sure it goes on the end of the stack. */ 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 } /* * push_para - adds a new entry onto the html paragraph stack. */ void html_text::push_para (HTML_TAG t, void *arg, html_indent *in) { tag_definition *p= new 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::push_para (HTML_TAG t) { push_para(t, (void *)"", NULL); } void html_text::push_para (color *c) { tag_definition *p = new tag_definition; p->type = COLOR_TAG; p->arg1 = NULL; p->col = *c; p->text_emitted = FALSE; p->indent = NULL; do_push(p); } /* * do_italic - changes to italic */ void html_text::do_italic (void) { if (! is_present(I_TAG)) push_para(I_TAG); } /* * do_bold - changes to bold. */ void html_text::do_bold (void) { if (! is_present(B_TAG)) push_para(B_TAG); } /* * do_tt - changes to teletype. */ void html_text::do_tt (void) { if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) push_para(TT_TAG); } /* * do_pre - changes to preformated text. */ void html_text::do_pre (void) { done_tt(); if (is_present(P_TAG)) { html_indent *i = remove_indent(P_TAG); int space = retrieve_para_space(); (void)done_para(); if (! is_present(PRE_TAG)) push_para(PRE_TAG, NULL, i); start_space = space; } else if (! is_present(PRE_TAG)) push_para(PRE_TAG, NULL, NULL); dump_stack(); } /* * is_in_pre - returns TRUE if we are currently within a preformatted * <pre> block. */ int html_text::is_in_pre (void) { 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); } /* * done_color - shutdown an outstanding color tag, if it exists. */ void html_text::done_color (void) { shutdown(COLOR_TAG); } /* * shutdown - shuts down an html tag. */ char *html_text::shutdown (HTML_TAG t) { char *arg=NULL; if (is_present(t)) { tag_definition *p =stackptr; tag_definition *temp =NULL; int notext =TRUE; dump_stack(); while ((stackptr != NULL) && (stackptr->type != t)) { notext = (notext && (! stackptr->text_emitted)); if (! notext) { end_tag(stackptr); } /* * pop tag */ p = stackptr; stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; /* * push tag onto temp stack */ p->next = temp; temp = p; } /* * and examine stackptr */ if ((stackptr != NULL) && (stackptr->type == t)) { if (stackptr->text_emitted) { end_tag(stackptr); } if (t == P_TAG) { arg = (char *)stackptr->arg1; } p = stackptr; stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; if (p->indent != NULL) delete p->indent; delete p; } /* * and restore unaffected tags */ while (temp != NULL) { if (temp->type == COLOR_TAG) push_para(&temp->col); else push_para(temp->type, temp->arg1, temp->indent); p = temp; temp = temp->next; delete p; } } return arg; } /* * done_bold - shuts downs a bold tag. */ void html_text::done_bold (void) { shutdown(B_TAG); } /* * done_italic - shuts downs an italic tag. */ void html_text::done_italic (void) { shutdown(I_TAG); } /* * done_sup - shuts downs a sup tag. */ void html_text::done_sup (void) { shutdown(SUP_TAG); } /* * done_sub - shuts downs a sub tag. */ void html_text::done_sub (void) { shutdown(SUB_TAG); } /* * done_tt - shuts downs a tt tag. */ void html_text::done_tt (void) { shutdown(TT_TAG); } /* * done_pre - shuts downs a pre tag. */ void html_text::done_pre (void) { shutdown(PRE_TAG); } /* * done_small - shuts downs a small tag. */ void html_text::done_small (void) { shutdown(SMALL_TAG); } /* * done_big - shuts downs a big tag. */ void html_text::done_big (void) { shutdown(BIG_TAG); } /* * check_emit_text - ensures that all previous tags have been emitted (in order) * before the text is written. */ void html_text::check_emit_text (tag_definition *t) { if ((t != NULL) && (! t->text_emitted)) { check_emit_text(t->next); t->text_emitted = TRUE; start_tag(t); } } /* * do_emittext - tells the class that text was written during the current tag. */ void html_text::do_emittext (const char *s, int length) { if ((! is_present(P_TAG)) && (! is_present(PRE_TAG))) do_para("", FALSE); if (is_present(BREAK_TAG)) { int text = remove_break(); check_emit_text(stackptr); if (text) { if (is_present(PRE_TAG)) { out->nl(); } else out->put_string("<br>").nl(); } } else check_emit_text(stackptr); out->put_string(s, length); space_emitted = FALSE; blank_para = FALSE; } /* * do_para - starts a new paragraph */ void html_text::do_para (const char *arg, html_indent *in, int space) { if (! is_present(P_TAG)) { if (is_present(PRE_TAG)) { html_indent *i = remove_indent(PRE_TAG); done_pre(); 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); start_space = space; } } void html_text::do_para (const char *arg, int space) { do_para(arg, NULL, space); } void html_text::do_para (simple_output *op, const char *arg1, int indentation_value, int page_offset, int line_length, int space) { html_indent *ind; if (indentation_value == 0) ind = NULL; else ind = new html_indent(op, indentation_value, page_offset, line_length); do_para(arg1, ind, space); } /* * done_para - shuts down a paragraph tag. */ char *html_text::done_para (void) { char *result; space_emitted = TRUE; result = shutdown(P_TAG); start_space = FALSE; return result; } /* * 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; } /* * remove_para_space - removes the leading space to a paragraph * (effectively this trims off a leading `.sp' tag). */ 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()) { do_emittext("", 0); out->force_nl(); space_emitted = TRUE; } else { html_indent *i = remove_indent(P_TAG); do_para(done_para(), i, TRUE); space_emitted = TRUE; } } /* * do_break - issue a break tag. */ void html_text::do_break (void) { if (! is_present(PRE_TAG)) if (emitted_text()) if (! is_present(BREAK_TAG)) push_para(BREAK_TAG); space_emitted = TRUE; } /* * do_newline - issue a newline providing that we are inside a <pre> tag. */ void html_text::do_newline (void) { if (is_present(PRE_TAG)) { do_emittext("\n", 1); space_emitted = TRUE; } } /* * emitted_text - returns FALSE if white space has just been written. */ int html_text::emitted_text (void) { 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 started this paragraph with a .sp */ int html_text::starts_with_space (void) { return start_space; } /* * retrieve_para_space - returns TRUE, if the paragraph starts with * a space and text has not yet been emitted. * If TRUE is returned, then the, start_space, * variable is set to FALSE. */ int html_text::retrieve_para_space (void) { if (start_space && blank_para) { start_space = FALSE; return TRUE; } else return FALSE; } /* * emit_space - writes a space providing that text was written beforehand. */ void html_text::emit_space (void) { if (is_present(PRE_TAG)) do_emittext(" ", 1); else out->space_or_newline(); space_emitted = TRUE; } /* * remove_def - removes a definition, t, from the stack. */ void html_text::remove_def (tag_definition *t) { tag_definition *p = stackptr; tag_definition *l = 0; tag_definition *q = 0; while ((p != 0) && (p != t)) { l = p; p = p->next; } if ((p != 0) && (p == t)) { if (p == stackptr) { stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; q = stackptr; } else if (l == 0) { error("stack list pointers are wrong"); } else { l->next = p->next; q = p->next; if (l->next == NULL) lastptr = l; } delete p; } } /* * remove_tag - removes a tag from the stack. */ void html_text::remove_tag (HTML_TAG tag) { tag_definition *p = stackptr; while ((p != 0) && (p->type != tag)) { p = p->next; } if ((p != 0) && (p->type == tag)) remove_def(p); } /* * remove_sub_sup - removes a sub or sup tag, should either exist * on the stack. */ void html_text::remove_sub_sup (void) { if (is_present(SUB_TAG)) { remove_tag(SUB_TAG); } if (is_present(SUP_TAG)) { remove_tag(SUP_TAG); } if (is_present(PRE_TAG)) { remove_tag(PRE_TAG); } } /* * remove_break - break tags are not balanced thus remove it once it has been emitted. * It returns TRUE if text was emitted before the <br> was issued. */ int html_text::remove_break (void) { tag_definition *p = stackptr; tag_definition *l = 0; tag_definition *q = 0; while ((p != 0) && (p->type != BREAK_TAG)) { l = p; p = p->next; } if ((p != 0) && (p->type == BREAK_TAG)) { if (p == stackptr) { stackptr = stackptr->next; if (stackptr == NULL) lastptr = NULL; q = stackptr; } else if (l == 0) error("stack list pointers are wrong"); else { l->next = p->next; q = p->next; if (l->next == NULL) lastptr = l; } delete p; } /* * now determine whether text was issued before <br> */ while (q != 0) { 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); int space = retrieve_para_space(); done_para(); do_para("", i, space); return; } p = p->next; } } } /* * 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 (char *)""; } /* * 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. */ void html_text::do_small (void) { if (is_present(BIG_TAG)) done_big(); else push_para(SMALL_TAG); } /* * do_big - is the mirror image of do_small. */ void html_text::do_big (void) { if (is_present(SMALL_TAG)) done_small(); else push_para(BIG_TAG); } /* * do_sup - save a superscript tag on the stack of tags. */ void html_text::do_sup (void) { push_para(SUP_TAG); } /* * do_sub - save a subscript tag on the stack of tags. */ void html_text::do_sub (void) { push_para(SUB_TAG); }