1 /*@ Provide a troff like state machine interface which generates html text.
3 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
5 * Copyright (C) 2000 - 2005, 2007
6 * Free Software Foundation, Inc.
8 * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp
11 * This is free software; you can redistribute it and/or modify it under
12 * the terms of the GNU General Public License as published by the Free
13 * Software Foundation; either version 2, or (at your option) any later
16 * This is distributed in the hope that it will be useful, but WITHOUT ANY
17 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 * You should have received a copy of the GNU General Public License along
22 * with groff; see the file COPYING. If not, write to the Free Software
23 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
27 #include "html-config.h"
31 #include "stringclass.h"
33 #include "html-text.h"
35 html_text::html_text(simple_output
*op
, html_dialect d
)
36 : stackptr(NULL
), lastptr(NULL
), out(op
), dialect(d
),
37 space_emitted(true), current_indentation(-1),
38 pageoffset(-1), linelength(-1), blank_para(true),
43 html_text::~html_text()
49 static int debugStack
= false;
52 * turnDebug - flip the debugStack boolean and return the new value.
55 static int turnDebug (void)
57 debugStack
= 1-debugStack
;
62 * dump_stack_element - display an element of the html stack, p.
65 void html_text::dump_stack_element (tag_definition
*p
)
67 fprintf(stderr
, " | ");
70 case P_TAG
: if (p
->indent
== NULL
) {
71 fprintf(stderr
, "<P %s>", (char *)p
->arg1
); break;
73 fprintf(stderr
, "<P %s [TABLE]>", (char *)p
->arg1
); break;
75 case I_TAG
: fprintf(stderr
, "<I>"); break;
76 case B_TAG
: fprintf(stderr
, "<B>"); break;
77 case SUB_TAG
: fprintf(stderr
, "<SUB>"); break;
78 case SUP_TAG
: fprintf(stderr
, "<SUP>"); break;
79 case TT_TAG
: fprintf(stderr
, "<TT>"); break;
80 case PRE_TAG
: if (p
->indent
== NULL
) {
81 fprintf(stderr
, "<PRE>"); break;
83 fprintf(stderr
, "<PRE [TABLE]>"); break;
85 case SMALL_TAG
: fprintf(stderr
, "<SMALL>"); break;
86 case BIG_TAG
: fprintf(stderr
, "<BIG>"); break;
87 case BREAK_TAG
: fprintf(stderr
, "<BREAK>"); break;
89 if (p
->col
.is_default())
90 fprintf(stderr
, "<COLOR (default)>");
94 p
->col
.get_rgb(&r
, &g
, &b
);
95 fprintf(stderr
, "<COLOR %x %x %x>", r
/0x101, g
/0x101, b
/0x101);
99 default: fprintf(stderr
, "unknown tag");
102 fprintf(stderr
, "[t] ");
106 * dump_stack - debugging function only.
109 void html_text::dump_stack (void)
112 tag_definition
*p
= stackptr
;
115 dump_stack_element(p
);
119 fprintf(stderr
, "\n");
124 void html_text::dump_stack (void) {}
128 * end_tag - shuts down the tag.
131 void html_text::end_tag (tag_definition
*t
)
135 case I_TAG
: out
->put_string("</i>"); break;
136 case B_TAG
: out
->put_string("</b>"); break;
137 case P_TAG
: if (t
->indent
== NULL
) {
138 out
->put_string("</p>");
142 out
->put_string("</p>");
144 out
->enable_newlines(false);
145 blank_para
= true; break;
146 case SUB_TAG
: out
->put_string("</sub>"); break;
147 case SUP_TAG
: out
->put_string("</sup>"); break;
148 case TT_TAG
: out
->put_string("</tt>"); break;
149 case PRE_TAG
: out
->put_string("</pre>"); out
->enable_newlines(true);
151 if (t
->indent
!= NULL
)
155 case SMALL_TAG
: if (! is_in_pre ())
156 out
->put_string("</small>");
158 case BIG_TAG
: if (! is_in_pre ())
159 out
->put_string("</big>");
161 case COLOR_TAG
: if (! is_in_pre ())
162 out
->put_string("</font>");
166 error("unrecognised tag");
171 * issue_tag - writes out an html tag with argument.
172 * space == 0 if no space is requested
173 * space == 1 if a space is requested
174 * space == 2 if tag should not have a space style
177 void html_text::issue_tag (const char *tagname
, const char *arg
,
180 if ((arg
== 0) || (strlen(arg
) == 0))
181 out
->put_string(tagname
);
183 out
->put_string(tagname
);
184 out
->put_string(" ");
185 out
->put_string(arg
);
188 out
->put_string(" style=\"margin-top: ");
189 out
->put_string(STYLE_VERTICAL_SPACE
);
190 out
->put_string("\"");
193 if (space
== true || space
== false)
194 out
->put_string(" valign=\"top\"");
196 out
->put_string(">");
200 * issue_color_begin - writes out an html color tag.
203 void html_text::issue_color_begin (color
*c
)
205 unsigned int r
, g
, b
;
208 out
->put_string("<font color=\"#");
210 sprintf(buf
, "000000");
212 c
->get_rgb(&r
, &g
, &b
);
213 // we have to scale 0..0xFFFF to 0..0xFF
214 sprintf(buf
, "%.2X%.2X%.2X", r
/0x101, g
/0x101, b
/0x101);
216 out
->put_string(buf
);
217 out
->put_string("\">");
221 * start_tag - starts a tag.
224 void html_text::start_tag (tag_definition
*t
)
228 case I_TAG
: issue_tag("<i", (char *)t
->arg1
); break;
229 case B_TAG
: issue_tag("<b", (char *)t
->arg1
); break;
230 case P_TAG
: if (t
->indent
!= NULL
) {
232 #if defined(DEBUGGING)
233 out
->simple_comment("INDENTATION");
235 out
->put_string("\n<p");
236 t
->indent
->begin(start_space
);
237 issue_tag("", (char *)t
->arg1
);
240 issue_tag("\n<p", (char *)t
->arg1
, start_space
);
243 out
->enable_newlines(true); break;
244 case SUB_TAG
: issue_tag("<sub", (char *)t
->arg1
); break;
245 case SUP_TAG
: issue_tag("<sup", (char *)t
->arg1
); break;
246 case TT_TAG
: issue_tag("<tt", (char *)t
->arg1
); break;
247 case PRE_TAG
: out
->enable_newlines(true);
248 out
->nl(); out
->put_string("<pre");
249 if (t
->indent
== NULL
)
250 issue_tag("", (char *)t
->arg1
, start_space
);
252 t
->indent
->begin(start_space
);
253 issue_tag("", (char *)t
->arg1
);
255 out
->enable_newlines(false); break;
256 case SMALL_TAG
: if (! is_in_pre ())
257 issue_tag("<small", (char *)t
->arg1
);
259 case BIG_TAG
: if (! is_in_pre ())
260 issue_tag("<big", (char *)t
->arg1
);
262 case BREAK_TAG
: break;
263 case COLOR_TAG
: if (! is_in_pre ())
264 issue_color_begin(&t
->col
);
268 error("unrecognised tag");
273 * flush_text - flushes html tags which are outstanding on the html stack.
276 void html_text::flush_text (void)
279 tag_definition
*p
=stackptr
;
281 while (stackptr
!= 0) {
282 notext
= (notext
&& (! stackptr
->text_emitted
));
287 stackptr
= stackptr
->next
;
294 * is_present - returns true if tag is already present on the stack.
297 int html_text::is_present (HTML_TAG t
)
299 tag_definition
*p
=stackptr
;
310 * uses_indent - returns true if the current paragraph is using a
311 * html table to effect an indent.
314 int html_text::uses_indent (void)
316 tag_definition
*p
= stackptr
;
319 if (p
->indent
!= NULL
)
329 * do_push - places, tag_definition, p, onto the stack
332 void html_text::do_push (tag_definition
*p
)
334 HTML_TAG t
= p
->type
;
336 #if defined(DEBUGGING)
340 fprintf(stderr
, "\nentering do_push (");
341 dump_stack_element(p
);
342 fprintf(stderr
, ")\n");
344 fprintf(stderr
, ")\n");
349 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
352 if (((t
== P_TAG
) || (t
== PRE_TAG
)) && (lastptr
!= NULL
)) {
354 * store, p, at the end
361 if (stackptr
== NULL
)
366 #if defined(DEBUGGING)
368 fprintf(stderr
, "exiting do_push\n");
373 * push_para - adds a new entry onto the html paragraph stack.
376 void html_text::push_para (HTML_TAG t
, void *arg
, html_indent
*in
)
378 tag_definition
*p
= new tag_definition
;
382 p
->text_emitted
= false;
385 if (t
== PRE_TAG
&& is_present(PRE_TAG
))
386 fatal("cannot have multiple PRE_TAGs");
391 void html_text::push_para (HTML_TAG t
)
393 push_para(t
, (void *)"", NULL
);
396 void html_text::push_para (color
*c
)
398 tag_definition
*p
= new tag_definition
;
403 p
->text_emitted
= false;
410 * do_italic - changes to italic
413 void html_text::do_italic (void)
415 if (! is_present(I_TAG
))
420 * do_bold - changes to bold.
423 void html_text::do_bold (void)
425 if (! is_present(B_TAG
))
430 * do_tt - changes to teletype.
433 void html_text::do_tt (void)
435 if ((! is_present(TT_TAG
)) && (! is_present(PRE_TAG
)))
440 * do_pre - changes to preformated text.
443 void html_text::do_pre (void)
446 if (is_present(P_TAG
)) {
447 html_indent
*i
= remove_indent(P_TAG
);
448 int space
= retrieve_para_space();
450 if (! is_present(PRE_TAG
))
451 push_para(PRE_TAG
, NULL
, i
);
453 } else if (! is_present(PRE_TAG
))
454 push_para(PRE_TAG
, NULL
, NULL
);
459 * is_in_pre - returns true if we are currently within a preformatted
463 int html_text::is_in_pre (void)
465 return is_present(PRE_TAG
);
469 * do_color - initiates a new color tag.
472 void html_text::do_color (color
*c
)
474 shutdown(COLOR_TAG
); // shutdown a previous color tag, if present
479 * done_color - shutdown an outstanding color tag, if it exists.
482 void html_text::done_color (void)
488 * shutdown - shuts down an html tag.
491 char *html_text::shutdown (HTML_TAG t
)
496 tag_definition
*p
=stackptr
;
497 tag_definition
*temp
=NULL
;
501 while ((stackptr
!= NULL
) && (stackptr
->type
!= t
)) {
502 notext
= (notext
&& (! stackptr
->text_emitted
));
511 stackptr
= stackptr
->next
;
512 if (stackptr
== NULL
)
516 * push tag onto temp stack
523 * and examine stackptr
525 if ((stackptr
!= NULL
) && (stackptr
->type
== t
)) {
526 if (stackptr
->text_emitted
) {
530 arg
= (char *)stackptr
->arg1
;
533 stackptr
= stackptr
->next
;
534 if (stackptr
== NULL
)
536 if (p
->indent
!= NULL
)
542 * and restore unaffected tags
544 while (temp
!= NULL
) {
545 if (temp
->type
== COLOR_TAG
)
546 push_para(&temp
->col
);
548 push_para(temp
->type
, temp
->arg1
, temp
->indent
);
558 * done_bold - shuts downs a bold tag.
561 void html_text::done_bold (void)
567 * done_italic - shuts downs an italic tag.
570 void html_text::done_italic (void)
576 * done_sup - shuts downs a sup tag.
579 void html_text::done_sup (void)
585 * done_sub - shuts downs a sub tag.
588 void html_text::done_sub (void)
594 * done_tt - shuts downs a tt tag.
597 void html_text::done_tt (void)
603 * done_pre - shuts downs a pre tag.
606 void html_text::done_pre (void)
612 * done_small - shuts downs a small tag.
615 void html_text::done_small (void)
621 * done_big - shuts downs a big tag.
624 void html_text::done_big (void)
630 * check_emit_text - ensures that all previous tags have been emitted (in order)
631 * before the text is written.
634 void html_text::check_emit_text (tag_definition
*t
)
636 if ((t
!= NULL
) && (! t
->text_emitted
)) {
637 check_emit_text(t
->next
);
638 t
->text_emitted
= true;
644 * do_emittext - tells the class that text was written during the current tag.
647 void html_text::do_emittext (const char *s
, int length
)
649 if ((! is_present(P_TAG
)) && (! is_present(PRE_TAG
)))
652 if (is_present(BREAK_TAG
)) {
653 int text
= remove_break();
654 check_emit_text(stackptr
);
656 if (is_present(PRE_TAG
))
658 else if (dialect
== xhtml
)
659 out
->put_string("<br/>").nl();
661 out
->put_string("<br>").nl();
664 check_emit_text(stackptr
);
666 out
->put_string(s
, length
);
667 space_emitted
= false;
672 * do_para - starts a new paragraph
675 void html_text::do_para (const char *arg
, html_indent
*in
, int space
)
677 if (! is_present(P_TAG
)) {
678 if (is_present(PRE_TAG
)) {
679 html_indent
*i
= remove_indent(PRE_TAG
);
681 if ((arg
== NULL
|| (strcmp(arg
, "") == 0)) &&
682 (i
== in
|| in
== NULL
))
688 push_para(P_TAG
, (void *)arg
, in
);
693 void html_text::do_para (const char *arg
, int space
)
695 do_para(arg
, NULL
, space
);
698 void html_text::do_para (simple_output
*op
, const char *arg1
,
699 int indentation_value
, int page_offset
,
700 int line_length
, int space
)
704 if (indentation_value
== 0)
707 ind
= new html_indent(op
, indentation_value
, page_offset
, line_length
);
708 do_para(arg1
, ind
, space
);
712 * done_para - shuts down a paragraph tag.
715 char *html_text::done_para (void)
718 space_emitted
= true;
719 result
= shutdown(P_TAG
);
725 * remove_indent - returns the indent associated with, tag.
726 * The indent associated with tag is set to NULL.
729 html_indent
*html_text::remove_indent (HTML_TAG tag
)
731 tag_definition
*p
=stackptr
;
734 if (tag
== p
->type
) {
735 html_indent
*i
= p
->indent
;
745 * remove_para_space - removes the leading space to a paragraph
746 * (effectively this trims off a leading `.sp' tag).
749 void html_text::remove_para_space (void)
755 * do_space - issues an end of paragraph
758 void html_text::do_space (void)
763 space_emitted
= true;
765 html_indent
*i
= remove_indent(P_TAG
);
767 do_para(done_para(), i
, true);
768 space_emitted
= true;
773 * do_break - issue a break tag.
776 void html_text::do_break (void)
778 if (! is_present(PRE_TAG
))
780 if (! is_present(BREAK_TAG
))
781 push_para(BREAK_TAG
);
783 space_emitted
= true;
787 * do_newline - issue a newline providing that we are inside a <pre> tag.
790 void html_text::do_newline (void)
792 if (is_present(PRE_TAG
)) {
793 do_emittext("\n", 1);
794 space_emitted
= true;
799 * emitted_text - returns false if white space has just been written.
802 int html_text::emitted_text (void)
804 return !space_emitted
;
808 * ever_emitted_text - returns true if we have ever emitted text in this
812 int html_text::ever_emitted_text (void)
818 * starts_with_space - returns true if we started this paragraph with a .sp
821 int html_text::starts_with_space (void)
827 * retrieve_para_space - returns true, if the paragraph starts with
828 * a space and text has not yet been emitted.
829 * If true is returned, then the, start_space,
830 * variable is set to false.
833 int html_text::retrieve_para_space (void)
835 if (start_space
&& blank_para
) {
844 * emit_space - writes a space providing that text was written beforehand.
847 void html_text::emit_space (void)
849 if (is_present(PRE_TAG
))
852 out
->space_or_newline();
854 space_emitted
= true;
858 * remove_def - removes a definition, t, from the stack.
861 void html_text::remove_def (tag_definition
*t
)
863 tag_definition
*p
= stackptr
;
864 tag_definition
*l
= 0;
865 tag_definition
*q
= 0;
867 while ((p
!= 0) && (p
!= t
)) {
871 if ((p
!= 0) && (p
== t
)) {
873 stackptr
= stackptr
->next
;
874 if (stackptr
== NULL
)
878 error("stack list pointers are wrong");
890 * remove_tag - removes a tag from the stack.
893 void html_text::remove_tag (HTML_TAG tag
)
895 tag_definition
*p
= stackptr
;
897 while ((p
!= 0) && (p
->type
!= tag
)) {
900 if ((p
!= 0) && (p
->type
== tag
))
905 * remove_sub_sup - removes a sub or sup tag, should either exist
909 void html_text::remove_sub_sup (void)
911 if (is_present(SUB_TAG
)) {
914 if (is_present(SUP_TAG
)) {
917 if (is_present(PRE_TAG
)) {
923 * remove_break - break tags are not balanced thus remove it once it has been emitted.
924 * It returns true if text was emitted before the <br> was issued.
927 int html_text::remove_break (void)
929 tag_definition
*p
= stackptr
;
930 tag_definition
*l
= 0;
931 tag_definition
*q
= 0;
933 while ((p
!= 0) && (p
->type
!= BREAK_TAG
)) {
937 if ((p
!= 0) && (p
->type
== BREAK_TAG
)) {
939 stackptr
= stackptr
->next
;
940 if (stackptr
== NULL
)
944 error("stack list pointers are wrong");
954 * now determine whether text was issued before <br>
966 * remove_para_align - removes a paragraph which has a text
967 * argument. If the paragraph has no text
968 * argument then it is left alone.
971 void html_text::remove_para_align (void)
973 if (is_present(P_TAG
)) {
974 tag_definition
*p
=stackptr
;
977 if (p
->type
== P_TAG
&& p
->arg1
!= NULL
) {
978 html_indent
*i
= remove_indent(P_TAG
);
979 int space
= retrieve_para_space();
981 do_para("", i
, space
);
990 * get_alignment - returns the alignment for the paragraph.
991 * If no alignment was given then we return "".
994 char *html_text::get_alignment (void)
996 if (is_present(P_TAG
)) {
997 tag_definition
*p
=stackptr
;
1000 if (p
->type
== P_TAG
&& p
->arg1
!= NULL
)
1001 return (char *)p
->arg1
;
1009 * do_small - potentially inserts a <small> tag into the html stream.
1010 * However we check for a <big> tag, if present then we terminate it.
1011 * Otherwise a <small> tag is inserted.
1014 void html_text::do_small (void)
1016 if (is_present(BIG_TAG
))
1019 push_para(SMALL_TAG
);
1023 * do_big - is the mirror image of do_small.
1026 void html_text::do_big (void)
1028 if (is_present(SMALL_TAG
))
1035 * do_sup - save a superscript tag on the stack of tags.
1038 void html_text::do_sup (void)
1044 * do_sub - save a subscript tag on the stack of tags.
1047 void html_text::do_sub (void)