2 /* Copyright (C) 2000-2018 Free Software Foundation, Inc.
4 * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp
8 * provide a troff like state machine interface which
13 This file is part of groff.
15 groff is free software; you can redistribute it and/or modify it under
16 the terms of the GNU General Public License as published by the Free
17 Software Foundation, either version 3 of the License, or
18 (at your option) any later version.
20 groff is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>. */
29 #include "stringclass.h"
40 #include "html-text.h"
45 html_text::html_text (simple_output *op, html_dialect d) :
46 stackptr(NULL), lastptr(NULL), out(op), dialect(d),
47 space_emitted(TRUE), current_indentation(-1),
48 pageoffset(-1), linelength(-1), blank_para(TRUE),
53 html_text::~html_text ()
59 #if defined(DEBUGGING)
60 static int debugStack = FALSE;
64 * turnDebug - flip the debugStack boolean and return the new value.
67 static int turnDebug (void)
69 debugStack = 1-debugStack;
74 * dump_stack_element - display an element of the html stack, p.
77 void html_text::dump_stack_element (tag_definition *p)
79 fprintf(stderr, " | ");
82 case P_TAG: if (p->indent == NULL) {
83 fprintf(stderr, "<P %s>", (char *)p->arg1); break;
85 fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
87 case I_TAG: fprintf(stderr, "<I>"); break;
88 case B_TAG: fprintf(stderr, "<B>"); break;
89 case SUB_TAG: fprintf(stderr, "<SUB>"); break;
90 case SUP_TAG: fprintf(stderr, "<SUP>"); break;
91 case TT_TAG: fprintf(stderr, "<TT>"); break;
92 case PRE_TAG: if (p->indent == NULL) {
93 fprintf(stderr, "<PRE>"); break;
95 fprintf(stderr, "<PRE [TABLE]>"); break;
97 case SMALL_TAG: fprintf(stderr, "<SMALL>"); break;
98 case BIG_TAG: fprintf(stderr, "<BIG>"); break;
99 case BREAK_TAG: fprintf(stderr, "<BREAK>"); break;
101 if (p->col.is_default())
102 fprintf(stderr, "<COLOR (default)>");
104 unsigned int r, g, b;
106 p->col.get_rgb(&r, &g, &b);
107 fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
111 default: fprintf(stderr, "unknown tag");
114 fprintf(stderr, "[t] ");
118 * dump_stack - debugging function only.
121 void html_text::dump_stack (void)
124 tag_definition *p = stackptr;
127 dump_stack_element(p);
131 fprintf(stderr, "\n");
135 void html_text::dump_stack (void) {}
140 * end_tag - shuts down the tag.
143 void html_text::end_tag (tag_definition *t)
147 case I_TAG: out->put_string("</i>"); break;
148 case B_TAG: out->put_string("</b>"); break;
149 case P_TAG: if (t->indent == NULL) {
150 out->put_string("</p>");
154 out->put_string("</p>");
156 out->enable_newlines(FALSE);
157 blank_para = TRUE; break;
158 case SUB_TAG: out->put_string("</sub>"); break;
159 case SUP_TAG: out->put_string("</sup>"); break;
160 case TT_TAG: out->put_string("</tt>"); break;
161 case PRE_TAG: out->put_string("</pre>"); out->enable_newlines(TRUE);
163 if (t->indent != NULL)
167 case SMALL_TAG: if (! is_in_pre ())
168 out->put_string("</small>");
170 case BIG_TAG: if (! is_in_pre ())
171 out->put_string("</big>");
173 case COLOR_TAG: if (! is_in_pre ())
174 out->put_string("</font>");
178 error("unrecognised tag");
183 * issue_tag - writes out an html tag with argument.
184 * space == 0 if no space is requested
185 * space == 1 if a space is requested
186 * space == 2 if tag should not have a space style
189 void html_text::issue_tag (const char *tagname, const char *arg,
192 if ((arg == 0) || (strlen(arg) == 0))
193 out->put_string(tagname);
195 out->put_string(tagname);
196 out->put_string(" ");
197 out->put_string(arg);
200 out->put_string(" style=\"margin-top: ");
201 out->put_string(STYLE_VERTICAL_SPACE);
202 out->put_string("\"");
205 if (space == TRUE || space == FALSE)
206 out->put_string(" valign=\"top\"");
208 out->put_string(">");
212 * issue_color_begin - writes out an html color tag.
215 void html_text::issue_color_begin (color *c)
217 unsigned int r, g, b;
220 out->put_string("<font color=\"#");
222 sprintf(buf, "000000");
224 c->get_rgb(&r, &g, &b);
225 // we have to scale 0..0xFFFF to 0..0xFF
226 sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
228 out->put_string(buf);
229 out->put_string("\">");
233 * start_tag - starts a tag.
236 void html_text::start_tag (tag_definition *t)
240 case I_TAG: issue_tag("<i", (char *)t->arg1); break;
241 case B_TAG: issue_tag("<b", (char *)t->arg1); break;
242 case P_TAG: if (t->indent != NULL) {
244 #if defined(DEBUGGING)
245 out->simple_comment("INDENTATION");
247 out->put_string("\n<p");
248 t->indent->begin(start_space);
249 issue_tag("", (char *)t->arg1);
252 issue_tag("\n<p", (char *)t->arg1, start_space);
255 out->enable_newlines(TRUE); break;
256 case SUB_TAG: issue_tag("<sub", (char *)t->arg1); break;
257 case SUP_TAG: issue_tag("<sup", (char *)t->arg1); break;
258 case TT_TAG: issue_tag("<tt", (char *)t->arg1); break;
259 case PRE_TAG: out->enable_newlines(TRUE);
260 out->nl(); out->put_string("<pre");
261 if (t->indent == NULL)
262 issue_tag("", (char *)t->arg1, start_space);
264 t->indent->begin(start_space);
265 issue_tag("", (char *)t->arg1);
267 out->enable_newlines(FALSE); break;
268 case SMALL_TAG: if (! is_in_pre ())
269 issue_tag("<small", (char *)t->arg1);
271 case BIG_TAG: if (! is_in_pre ())
272 issue_tag("<big", (char *)t->arg1);
274 case BREAK_TAG: break;
275 case COLOR_TAG: if (! is_in_pre ())
276 issue_color_begin(&t->col);
280 error("unrecognised tag");
285 * flush_text - flushes html tags which are outstanding on the html stack.
288 void html_text::flush_text (void)
291 tag_definition *p=stackptr;
293 while (stackptr != 0) {
294 notext = (notext && (! stackptr->text_emitted));
299 stackptr = stackptr->next;
306 * is_present - returns TRUE if tag is already present on the stack.
309 int html_text::is_present (HTML_TAG t)
311 tag_definition *p=stackptr;
322 * uses_indent - returns TRUE if the current paragraph is using a
323 * html table to effect an indent.
326 int html_text::uses_indent (void)
328 tag_definition *p = stackptr;
331 if (p->indent != NULL)
341 * do_push - places, tag_definition, p, onto the stack
344 void html_text::do_push (tag_definition *p)
346 HTML_TAG t = p->type;
348 #if defined(DEBUGGING)
352 fprintf(stderr, "\nentering do_push (");
353 dump_stack_element(p);
354 fprintf(stderr, ")\n");
356 fprintf(stderr, ")\n");
361 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
364 if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
366 * store, p, at the end
373 if (stackptr == NULL)
378 #if defined(DEBUGGING)
380 fprintf(stderr, "exiting do_push\n");
385 * push_para - adds a new entry onto the html paragraph stack.
388 void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
390 tag_definition *p= new tag_definition;
394 p->text_emitted = FALSE;
397 if (t == PRE_TAG && is_present(PRE_TAG))
398 fatal("cannot have multiple PRE_TAGs");
403 void html_text::push_para (HTML_TAG t)
405 push_para(t, (void *)"", NULL);
408 void html_text::push_para (color *c)
410 tag_definition *p = new tag_definition;
415 p->text_emitted = FALSE;
422 * do_italic - changes to italic
425 void html_text::do_italic (void)
427 if (! is_present(I_TAG))
432 * do_bold - changes to bold.
435 void html_text::do_bold (void)
437 if (! is_present(B_TAG))
442 * do_tt - changes to teletype.
445 void html_text::do_tt (void)
447 if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
452 * do_pre - changes to preformated text.
455 void html_text::do_pre (void)
458 if (is_present(P_TAG)) {
459 html_indent *i = remove_indent(P_TAG);
460 int space = retrieve_para_space();
462 if (! is_present(PRE_TAG))
463 push_para(PRE_TAG, NULL, i);
465 } else if (! is_present(PRE_TAG))
466 push_para(PRE_TAG, NULL, NULL);
471 * is_in_pre - returns TRUE if we are currently within a preformatted
475 int html_text::is_in_pre (void)
477 return is_present(PRE_TAG);
481 * do_color - initiates a new color tag.
484 void html_text::do_color (color *c)
486 shutdown(COLOR_TAG); // shutdown a previous color tag, if present
491 * done_color - shutdown an outstanding color tag, if it exists.
494 void html_text::done_color (void)
500 * shutdown - shuts down an html tag.
503 char *html_text::shutdown (HTML_TAG t)
508 tag_definition *p =stackptr;
509 tag_definition *temp =NULL;
513 while ((stackptr != NULL) && (stackptr->type != t)) {
514 notext = (notext && (! stackptr->text_emitted));
523 stackptr = stackptr->next;
524 if (stackptr == NULL)
528 * push tag onto temp stack
535 * and examine stackptr
537 if ((stackptr != NULL) && (stackptr->type == t)) {
538 if (stackptr->text_emitted) {
542 arg = (char *)stackptr->arg1;
545 stackptr = stackptr->next;
546 if (stackptr == NULL)
548 if (p->indent != NULL)
554 * and restore unaffected tags
556 while (temp != NULL) {
557 if (temp->type == COLOR_TAG)
558 push_para(&temp->col);
560 push_para(temp->type, temp->arg1, temp->indent);
570 * done_bold - shuts downs a bold tag.
573 void html_text::done_bold (void)
579 * done_italic - shuts downs an italic tag.
582 void html_text::done_italic (void)
588 * done_sup - shuts downs a sup tag.
591 void html_text::done_sup (void)
597 * done_sub - shuts downs a sub tag.
600 void html_text::done_sub (void)
606 * done_tt - shuts downs a tt tag.
609 void html_text::done_tt (void)
615 * done_pre - shuts downs a pre tag.
618 void html_text::done_pre (void)
624 * done_small - shuts downs a small tag.
627 void html_text::done_small (void)
633 * done_big - shuts downs a big tag.
636 void html_text::done_big (void)
642 * check_emit_text - ensures that all previous tags have been emitted (in order)
643 * before the text is written.
646 void html_text::check_emit_text (tag_definition *t)
648 if ((t != NULL) && (! t->text_emitted)) {
649 check_emit_text(t->next);
650 t->text_emitted = TRUE;
656 * do_emittext - tells the class that text was written during the current tag.
659 void html_text::do_emittext (const char *s, int length)
661 if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
664 if (is_present(BREAK_TAG)) {
665 int text = remove_break();
666 check_emit_text(stackptr);
668 if (is_present(PRE_TAG))
670 else if (dialect == xhtml)
671 out->put_string("<br/>").nl();
673 out->put_string("<br>").nl();
676 check_emit_text(stackptr);
678 out->put_string(s, length);
679 space_emitted = FALSE;
684 * do_para - starts a new paragraph
687 void html_text::do_para (const char *arg, html_indent *in, int space)
689 if (! is_present(P_TAG)) {
690 if (is_present(PRE_TAG)) {
691 html_indent *i = remove_indent(PRE_TAG);
693 if ((arg == NULL || (strcmp(arg, "") == 0)) &&
694 (i == in || in == NULL))
700 push_para(P_TAG, (void *)arg, in);
705 void html_text::do_para (const char *arg, int space)
707 do_para(arg, NULL, space);
710 void html_text::do_para (simple_output *op, const char *arg1,
711 int indentation_value, int page_offset,
712 int line_length, int space)
716 if (indentation_value == 0)
719 ind = new html_indent(op, indentation_value, page_offset, line_length);
720 do_para(arg1, ind, space);
724 * done_para - shuts down a paragraph tag.
727 char *html_text::done_para (void)
730 space_emitted = TRUE;
731 result = shutdown(P_TAG);
737 * remove_indent - returns the indent associated with, tag.
738 * The indent associated with tag is set to NULL.
741 html_indent *html_text::remove_indent (HTML_TAG tag)
743 tag_definition *p=stackptr;
746 if (tag == p->type) {
747 html_indent *i = p->indent;
757 * remove_para_space - removes the leading space to a paragraph
758 * (effectively this trims off a leading '.sp' tag).
761 void html_text::remove_para_space (void)
767 * do_space - issues an end of paragraph
770 void html_text::do_space (void)
775 space_emitted = TRUE;
777 html_indent *i = remove_indent(P_TAG);
779 do_para(done_para(), i, TRUE);
780 space_emitted = TRUE;
785 * do_break - issue a break tag.
788 void html_text::do_break (void)
790 if (! is_present(PRE_TAG))
792 if (! is_present(BREAK_TAG))
793 push_para(BREAK_TAG);
795 space_emitted = TRUE;
799 * do_newline - issue a newline providing that we are inside a <pre> tag.
802 void html_text::do_newline (void)
804 if (is_present(PRE_TAG)) {
805 do_emittext("\n", 1);
806 space_emitted = TRUE;
811 * emitted_text - returns FALSE if white space has just been written.
814 int html_text::emitted_text (void)
816 return !space_emitted;
820 * ever_emitted_text - returns TRUE if we have ever emitted text in this
824 int html_text::ever_emitted_text (void)
830 * starts_with_space - returns TRUE if we started this paragraph with a .sp
833 int html_text::starts_with_space (void)
839 * retrieve_para_space - returns TRUE, if the paragraph starts with
840 * a space and text has not yet been emitted.
841 * If TRUE is returned, then the, start_space,
842 * variable is set to FALSE.
845 int html_text::retrieve_para_space (void)
847 if (start_space && blank_para) {
856 * emit_space - writes a space providing that text was written beforehand.
859 void html_text::emit_space (void)
861 if (is_present(PRE_TAG))
864 out->space_or_newline();
866 space_emitted = TRUE;
870 * remove_def - removes a definition, t, from the stack.
873 void html_text::remove_def (tag_definition *t)
875 tag_definition *p = stackptr;
876 tag_definition *l = 0;
878 while ((p != 0) && (p != t)) {
882 if ((p != 0) && (p == t)) {
884 stackptr = stackptr->next;
885 if (stackptr == NULL)
888 error("stack list pointers are wrong");
899 * remove_tag - removes a tag from the stack.
902 void html_text::remove_tag (HTML_TAG tag)
904 tag_definition *p = stackptr;
906 while ((p != 0) && (p->type != tag)) {
909 if ((p != 0) && (p->type == tag))
914 * remove_sub_sup - removes a sub or sup tag, should either exist
918 void html_text::remove_sub_sup (void)
920 if (is_present(SUB_TAG)) {
923 if (is_present(SUP_TAG)) {
926 if (is_present(PRE_TAG)) {
932 * remove_break - break tags are not balanced thus remove it once it has been emitted.
933 * It returns TRUE if text was emitted before the <br> was issued.
936 int html_text::remove_break (void)
938 tag_definition *p = stackptr;
939 tag_definition *l = 0;
940 tag_definition *q = 0;
942 while ((p != 0) && (p->type != BREAK_TAG)) {
946 if ((p != 0) && (p->type == BREAK_TAG)) {
948 stackptr = stackptr->next;
949 if (stackptr == NULL)
953 error("stack list pointers are wrong");
963 * now determine whether text was issued before <br>
975 * remove_para_align - removes a paragraph which has a text
976 * argument. If the paragraph has no text
977 * argument then it is left alone.
980 void html_text::remove_para_align (void)
982 if (is_present(P_TAG)) {
983 tag_definition *p=stackptr;
986 if (p->type == P_TAG && p->arg1 != NULL) {
987 html_indent *i = remove_indent(P_TAG);
988 int space = retrieve_para_space();
990 do_para("", i, space);
999 * get_alignment - returns the alignment for the paragraph.
1000 * If no alignment was given then we return "".
1003 char *html_text::get_alignment (void)
1005 if (is_present(P_TAG)) {
1006 tag_definition *p=stackptr;
1009 if (p->type == P_TAG && p->arg1 != NULL)
1010 return (char *)p->arg1;
1018 * do_small - potentially inserts a <small> tag into the html stream.
1019 * However we check for a <big> tag, if present then we terminate it.
1020 * Otherwise a <small> tag is inserted.
1023 void html_text::do_small (void)
1025 if (is_present(BIG_TAG))
1028 push_para(SMALL_TAG);
1032 * do_big - is the mirror image of do_small.
1035 void html_text::do_big (void)
1037 if (is_present(SMALL_TAG))
1044 * do_sup - save a superscript tag on the stack of tags.
1047 void html_text::do_sup (void)
1053 * do_sub - save a subscript tag on the stack of tags.
1056 void html_text::do_sub (void)