2 /* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009
3 * Free Software Foundation, Inc.
5 * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp
9 * provide a troff like state machine interface which
10 * generates html text.
14 This file is part of groff.
16 groff is free software; you can redistribute it and/or modify it under
17 the terms of the GNU General Public License as published by the Free
18 Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
21 groff is distributed in the hope that it will be useful, but WITHOUT ANY
22 WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>. */
30 #include "stringclass.h"
41 #include "html-text.h"
46 html_text::html_text (simple_output *op, html_dialect d) :
47 stackptr(NULL), lastptr(NULL), out(op), dialect(d),
48 space_emitted(TRUE), current_indentation(-1),
49 pageoffset(-1), linelength(-1), blank_para(TRUE),
54 html_text::~html_text ()
60 #if defined(DEBUGGING)
61 static int debugStack = FALSE;
65 * turnDebug - flip the debugStack boolean and return the new value.
68 static int turnDebug (void)
70 debugStack = 1-debugStack;
75 * dump_stack_element - display an element of the html stack, p.
78 void html_text::dump_stack_element (tag_definition *p)
80 fprintf(stderr, " | ");
83 case P_TAG: if (p->indent == NULL) {
84 fprintf(stderr, "<P %s>", (char *)p->arg1); break;
86 fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
88 case I_TAG: fprintf(stderr, "<I>"); break;
89 case B_TAG: fprintf(stderr, "<B>"); break;
90 case SUB_TAG: fprintf(stderr, "<SUB>"); break;
91 case SUP_TAG: fprintf(stderr, "<SUP>"); break;
92 case TT_TAG: fprintf(stderr, "<TT>"); break;
93 case PRE_TAG: if (p->indent == NULL) {
94 fprintf(stderr, "<PRE>"); break;
96 fprintf(stderr, "<PRE [TABLE]>"); break;
98 case SMALL_TAG: fprintf(stderr, "<SMALL>"); break;
99 case BIG_TAG: fprintf(stderr, "<BIG>"); break;
100 case BREAK_TAG: fprintf(stderr, "<BREAK>"); break;
102 if (p->col.is_default())
103 fprintf(stderr, "<COLOR (default)>");
105 unsigned int r, g, b;
107 p->col.get_rgb(&r, &g, &b);
108 fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
112 default: fprintf(stderr, "unknown tag");
115 fprintf(stderr, "[t] ");
119 * dump_stack - debugging function only.
122 void html_text::dump_stack (void)
125 tag_definition *p = stackptr;
128 dump_stack_element(p);
132 fprintf(stderr, "\n");
136 void html_text::dump_stack (void) {}
141 * end_tag - shuts down the tag.
144 void html_text::end_tag (tag_definition *t)
148 case I_TAG: out->put_string("</i>"); break;
149 case B_TAG: out->put_string("</b>"); break;
150 case P_TAG: if (t->indent == NULL) {
151 out->put_string("</p>");
155 out->put_string("</p>");
157 out->enable_newlines(FALSE);
158 blank_para = TRUE; break;
159 case SUB_TAG: out->put_string("</sub>"); break;
160 case SUP_TAG: out->put_string("</sup>"); break;
161 case TT_TAG: out->put_string("</tt>"); break;
162 case PRE_TAG: out->put_string("</pre>"); out->enable_newlines(TRUE);
164 if (t->indent != NULL)
168 case SMALL_TAG: if (! is_in_pre ())
169 out->put_string("</small>");
171 case BIG_TAG: if (! is_in_pre ())
172 out->put_string("</big>");
174 case COLOR_TAG: if (! is_in_pre ())
175 out->put_string("</font>");
179 error("unrecognised tag");
184 * issue_tag - writes out an html tag with argument.
185 * space == 0 if no space is requested
186 * space == 1 if a space is requested
187 * space == 2 if tag should not have a space style
190 void html_text::issue_tag (const char *tagname, const char *arg,
193 if ((arg == 0) || (strlen(arg) == 0))
194 out->put_string(tagname);
196 out->put_string(tagname);
197 out->put_string(" ");
198 out->put_string(arg);
201 out->put_string(" style=\"margin-top: ");
202 out->put_string(STYLE_VERTICAL_SPACE);
203 out->put_string("\"");
206 if (space == TRUE || space == FALSE)
207 out->put_string(" valign=\"top\"");
209 out->put_string(">");
213 * issue_color_begin - writes out an html color tag.
216 void html_text::issue_color_begin (color *c)
218 unsigned int r, g, b;
221 out->put_string("<font color=\"#");
223 sprintf(buf, "000000");
225 c->get_rgb(&r, &g, &b);
226 // we have to scale 0..0xFFFF to 0..0xFF
227 sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
229 out->put_string(buf);
230 out->put_string("\">");
234 * start_tag - starts a tag.
237 void html_text::start_tag (tag_definition *t)
241 case I_TAG: issue_tag("<i", (char *)t->arg1); break;
242 case B_TAG: issue_tag("<b", (char *)t->arg1); break;
243 case P_TAG: if (t->indent != NULL) {
245 #if defined(DEBUGGING)
246 out->simple_comment("INDENTATION");
248 out->put_string("\n<p");
249 t->indent->begin(start_space);
250 issue_tag("", (char *)t->arg1);
253 issue_tag("\n<p", (char *)t->arg1, start_space);
256 out->enable_newlines(TRUE); break;
257 case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break;
258 case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break;
259 case TT_TAG: issue_tag("<tt", (char *)t->arg1); break;
260 case PRE_TAG: out->enable_newlines(TRUE);
261 out->nl(); out->put_string("<pre");
262 if (t->indent == NULL)
263 issue_tag("", (char *)t->arg1, start_space);
265 t->indent->begin(start_space);
266 issue_tag("", (char *)t->arg1);
268 out->enable_newlines(FALSE); break;
269 case SMALL_TAG: if (! is_in_pre ())
270 issue_tag("<small", (char *)t->arg1);
272 case BIG_TAG: if (! is_in_pre ())
273 issue_tag("<big", (char *)t->arg1);
275 case BREAK_TAG: break;
276 case COLOR_TAG: if (! is_in_pre ())
277 issue_color_begin(&t->col);
281 error("unrecognised tag");
286 * flush_text - flushes html tags which are outstanding on the html stack.
289 void html_text::flush_text (void)
292 tag_definition *p=stackptr;
294 while (stackptr != 0) {
295 notext = (notext && (! stackptr->text_emitted));
300 stackptr = stackptr->next;
307 * is_present - returns TRUE if tag is already present on the stack.
310 int html_text::is_present (HTML_TAG t)
312 tag_definition *p=stackptr;
323 * uses_indent - returns TRUE if the current paragraph is using a
324 * html table to effect an indent.
327 int html_text::uses_indent (void)
329 tag_definition *p = stackptr;
332 if (p->indent != NULL)
342 * do_push - places, tag_definition, p, onto the stack
345 void html_text::do_push (tag_definition *p)
347 HTML_TAG t = p->type;
349 #if defined(DEBUGGING)
353 fprintf(stderr, "\nentering do_push (");
354 dump_stack_element(p);
355 fprintf(stderr, ")\n");
357 fprintf(stderr, ")\n");
362 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
365 if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
367 * store, p, at the end
374 if (stackptr == NULL)
379 #if defined(DEBUGGING)
381 fprintf(stderr, "exiting do_push\n");
386 * push_para - adds a new entry onto the html paragraph stack.
389 void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
391 tag_definition *p= new tag_definition;
395 p->text_emitted = FALSE;
398 if (t == PRE_TAG && is_present(PRE_TAG))
399 fatal("cannot have multiple PRE_TAGs");
404 void html_text::push_para (HTML_TAG t)
406 push_para(t, (void *)"", NULL);
409 void html_text::push_para (color *c)
411 tag_definition *p = new tag_definition;
416 p->text_emitted = FALSE;
423 * do_italic - changes to italic
426 void html_text::do_italic (void)
428 if (! is_present(I_TAG))
433 * do_bold - changes to bold.
436 void html_text::do_bold (void)
438 if (! is_present(B_TAG))
443 * do_tt - changes to teletype.
446 void html_text::do_tt (void)
448 if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
453 * do_pre - changes to preformated text.
456 void html_text::do_pre (void)
459 if (is_present(P_TAG)) {
460 html_indent *i = remove_indent(P_TAG);
461 int space = retrieve_para_space();
463 if (! is_present(PRE_TAG))
464 push_para(PRE_TAG, NULL, i);
466 } else if (! is_present(PRE_TAG))
467 push_para(PRE_TAG, NULL, NULL);
472 * is_in_pre - returns TRUE if we are currently within a preformatted
476 int html_text::is_in_pre (void)
478 return is_present(PRE_TAG);
482 * do_color - initiates a new color tag.
485 void html_text::do_color (color *c)
487 shutdown(COLOR_TAG); // shutdown a previous color tag, if present
492 * done_color - shutdown an outstanding color tag, if it exists.
495 void html_text::done_color (void)
501 * shutdown - shuts down an html tag.
504 char *html_text::shutdown (HTML_TAG t)
509 tag_definition *p =stackptr;
510 tag_definition *temp =NULL;
514 while ((stackptr != NULL) && (stackptr->type != t)) {
515 notext = (notext && (! stackptr->text_emitted));
524 stackptr = stackptr->next;
525 if (stackptr == NULL)
529 * push tag onto temp stack
536 * and examine stackptr
538 if ((stackptr != NULL) && (stackptr->type == t)) {
539 if (stackptr->text_emitted) {
543 arg = (char *)stackptr->arg1;
546 stackptr = stackptr->next;
547 if (stackptr == NULL)
549 if (p->indent != NULL)
555 * and restore unaffected tags
557 while (temp != NULL) {
558 if (temp->type == COLOR_TAG)
559 push_para(&temp->col);
561 push_para(temp->type, temp->arg1, temp->indent);
571 * done_bold - shuts downs a bold tag.
574 void html_text::done_bold (void)
580 * done_italic - shuts downs an italic tag.
583 void html_text::done_italic (void)
589 * done_sup - shuts downs a sup tag.
592 void html_text::done_sup (void)
598 * done_sub - shuts downs a sub tag.
601 void html_text::done_sub (void)
607 * done_tt - shuts downs a tt tag.
610 void html_text::done_tt (void)
616 * done_pre - shuts downs a pre tag.
619 void html_text::done_pre (void)
625 * done_small - shuts downs a small tag.
628 void html_text::done_small (void)
634 * done_big - shuts downs a big tag.
637 void html_text::done_big (void)
643 * check_emit_text - ensures that all previous tags have been emitted (in order)
644 * before the text is written.
647 void html_text::check_emit_text (tag_definition *t)
649 if ((t != NULL) && (! t->text_emitted)) {
650 check_emit_text(t->next);
651 t->text_emitted = TRUE;
657 * do_emittext - tells the class that text was written during the current tag.
660 void html_text::do_emittext (const char *s, int length)
662 if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
665 if (is_present(BREAK_TAG)) {
666 int text = remove_break();
667 check_emit_text(stackptr);
669 if (is_present(PRE_TAG))
671 else if (dialect == xhtml)
672 out->put_string("<br/>").nl();
674 out->put_string("<br>").nl();
677 check_emit_text(stackptr);
679 out->put_string(s, length);
680 space_emitted = FALSE;
685 * do_para - starts a new paragraph
688 void html_text::do_para (const char *arg, html_indent *in, int space)
690 if (! is_present(P_TAG)) {
691 if (is_present(PRE_TAG)) {
692 html_indent *i = remove_indent(PRE_TAG);
694 if ((arg == NULL || (strcmp(arg, "") == 0)) &&
695 (i == in || in == NULL))
701 push_para(P_TAG, (void *)arg, in);
706 void html_text::do_para (const char *arg, int space)
708 do_para(arg, NULL, space);
711 void html_text::do_para (simple_output *op, const char *arg1,
712 int indentation_value, int page_offset,
713 int line_length, int space)
717 if (indentation_value == 0)
720 ind = new html_indent(op, indentation_value, page_offset, line_length);
721 do_para(arg1, ind, space);
725 * done_para - shuts down a paragraph tag.
728 char *html_text::done_para (void)
731 space_emitted = TRUE;
732 result = shutdown(P_TAG);
738 * remove_indent - returns the indent associated with, tag.
739 * The indent associated with tag is set to NULL.
742 html_indent *html_text::remove_indent (HTML_TAG tag)
744 tag_definition *p=stackptr;
747 if (tag == p->type) {
748 html_indent *i = p->indent;
758 * remove_para_space - removes the leading space to a paragraph
759 * (effectively this trims off a leading `.sp' tag).
762 void html_text::remove_para_space (void)
768 * do_space - issues an end of paragraph
771 void html_text::do_space (void)
776 space_emitted = TRUE;
778 html_indent *i = remove_indent(P_TAG);
780 do_para(done_para(), i, TRUE);
781 space_emitted = TRUE;
786 * do_break - issue a break tag.
789 void html_text::do_break (void)
791 if (! is_present(PRE_TAG))
793 if (! is_present(BREAK_TAG))
794 push_para(BREAK_TAG);
796 space_emitted = TRUE;
800 * do_newline - issue a newline providing that we are inside a <pre> tag.
803 void html_text::do_newline (void)
805 if (is_present(PRE_TAG)) {
806 do_emittext("\n", 1);
807 space_emitted = TRUE;
812 * emitted_text - returns FALSE if white space has just been written.
815 int html_text::emitted_text (void)
817 return !space_emitted;
821 * ever_emitted_text - returns TRUE if we have ever emitted text in this
825 int html_text::ever_emitted_text (void)
831 * starts_with_space - returns TRUE if we started this paragraph with a .sp
834 int html_text::starts_with_space (void)
840 * retrieve_para_space - returns TRUE, if the paragraph starts with
841 * a space and text has not yet been emitted.
842 * If TRUE is returned, then the, start_space,
843 * variable is set to FALSE.
846 int html_text::retrieve_para_space (void)
848 if (start_space && blank_para) {
857 * emit_space - writes a space providing that text was written beforehand.
860 void html_text::emit_space (void)
862 if (is_present(PRE_TAG))
865 out->space_or_newline();
867 space_emitted = TRUE;
871 * remove_def - removes a definition, t, from the stack.
874 void html_text::remove_def (tag_definition *t)
876 tag_definition *p = stackptr;
877 tag_definition *l = 0;
878 tag_definition *q = 0;
880 while ((p != 0) && (p != t)) {
884 if ((p != 0) && (p == t)) {
886 stackptr = stackptr->next;
887 if (stackptr == NULL)
891 error("stack list pointers are wrong");
903 * remove_tag - removes a tag from the stack.
906 void html_text::remove_tag (HTML_TAG tag)
908 tag_definition *p = stackptr;
910 while ((p != 0) && (p->type != tag)) {
913 if ((p != 0) && (p->type == tag))
918 * remove_sub_sup - removes a sub or sup tag, should either exist
922 void html_text::remove_sub_sup (void)
924 if (is_present(SUB_TAG)) {
927 if (is_present(SUP_TAG)) {
930 if (is_present(PRE_TAG)) {
936 * remove_break - break tags are not balanced thus remove it once it has been emitted.
937 * It returns TRUE if text was emitted before the <br> was issued.
940 int html_text::remove_break (void)
942 tag_definition *p = stackptr;
943 tag_definition *l = 0;
944 tag_definition *q = 0;
946 while ((p != 0) && (p->type != BREAK_TAG)) {
950 if ((p != 0) && (p->type == BREAK_TAG)) {
952 stackptr = stackptr->next;
953 if (stackptr == NULL)
957 error("stack list pointers are wrong");
967 * now determine whether text was issued before <br>
979 * remove_para_align - removes a paragraph which has a text
980 * argument. If the paragraph has no text
981 * argument then it is left alone.
984 void html_text::remove_para_align (void)
986 if (is_present(P_TAG)) {
987 tag_definition *p=stackptr;
990 if (p->type == P_TAG && p->arg1 != NULL) {
991 html_indent *i = remove_indent(P_TAG);
992 int space = retrieve_para_space();
994 do_para("", i, space);
1003 * get_alignment - returns the alignment for the paragraph.
1004 * If no alignment was given then we return "".
1007 char *html_text::get_alignment (void)
1009 if (is_present(P_TAG)) {
1010 tag_definition *p=stackptr;
1013 if (p->type == P_TAG && p->arg1 != NULL)
1014 return (char *)p->arg1;
1022 * do_small - potentially inserts a <small> tag into the html stream.
1023 * However we check for a <big> tag, if present then we terminate it.
1024 * Otherwise a <small> tag is inserted.
1027 void html_text::do_small (void)
1029 if (is_present(BIG_TAG))
1032 push_para(SMALL_TAG);
1036 * do_big - is the mirror image of do_small.
1039 void html_text::do_big (void)
1041 if (is_present(SMALL_TAG))
1048 * do_sup - save a superscript tag on the stack of tags.
1051 void html_text::do_sup (void)
1057 * do_sub - save a subscript tag on the stack of tags.
1060 void html_text::do_sub (void)