2 /* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
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 2, or (at your option) any later
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 along
27 with groff; see the file COPYING. If not, write to the Free Software
28 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
31 #include "stringclass.h"
42 #include "html-text.h"
47 html_text::html_text (simple_output *op) :
48 stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE),
49 current_indentation(-1), pageoffset(-1), linelength(-1),
50 blank_para(TRUE), start_space(FALSE)
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: out->put_string("</small>"); break;
169 case BIG_TAG: out->put_string("</big>"); break;
170 case COLOR_TAG: out->put_string("</font>"); break;
173 error("unrecognised tag");
178 * issue_tag - writes out an html tag with argument.
179 * space == 0 if no space is requested
180 * space == 1 if a space is requested
181 * space == 2 if tag should not have a space style
184 void html_text::issue_tag (const char *tagname, const char *arg,
187 if ((arg == 0) || (strlen(arg) == 0))
188 out->put_string(tagname);
190 out->put_string(tagname);
191 out->put_string(" ");
192 out->put_string(arg);
195 out->put_string(" style=\"margin-top: ");
196 out->put_string(STYLE_VERTICAL_SPACE);
197 out->put_string("\"");
199 if (space == TRUE || space == FALSE)
200 out->put_string(" valign=\"top\"");
201 out->put_string(">");
205 * issue_color_begin - writes out an html color tag.
208 void html_text::issue_color_begin (color *c)
210 unsigned int r, g, b;
213 out->put_string("<font color=\"#");
215 sprintf(buf, "000000");
217 c->get_rgb(&r, &g, &b);
218 // we have to scale 0..0xFFFF to 0..0xFF
219 sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
221 out->put_string(buf);
222 out->put_string("\">");
226 * start_tag - starts a tag.
229 void html_text::start_tag (tag_definition *t)
233 case I_TAG: issue_tag("<i", (char *)t->arg1); break;
234 case B_TAG: issue_tag("<b", (char *)t->arg1); break;
235 case P_TAG: if (t->indent != NULL) {
237 #if defined(DEBUGGING)
238 out->simple_comment("INDENTATION");
240 out->put_string("\n<p");
241 t->indent->begin(start_space);
242 issue_tag("", (char *)t->arg1);
245 issue_tag("\n<p", (char *)t->arg1, start_space);
248 out->enable_newlines(TRUE); break;
249 case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break;
250 case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break;
251 case TT_TAG: issue_tag("<tt", (char *)t->arg1); break;
252 case PRE_TAG: out->enable_newlines(TRUE);
253 out->nl(); out->put_string("<pre");
254 if (t->indent == NULL)
255 issue_tag("", (char *)t->arg1, start_space);
257 t->indent->begin(start_space);
258 issue_tag("", (char *)t->arg1);
260 out->enable_newlines(FALSE); break;
261 case SMALL_TAG: issue_tag("<small", (char *)t->arg1); break;
262 case BIG_TAG: issue_tag("<big", (char *)t->arg1); break;
263 case BREAK_TAG: break;
264 case COLOR_TAG: issue_color_begin(&t->col); break;
267 error("unrecognised tag");
272 * flush_text - flushes html tags which are outstanding on the html stack.
275 void html_text::flush_text (void)
278 tag_definition *p=stackptr;
280 while (stackptr != 0) {
281 notext = (notext && (! stackptr->text_emitted));
286 stackptr = stackptr->next;
293 * is_present - returns TRUE if tag is already present on the stack.
296 int html_text::is_present (HTML_TAG t)
298 tag_definition *p=stackptr;
309 * uses_indent - returns TRUE if the current paragraph is using a
310 * html table to effect an indent.
313 int html_text::uses_indent (void)
315 tag_definition *p = stackptr;
318 if (p->indent != NULL)
328 * do_push - places, tag_definition, p, onto the stack
331 void html_text::do_push (tag_definition *p)
333 HTML_TAG t = p->type;
335 #if defined(DEBUGGING)
339 fprintf(stderr, "\nentering do_push (");
340 dump_stack_element(p);
341 fprintf(stderr, ")\n");
343 fprintf(stderr, ")\n");
348 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
351 if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
353 * store, p, at the end
360 if (stackptr == NULL)
365 #if defined(DEBUGGING)
367 fprintf(stderr, "exiting do_push\n");
372 * push_para - adds a new entry onto the html paragraph stack.
375 void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
377 tag_definition *p= new tag_definition;
381 p->text_emitted = FALSE;
384 if (t == PRE_TAG && is_present(PRE_TAG))
385 fatal("cannot have multiple PRE_TAGs");
390 void html_text::push_para (HTML_TAG t)
392 push_para(t, (void *)"", NULL);
395 void html_text::push_para (color *c)
397 tag_definition *p = new tag_definition;
402 p->text_emitted = FALSE;
409 * do_italic - changes to italic
412 void html_text::do_italic (void)
414 if (! is_present(I_TAG))
419 * do_bold - changes to bold.
422 void html_text::do_bold (void)
424 if (! is_present(B_TAG))
429 * do_tt - changes to teletype.
432 void html_text::do_tt (void)
434 if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
439 * do_pre - changes to preformated text.
442 void html_text::do_pre (void)
445 if (is_present(P_TAG)) {
446 html_indent *i = remove_indent(P_TAG);
447 int space = retrieve_para_space();
449 if (! is_present(PRE_TAG))
450 push_para(PRE_TAG, NULL, i);
452 } else if (! is_present(PRE_TAG))
453 push_para(PRE_TAG, NULL, NULL);
458 * is_in_pre - returns TRUE if we are currently within a preformatted
462 int html_text::is_in_pre (void)
464 return is_present(PRE_TAG);
468 * do_color - initiates a new color tag.
471 void html_text::do_color (color *c)
473 shutdown(COLOR_TAG); // shutdown a previous color tag, if present
478 * done_color - shutdown an outstanding color tag, if it exists.
481 void html_text::done_color (void)
487 * shutdown - shuts down an html tag.
490 char *html_text::shutdown (HTML_TAG t)
495 tag_definition *p =stackptr;
496 tag_definition *temp =NULL;
500 while ((stackptr != NULL) && (stackptr->type != t)) {
501 notext = (notext && (! stackptr->text_emitted));
510 stackptr = stackptr->next;
511 if (stackptr == NULL)
515 * push tag onto temp stack
522 * and examine stackptr
524 if ((stackptr != NULL) && (stackptr->type == t)) {
525 if (stackptr->text_emitted) {
529 arg = (char *)stackptr->arg1;
532 stackptr = stackptr->next;
533 if (stackptr == NULL)
535 if (p->indent != NULL)
541 * and restore unaffected tags
543 while (temp != NULL) {
544 if (temp->type == COLOR_TAG)
545 push_para(&temp->col);
547 push_para(temp->type, temp->arg1, temp->indent);
557 * done_bold - shuts downs a bold tag.
560 void html_text::done_bold (void)
566 * done_italic - shuts downs an italic tag.
569 void html_text::done_italic (void)
575 * done_sup - shuts downs a sup tag.
578 void html_text::done_sup (void)
584 * done_sub - shuts downs a sub tag.
587 void html_text::done_sub (void)
593 * done_tt - shuts downs a tt tag.
596 void html_text::done_tt (void)
602 * done_pre - shuts downs a pre tag.
605 void html_text::done_pre (void)
611 * done_small - shuts downs a small tag.
614 void html_text::done_small (void)
620 * done_big - shuts downs a big tag.
623 void html_text::done_big (void)
629 * check_emit_text - ensures that all previous tags have been emitted (in order)
630 * before the text is written.
633 void html_text::check_emit_text (tag_definition *t)
635 if ((t != NULL) && (! t->text_emitted)) {
636 check_emit_text(t->next);
637 t->text_emitted = TRUE;
643 * do_emittext - tells the class that text was written during the current tag.
646 void html_text::do_emittext (const char *s, int length)
648 if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
651 if (is_present(BREAK_TAG)) {
652 int text = remove_break();
653 check_emit_text(stackptr);
655 if (is_present(PRE_TAG)) {
658 out->put_string("<br>").nl();
661 check_emit_text(stackptr);
663 out->put_string(s, length);
664 space_emitted = FALSE;
669 * do_para - starts a new paragraph
672 void html_text::do_para (const char *arg, html_indent *in, int space)
674 if (! is_present(P_TAG)) {
675 if (is_present(PRE_TAG)) {
676 html_indent *i = remove_indent(PRE_TAG);
678 if ((arg == NULL || (strcmp(arg, "") == 0)) &&
679 (i == in || in == NULL))
685 push_para(P_TAG, (void *)arg, in);
690 void html_text::do_para (const char *arg, int space)
692 do_para(arg, NULL, space);
695 void html_text::do_para (simple_output *op, const char *arg1,
696 int indentation_value, int page_offset,
697 int line_length, int space)
701 if (indentation_value == 0)
704 ind = new html_indent(op, indentation_value, page_offset, line_length);
705 do_para(arg1, ind, space);
709 * done_para - shuts down a paragraph tag.
712 char *html_text::done_para (void)
715 space_emitted = TRUE;
716 result = shutdown(P_TAG);
722 * remove_indent - returns the indent associated with, tag.
723 * The indent associated with tag is set to NULL.
726 html_indent *html_text::remove_indent (HTML_TAG tag)
728 tag_definition *p=stackptr;
731 if (tag == p->type) {
732 html_indent *i = p->indent;
742 * remove_para_space - removes the leading space to a paragraph
743 * (effectively this trims off a leading `.sp' tag).
746 void html_text::remove_para_space (void)
752 * do_space - issues an end of paragraph
755 void html_text::do_space (void)
760 space_emitted = TRUE;
762 html_indent *i = remove_indent(P_TAG);
764 do_para(done_para(), i, TRUE);
765 space_emitted = TRUE;
770 * do_break - issue a break tag.
773 void html_text::do_break (void)
775 if (! is_present(PRE_TAG))
777 if (! is_present(BREAK_TAG))
778 push_para(BREAK_TAG);
780 space_emitted = TRUE;
784 * do_newline - issue a newline providing that we are inside a <pre> tag.
787 void html_text::do_newline (void)
789 if (is_present(PRE_TAG)) {
790 do_emittext("\n", 1);
791 space_emitted = TRUE;
796 * emitted_text - returns FALSE if white space has just been written.
799 int html_text::emitted_text (void)
801 return !space_emitted;
805 * ever_emitted_text - returns TRUE if we have ever emitted text in this
809 int html_text::ever_emitted_text (void)
815 * starts_with_space - returns TRUE if we started this paragraph with a .sp
818 int html_text::starts_with_space (void)
824 * retrieve_para_space - returns TRUE, if the paragraph starts with
825 * a space and text has not yet been emitted.
826 * If TRUE is returned, then the, start_space,
827 * variable is set to FALSE.
830 int html_text::retrieve_para_space (void)
832 if (start_space && blank_para) {
841 * emit_space - writes a space providing that text was written beforehand.
844 void html_text::emit_space (void)
846 if (is_present(PRE_TAG))
849 out->space_or_newline();
851 space_emitted = TRUE;
855 * remove_def - removes a definition, t, from the stack.
858 void html_text::remove_def (tag_definition *t)
860 tag_definition *p = stackptr;
861 tag_definition *l = 0;
862 tag_definition *q = 0;
864 while ((p != 0) && (p != t)) {
868 if ((p != 0) && (p == t)) {
870 stackptr = stackptr->next;
871 if (stackptr == NULL)
875 error("stack list pointers are wrong");
887 * remove_tag - removes a tag from the stack.
890 void html_text::remove_tag (HTML_TAG tag)
892 tag_definition *p = stackptr;
894 while ((p != 0) && (p->type != tag)) {
897 if ((p != 0) && (p->type == tag))
902 * remove_sub_sup - removes a sub or sup tag, should either exist
906 void html_text::remove_sub_sup (void)
908 if (is_present(SUB_TAG)) {
911 if (is_present(SUP_TAG)) {
914 if (is_present(PRE_TAG)) {
920 * remove_break - break tags are not balanced thus remove it once it has been emitted.
921 * It returns TRUE if text was emitted before the <br> was issued.
924 int html_text::remove_break (void)
926 tag_definition *p = stackptr;
927 tag_definition *l = 0;
928 tag_definition *q = 0;
930 while ((p != 0) && (p->type != BREAK_TAG)) {
934 if ((p != 0) && (p->type == BREAK_TAG)) {
936 stackptr = stackptr->next;
937 if (stackptr == NULL)
941 error("stack list pointers are wrong");
951 * now determine whether text was issued before <br>
963 * remove_para_align - removes a paragraph which has a text
964 * argument. If the paragraph has no text
965 * argument then it is left alone.
968 void html_text::remove_para_align (void)
970 if (is_present(P_TAG)) {
971 tag_definition *p=stackptr;
974 if (p->type == P_TAG && p->arg1 != NULL) {
975 html_indent *i = remove_indent(P_TAG);
976 int space = retrieve_para_space();
978 do_para("", i, space);
987 * get_alignment - returns the alignment for the paragraph.
988 * If no alignment was given then we return "".
991 char *html_text::get_alignment (void)
993 if (is_present(P_TAG)) {
994 tag_definition *p=stackptr;
997 if (p->type == P_TAG && p->arg1 != NULL)
998 return (char *)p->arg1;
1006 * do_small - potentially inserts a <small> tag into the html stream.
1007 * However we check for a <big> tag, if present then we terminate it.
1008 * Otherwise a <small> tag is inserted.
1011 void html_text::do_small (void)
1013 if (is_present(BIG_TAG))
1016 push_para(SMALL_TAG);
1020 * do_big - is the mirror image of do_small.
1023 void html_text::do_big (void)
1025 if (is_present(SMALL_TAG))
1032 * do_sup - save a superscript tag on the stack of tags.
1035 void html_text::do_sup (void)
1041 * do_sub - save a subscript tag on the stack of tags.
1044 void html_text::do_sub (void)