2 /* Copyright (C) 2000, 2001, 2002, 2003, 2004 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 2, or (at your option) any later
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 along
26 with groff; see the file COPYING. If not, write to the Free Software
27 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
30 #include "stringclass.h"
41 #include "html-text.h"
45 html_text::html_text (simple_output
*op
) :
46 stackptr(NULL
), lastptr(NULL
), out(op
), space_emitted(TRUE
),
47 current_indentation(-1), pageoffset(-1), linelength(-1),
48 blank_para(TRUE
), start_space(FALSE
)
52 html_text::~html_text ()
58 #if defined(DEBUGGING)
59 static int debugStack
= FALSE
;
63 * turnDebug - flip the debugStack boolean and return the new value.
66 static int turnDebug (void)
68 debugStack
= 1-debugStack
;
73 * dump_stack_element - display an element of the html stack, p.
76 void html_text::dump_stack_element (tag_definition
*p
)
78 fprintf(stderr
, " | ");
81 case P_TAG
: if (p
->indent
== NULL
) {
82 fprintf(stderr
, "<P %s>", (char *)p
->arg1
); break;
84 fprintf(stderr
, "<P %s [TABLE]>", (char *)p
->arg1
); break;
86 case I_TAG
: fprintf(stderr
, "<I>"); break;
87 case B_TAG
: fprintf(stderr
, "<B>"); break;
88 case SUB_TAG
: fprintf(stderr
, "<SUB>"); break;
89 case SUP_TAG
: fprintf(stderr
, "<SUP>"); break;
90 case TT_TAG
: fprintf(stderr
, "<TT>"); break;
91 case PRE_TAG
: if (p
->indent
== NULL
) {
92 fprintf(stderr
, "<PRE>"); break;
94 fprintf(stderr
, "<PRE [TABLE]>"); break;
96 case SMALL_TAG
: fprintf(stderr
, "<SMALL>"); break;
97 case BIG_TAG
: fprintf(stderr
, "<BIG>"); break;
98 case BREAK_TAG
: fprintf(stderr
, "<BREAK>"); break;
100 if (p
->col
.is_default())
101 fprintf(stderr
, "<COLOR (default)>");
103 unsigned int r
, g
, b
;
105 p
->col
.get_rgb(&r
, &g
, &b
);
106 fprintf(stderr
, "<COLOR %x %x %x>", r
/0x101, g
/0x101, b
/0x101);
110 default: fprintf(stderr
, "unknown tag");
113 fprintf(stderr
, "[t] ");
117 * dump_stack - debugging function only.
120 void html_text::dump_stack (void)
123 tag_definition
*p
= stackptr
;
126 dump_stack_element(p
);
130 fprintf(stderr
, "\n");
134 void html_text::dump_stack (void) {}
139 * end_tag - shuts down the tag.
142 void html_text::end_tag (tag_definition
*t
)
146 case I_TAG
: out
->put_string("</i>"); break;
147 case B_TAG
: out
->put_string("</b>"); break;
148 case P_TAG
: out
->put_string("</p>");
149 if (t
->indent
!= NULL
) {
153 out
->nl(); out
->enable_newlines(FALSE
);
154 blank_para
= TRUE
; break;
155 case SUB_TAG
: out
->put_string("</sub>"); break;
156 case SUP_TAG
: out
->put_string("</sup>"); break;
157 case TT_TAG
: out
->put_string("</tt>"); break;
158 case PRE_TAG
: out
->put_string("</pre>"); out
->nl(); out
->enable_newlines(TRUE
);
159 blank_para
= TRUE
; break;
160 case SMALL_TAG
: out
->put_string("</small>"); break;
161 case BIG_TAG
: out
->put_string("</big>"); break;
162 case COLOR_TAG
: out
->put_string("</font>"); break;
165 error("unrecognised tag");
170 * issue_tag - writes out an html tag with argument.
173 void html_text::issue_tag (const char *tagname
, const char *arg
)
175 if ((arg
== 0) || (strlen(arg
) == 0)) {
176 out
->put_string(tagname
);
177 out
->put_string(">");
179 out
->put_string(tagname
);
180 out
->put_string(" ");
181 out
->put_string(arg
);
182 out
->put_string(">");
187 * issue_color_begin - writes out an html color tag.
190 void html_text::issue_color_begin (color
*c
)
192 unsigned int r
, g
, b
;
195 out
->put_string("<font color=\"#");
197 sprintf(buf
, "000000");
199 c
->get_rgb(&r
, &g
, &b
);
200 // we have to scale 0..0xFFFF to 0..0xFF
201 sprintf(buf
, "%.2X%.2X%.2X", r
/0x101, g
/0x101, b
/0x101);
203 out
->put_string(buf
);
204 out
->put_string("\">");
208 * start_tag - starts a tag.
211 void html_text::start_tag (tag_definition
*t
)
215 case I_TAG
: issue_tag("<i", (char *)t
->arg1
); break;
216 case B_TAG
: issue_tag("<b", (char *)t
->arg1
); break;
217 case P_TAG
: if (t
->indent
== NULL
) {
219 issue_tag("\n<p", (char *)t
->arg1
);
222 out
->simple_comment("INDENTATION");
223 t
->indent
->begin(FALSE
);
225 issue_tag("<p", (char *)t
->arg1
);
228 out
->enable_newlines(TRUE
); break;
229 case SUB_TAG
: issue_tag("<sub", (char *)t
->arg1
); break;
230 case SUP_TAG
: issue_tag("<sup", (char *)t
->arg1
); break;
231 case TT_TAG
: issue_tag("<tt", (char *)t
->arg1
); break;
232 case PRE_TAG
: if (t
->indent
!= NULL
) {
234 out
->simple_comment("INDENTATION");
235 t
->indent
->begin(FALSE
);
238 out
->enable_newlines(TRUE
);
239 out
->nl(); issue_tag("<pre", (char *)t
->arg1
);
240 out
->enable_newlines(FALSE
); break;
241 case SMALL_TAG
: issue_tag("<small", (char *)t
->arg1
); break;
242 case BIG_TAG
: issue_tag("<big", (char *)t
->arg1
); break;
243 case BREAK_TAG
: break;
244 case COLOR_TAG
: issue_color_begin(&t
->col
); break;
247 error("unrecognised tag");
252 * flush_text - flushes html tags which are outstanding on the html stack.
255 void html_text::flush_text (void)
258 tag_definition
*p
=stackptr
;
260 while (stackptr
!= 0) {
261 notext
= (notext
&& (! stackptr
->text_emitted
));
266 stackptr
= stackptr
->next
;
273 * is_present - returns TRUE if tag is already present on the stack.
276 int html_text::is_present (HTML_TAG t
)
278 tag_definition
*p
=stackptr
;
291 * do_push - places, tag_definition, p, onto the stack
294 void html_text::do_push (tag_definition
*p
)
296 HTML_TAG t
= p
->type
;
298 #if defined(DEBUGGING)
302 fprintf(stderr
, "\nentering do_push (");
303 dump_stack_element(p
);
304 fprintf(stderr
, ")\n");
306 fprintf(stderr
, ")\n");
311 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
314 if (((t
== P_TAG
) || (t
== PRE_TAG
)) && (lastptr
!= NULL
)) {
316 * store, p, at the end
323 if (stackptr
== NULL
)
328 #if defined(DEBUGGING)
330 fprintf(stderr
, "exiting do_push\n");
335 * push_para - adds a new entry onto the html paragraph stack.
338 void html_text::push_para (HTML_TAG t
, void *arg
, html_indent
*in
)
340 tag_definition
*p
=(tag_definition
*)malloc(sizeof(tag_definition
));
344 p
->text_emitted
= FALSE
;
347 if (t
== PRE_TAG
&& is_present(PRE_TAG
))
348 fatal("cannot have multiple PRE_TAGs");
353 void html_text::push_para (HTML_TAG t
)
355 push_para(t
, (void *)"", NULL
);
358 void html_text::push_para (color
*c
)
360 tag_definition
*p
=(tag_definition
*)malloc(sizeof(tag_definition
));
365 p
->text_emitted
= FALSE
;
372 * do_italic - changes to italic
375 void html_text::do_italic (void)
377 if (! is_present(I_TAG
))
382 * do_bold - changes to bold.
385 void html_text::do_bold (void)
387 if (! is_present(B_TAG
))
392 * do_tt - changes to teletype.
395 void html_text::do_tt (void)
397 if ((! is_present(TT_TAG
)) && (! is_present(PRE_TAG
)))
402 * do_pre - changes to preformated text.
405 void html_text::do_pre (void)
408 if (is_present(P_TAG
)) {
409 html_indent
*i
= remove_indent(P_TAG
);
411 if (! is_present(PRE_TAG
))
412 push_para(PRE_TAG
, NULL
, i
);
413 } else if (! is_present(PRE_TAG
))
414 push_para(PRE_TAG
, NULL
, NULL
);
419 * is_in_pre - returns TRUE if we are currently within a preformatted
423 int html_text::is_in_pre (void)
425 return is_present(PRE_TAG
);
429 * do_color - initiates a new color tag.
432 void html_text::do_color (color
*c
)
434 shutdown(COLOR_TAG
); // shutdown a previous color tag, if present
439 * done_color - shutdown an outstanding color tag, if it exists.
442 void html_text::done_color (void)
448 * shutdown - shuts down an html tag.
451 char *html_text::shutdown (HTML_TAG t
)
456 tag_definition
*p
=stackptr
;
457 tag_definition
*temp
=NULL
;
461 while ((stackptr
!= NULL
) && (stackptr
->type
!= t
)) {
462 notext
= (notext
&& (! stackptr
->text_emitted
));
471 stackptr
= stackptr
->next
;
472 if (stackptr
== NULL
)
476 * push tag onto temp stack
483 * and examine stackptr
485 if ((stackptr
!= NULL
) && (stackptr
->type
== t
)) {
486 if (stackptr
->text_emitted
) {
490 arg
= (char *)stackptr
->arg1
;
493 stackptr
= stackptr
->next
;
494 if (stackptr
== NULL
)
496 if (p
->indent
!= NULL
)
502 * and restore unaffected tags
504 while (temp
!= NULL
) {
505 if (temp
->type
== COLOR_TAG
)
506 push_para(&temp
->col
);
508 push_para(temp
->type
, temp
->arg1
, temp
->indent
);
518 * done_bold - shuts downs a bold tag.
521 void html_text::done_bold (void)
527 * done_italic - shuts downs an italic tag.
530 void html_text::done_italic (void)
536 * done_sup - shuts downs a sup tag.
539 void html_text::done_sup (void)
545 * done_sub - shuts downs a sub tag.
548 void html_text::done_sub (void)
554 * done_tt - shuts downs a tt tag.
557 void html_text::done_tt (void)
563 * done_pre - shuts downs a pre tag.
566 void html_text::done_pre (void)
572 * done_small - shuts downs a small tag.
575 void html_text::done_small (void)
581 * done_big - shuts downs a big tag.
584 void html_text::done_big (void)
590 * check_emit_text - ensures that all previous tags have been emitted (in order)
591 * before the text is written.
594 void html_text::check_emit_text (tag_definition
*t
)
596 if ((t
!= NULL
) && (! t
->text_emitted
)) {
597 check_emit_text(t
->next
);
598 t
->text_emitted
= TRUE
;
604 * do_emittext - tells the class that text was written during the current tag.
607 void html_text::do_emittext (const char *s
, int length
)
609 if ((! is_present(P_TAG
)) && (! is_present(PRE_TAG
)))
612 if (is_present(BREAK_TAG
)) {
613 int text
= remove_break();
614 check_emit_text(stackptr
);
616 if (is_present(PRE_TAG
)) {
619 out
->put_string("<br>").nl();
623 check_emit_text(stackptr
);
625 out
->put_string(s
, length
);
626 space_emitted
= FALSE
;
631 * do_para - starts a new paragraph
634 void html_text::do_para (const char *arg
, html_indent
*in
)
636 if (! is_present(P_TAG
)) {
637 if (is_present(PRE_TAG
)) {
638 html_indent
*i
= remove_indent(PRE_TAG
);
640 if (i
== in
|| in
== NULL
)
646 push_para(P_TAG
, (void *)arg
, in
);
647 space_emitted
= TRUE
;
651 void html_text::do_para (const char *arg
)
656 void html_text::do_para (simple_output
*op
, const char *arg1
,
657 int indentation_value
, int page_offset
,
662 if (indentation_value
== 0)
665 ind
= new html_indent(op
, indentation_value
, page_offset
, line_length
);
670 * done_para - shuts down a paragraph tag.
673 char *html_text::done_para (void)
675 space_emitted
= TRUE
;
676 return shutdown(P_TAG
);
680 * remove_indent - returns the indent associated with, tag.
681 * The indent associated with tag is set to NULL.
684 html_indent
*html_text::remove_indent (HTML_TAG tag
)
686 tag_definition
*p
=stackptr
;
689 if (tag
== p
->type
) {
690 html_indent
*i
= p
->indent
;
700 * do_space - issues an end of paragraph
703 void html_text::do_space (void)
711 space_emitted
= TRUE
;
714 html_indent
*i
= remove_indent(P_TAG
);
716 do_para(done_para(), i
);
717 space_emitted
= TRUE
;
723 * do_break - issue a break tag.
726 void html_text::do_break (void)
728 if (! is_present(PRE_TAG
)) {
729 if (emitted_text()) {
730 if (! is_present(BREAK_TAG
)) {
731 push_para(BREAK_TAG
);
735 space_emitted
= TRUE
;
739 * do_newline - issue a newline providing that we are inside a <pre> tag.
742 void html_text::do_newline (void)
744 if (is_present(PRE_TAG
)) {
745 do_emittext("\n", 1);
746 space_emitted
= TRUE
;
751 * emitted_text - returns FALSE if white space has just been written.
754 int html_text::emitted_text (void)
756 return !space_emitted
;
760 * ever_emitted_text - returns TRUE if we have ever emitted text in this paragraph.
763 int html_text::ever_emitted_text (void)
769 * starts_with_space - returns TRUE if we have start this paragraph with a .sp
772 int html_text::starts_with_space (void)
778 * emit_space - writes a space providing that text was written beforehand.
781 void html_text::emit_space (void)
784 if (is_present(PRE_TAG
)) {
788 out
->space_or_newline();
789 space_emitted
= TRUE
;
794 * remove_def - removes a definition, t, from the stack.
797 void html_text::remove_def (tag_definition
*t
)
799 tag_definition
*p
= stackptr
;
800 tag_definition
*l
= 0;
801 tag_definition
*q
= 0;
803 while ((p
!= 0) && (p
!= t
)) {
807 if ((p
!= 0) && (p
== t
)) {
809 stackptr
= stackptr
->next
;
810 if (stackptr
== NULL
)
814 error("stack list pointers are wrong");
826 * remove_tag - removes a tag from the stack.
829 void html_text::remove_tag (HTML_TAG tag
)
831 tag_definition
*p
= stackptr
;
833 while ((p
!= 0) && (p
->type
!= tag
)) {
836 if ((p
!= 0) && (p
->type
== tag
))
841 * remove_sub_sup - removes a sub or sup tag, should either exist on the stack.
844 void html_text::remove_sub_sup (void)
846 if (is_present(SUB_TAG
)) {
849 if (is_present(SUP_TAG
)) {
852 if (is_present(PRE_TAG
)) {
858 * remove_break - break tags are not balanced thus remove it once it has been emitted.
859 * It returns TRUE if text was emitted before the <br> was issued.
862 int html_text::remove_break (void)
864 tag_definition
*p
= stackptr
;
865 tag_definition
*l
= 0;
866 tag_definition
*q
= 0;
868 while ((p
!= 0) && (p
->type
!= BREAK_TAG
)) {
872 if ((p
!= 0) && (p
->type
== BREAK_TAG
)) {
874 stackptr
= stackptr
->next
;
875 if (stackptr
== NULL
)
879 error("stack list pointers are wrong");
889 * now determine whether text was issued before <br>
901 * remove_para_align - removes a paragraph which has a text
902 * argument. If the paragraph has no text
903 * argument then it is left alone.
906 void html_text::remove_para_align (void)
908 if (is_present(P_TAG
)) {
909 tag_definition
*p
=stackptr
;
912 if (p
->type
== P_TAG
&& p
->arg1
!= NULL
) {
913 html_indent
*i
= remove_indent(P_TAG
);
924 * do_small - potentially inserts a <small> tag into the html stream.
925 * However we check for a <big> tag, if present then we terminate it.
926 * Otherwise a <small> tag is inserted.
929 void html_text::do_small (void)
931 if (is_present(BIG_TAG
))
934 push_para(SMALL_TAG
);
938 * do_big - is the mirror image of do_small.
941 void html_text::do_big (void)
943 if (is_present(SMALL_TAG
))
950 * do_sup - save a superscript tag on the stack of tags.
953 void html_text::do_sup (void)
959 * do_sub - save a subscript tag on the stack of tags.
962 void html_text::do_sub (void)