1 // -*- C++ -*-
2 /* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
3 * Free Software Foundation, Inc.
4 *
5 * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp
6 *
7 * html-text.cpp
8 *
9 * provide a troff like state machine interface which
10 * generates html text.
11 */
12
13 /*
14 This file is part of groff.
15
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
19 version.
20
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
24 for more details.
25
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. */
29
30 #include "driver.h"
31 #include "stringclass.h"
32 #include "cset.h"
33
34 #if !defined(TRUE)
35 # define TRUE (1==1)
36 #endif
37 #if !defined(FALSE)
38 # define FALSE (1==0)
39 #endif
40
41
42 #include "html-text.h"
43
44 #undef DEBUGGING
45 // #define DEBUGGING
46
html_text(simple_output * op)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)
51 {
52 }
53
~html_text()54 html_text::~html_text ()
55 {
56 flush_text();
57 }
58
59
60 #if defined(DEBUGGING)
61 static int debugStack = FALSE;
62
63
64 /*
65 * turnDebug - flip the debugStack boolean and return the new value.
66 */
67
turnDebug(void)68 static int turnDebug (void)
69 {
70 debugStack = 1-debugStack;
71 return debugStack;
72 }
73
74 /*
75 * dump_stack_element - display an element of the html stack, p.
76 */
77
dump_stack_element(tag_definition * p)78 void html_text::dump_stack_element (tag_definition *p)
79 {
80 fprintf(stderr, " | ");
81 switch (p->type) {
82
83 case P_TAG: if (p->indent == NULL) {
84 fprintf(stderr, "<P %s>", (char *)p->arg1); break;
85 } else {
86 fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
87 }
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;
95 } else {
96 fprintf(stderr, "<PRE [TABLE]>"); break;
97 }
98 case SMALL_TAG: fprintf(stderr, "<SMALL>"); break;
99 case BIG_TAG: fprintf(stderr, "<BIG>"); break;
100 case BREAK_TAG: fprintf(stderr, "<BREAK>"); break;
101 case COLOR_TAG: {
102 if (p->col.is_default())
103 fprintf(stderr, "<COLOR (default)>");
104 else {
105 unsigned int r, g, b;
106
107 p->col.get_rgb(&r, &g, &b);
108 fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
109 }
110 break;
111 }
112 default: fprintf(stderr, "unknown tag");
113 }
114 if (p->text_emitted)
115 fprintf(stderr, "[t] ");
116 }
117
118 /*
119 * dump_stack - debugging function only.
120 */
121
dump_stack(void)122 void html_text::dump_stack (void)
123 {
124 if (debugStack) {
125 tag_definition *p = stackptr;
126
127 while (p != NULL) {
128 dump_stack_element(p);
129 p = p->next;
130 }
131 }
132 fprintf(stderr, "\n");
133 fflush(stderr);
134 }
135 #else
dump_stack(void)136 void html_text::dump_stack (void) {}
137 #endif
138
139
140 /*
141 * end_tag - shuts down the tag.
142 */
143
end_tag(tag_definition * t)144 void html_text::end_tag (tag_definition *t)
145 {
146 switch (t->type) {
147
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>");
152 } else {
153 delete t->indent;
154 t->indent = NULL;
155 out->put_string("</p>");
156 }
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);
163 blank_para = TRUE;
164 if (t->indent != NULL)
165 delete t->indent;
166 t->indent = NULL;
167 break;
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;
171
172 default:
173 error("unrecognised tag");
174 }
175 }
176
177 /*
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
182 */
183
issue_tag(const char * tagname,const char * arg,int space)184 void html_text::issue_tag (const char *tagname, const char *arg,
185 int space)
186 {
187 if ((arg == 0) || (strlen(arg) == 0))
188 out->put_string(tagname);
189 else {
190 out->put_string(tagname);
191 out->put_string(" ");
192 out->put_string(arg);
193 }
194 if (space == TRUE) {
195 out->put_string(" style=\"margin-top: ");
196 out->put_string(STYLE_VERTICAL_SPACE);
197 out->put_string("\"");
198 }
199 if (space == TRUE || space == FALSE)
200 out->put_string(" valign=\"top\"");
201 out->put_string(">");
202 }
203
204 /*
205 * issue_color_begin - writes out an html color tag.
206 */
207
issue_color_begin(color * c)208 void html_text::issue_color_begin (color *c)
209 {
210 unsigned int r, g, b;
211 char buf[6+1];
212
213 out->put_string("<font color=\"#");
214 if (c->is_default())
215 sprintf(buf, "000000");
216 else {
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);
220 }
221 out->put_string(buf);
222 out->put_string("\">");
223 }
224
225 /*
226 * start_tag - starts a tag.
227 */
228
start_tag(tag_definition * t)229 void html_text::start_tag (tag_definition *t)
230 {
231 switch (t->type) {
232
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) {
236 out->nl();
237 #if defined(DEBUGGING)
238 out->simple_comment("INDENTATION");
239 #endif
240 out->put_string("\n<p");
241 t->indent->begin(start_space);
242 issue_tag("", (char *)t->arg1);
243 } else {
244 out->nl();
245 issue_tag("\n<p", (char *)t->arg1, start_space);
246 }
247
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);
256 else {
257 t->indent->begin(start_space);
258 issue_tag("", (char *)t->arg1);
259 }
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;
265
266 default:
267 error("unrecognised tag");
268 }
269 }
270
271 /*
272 * flush_text - flushes html tags which are outstanding on the html stack.
273 */
274
flush_text(void)275 void html_text::flush_text (void)
276 {
277 int notext=TRUE;
278 tag_definition *p=stackptr;
279
280 while (stackptr != 0) {
281 notext = (notext && (! stackptr->text_emitted));
282 if (! notext) {
283 end_tag(stackptr);
284 }
285 p = stackptr;
286 stackptr = stackptr->next;
287 delete p;
288 }
289 lastptr = NULL;
290 }
291
292 /*
293 * is_present - returns TRUE if tag is already present on the stack.
294 */
295
is_present(HTML_TAG t)296 int html_text::is_present (HTML_TAG t)
297 {
298 tag_definition *p=stackptr;
299
300 while (p != NULL) {
301 if (t == p->type)
302 return TRUE;
303 p = p->next;
304 }
305 return FALSE;
306 }
307
308 /*
309 * uses_indent - returns TRUE if the current paragraph is using a
310 * html table to effect an indent.
311 */
312
uses_indent(void)313 int html_text::uses_indent (void)
314 {
315 tag_definition *p = stackptr;
316
317 while (p != NULL) {
318 if (p->indent != NULL)
319 return TRUE;
320 p = p->next;
321 }
322 return FALSE;
323 }
324
325 extern void stop();
326
327 /*
328 * do_push - places, tag_definition, p, onto the stack
329 */
330
do_push(tag_definition * p)331 void html_text::do_push (tag_definition *p)
332 {
333 HTML_TAG t = p->type;
334
335 #if defined(DEBUGGING)
336 if (t == PRE_TAG)
337 stop();
338 debugStack = TRUE;
339 fprintf(stderr, "\nentering do_push (");
340 dump_stack_element(p);
341 fprintf(stderr, ")\n");
342 dump_stack();
343 fprintf(stderr, ")\n");
344 fflush(stderr);
345 #endif
346
347 /*
348 * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
349 */
350
351 if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
352 /*
353 * store, p, at the end
354 */
355 lastptr->next = p;
356 lastptr = p;
357 p->next = NULL;
358 } else {
359 p->next = stackptr;
360 if (stackptr == NULL)
361 lastptr = p;
362 stackptr = p;
363 }
364
365 #if defined(DEBUGGING)
366 dump_stack();
367 fprintf(stderr, "exiting do_push\n");
368 #endif
369 }
370
371 /*
372 * push_para - adds a new entry onto the html paragraph stack.
373 */
374
push_para(HTML_TAG t,void * arg,html_indent * in)375 void html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
376 {
377 tag_definition *p= new tag_definition;
378
379 p->type = t;
380 p->arg1 = arg;
381 p->text_emitted = FALSE;
382 p->indent = in;
383
384 if (t == PRE_TAG && is_present(PRE_TAG))
385 fatal("cannot have multiple PRE_TAGs");
386
387 do_push(p);
388 }
389
push_para(HTML_TAG t)390 void html_text::push_para (HTML_TAG t)
391 {
392 push_para(t, (void *)"", NULL);
393 }
394
push_para(color * c)395 void html_text::push_para (color *c)
396 {
397 tag_definition *p = new tag_definition;
398
399 p->type = COLOR_TAG;
400 p->arg1 = NULL;
401 p->col = *c;
402 p->text_emitted = FALSE;
403 p->indent = NULL;
404
405 do_push(p);
406 }
407
408 /*
409 * do_italic - changes to italic
410 */
411
do_italic(void)412 void html_text::do_italic (void)
413 {
414 if (! is_present(I_TAG))
415 push_para(I_TAG);
416 }
417
418 /*
419 * do_bold - changes to bold.
420 */
421
do_bold(void)422 void html_text::do_bold (void)
423 {
424 if (! is_present(B_TAG))
425 push_para(B_TAG);
426 }
427
428 /*
429 * do_tt - changes to teletype.
430 */
431
do_tt(void)432 void html_text::do_tt (void)
433 {
434 if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
435 push_para(TT_TAG);
436 }
437
438 /*
439 * do_pre - changes to preformated text.
440 */
441
do_pre(void)442 void html_text::do_pre (void)
443 {
444 done_tt();
445 if (is_present(P_TAG)) {
446 html_indent *i = remove_indent(P_TAG);
447 int space = retrieve_para_space();
448 (void)done_para();
449 if (! is_present(PRE_TAG))
450 push_para(PRE_TAG, NULL, i);
451 start_space = space;
452 } else if (! is_present(PRE_TAG))
453 push_para(PRE_TAG, NULL, NULL);
454 dump_stack();
455 }
456
457 /*
458 * is_in_pre - returns TRUE if we are currently within a preformatted
459 * <pre> block.
460 */
461
is_in_pre(void)462 int html_text::is_in_pre (void)
463 {
464 return is_present(PRE_TAG);
465 }
466
467 /*
468 * do_color - initiates a new color tag.
469 */
470
do_color(color * c)471 void html_text::do_color (color *c)
472 {
473 shutdown(COLOR_TAG); // shutdown a previous color tag, if present
474 push_para(c);
475 }
476
477 /*
478 * done_color - shutdown an outstanding color tag, if it exists.
479 */
480
done_color(void)481 void html_text::done_color (void)
482 {
483 shutdown(COLOR_TAG);
484 }
485
486 /*
487 * shutdown - shuts down an html tag.
488 */
489
shutdown(HTML_TAG t)490 char *html_text::shutdown (HTML_TAG t)
491 {
492 char *arg=NULL;
493
494 if (is_present(t)) {
495 tag_definition *p =stackptr;
496 tag_definition *temp =NULL;
497 int notext =TRUE;
498
499 dump_stack();
500 while ((stackptr != NULL) && (stackptr->type != t)) {
501 notext = (notext && (! stackptr->text_emitted));
502 if (! notext) {
503 end_tag(stackptr);
504 }
505
506 /*
507 * pop tag
508 */
509 p = stackptr;
510 stackptr = stackptr->next;
511 if (stackptr == NULL)
512 lastptr = NULL;
513
514 /*
515 * push tag onto temp stack
516 */
517 p->next = temp;
518 temp = p;
519 }
520
521 /*
522 * and examine stackptr
523 */
524 if ((stackptr != NULL) && (stackptr->type == t)) {
525 if (stackptr->text_emitted) {
526 end_tag(stackptr);
527 }
528 if (t == P_TAG) {
529 arg = (char *)stackptr->arg1;
530 }
531 p = stackptr;
532 stackptr = stackptr->next;
533 if (stackptr == NULL)
534 lastptr = NULL;
535 if (p->indent != NULL)
536 delete p->indent;
537 delete p;
538 }
539
540 /*
541 * and restore unaffected tags
542 */
543 while (temp != NULL) {
544 if (temp->type == COLOR_TAG)
545 push_para(&temp->col);
546 else
547 push_para(temp->type, temp->arg1, temp->indent);
548 p = temp;
549 temp = temp->next;
550 delete p;
551 }
552 }
553 return arg;
554 }
555
556 /*
557 * done_bold - shuts downs a bold tag.
558 */
559
done_bold(void)560 void html_text::done_bold (void)
561 {
562 shutdown(B_TAG);
563 }
564
565 /*
566 * done_italic - shuts downs an italic tag.
567 */
568
done_italic(void)569 void html_text::done_italic (void)
570 {
571 shutdown(I_TAG);
572 }
573
574 /*
575 * done_sup - shuts downs a sup tag.
576 */
577
done_sup(void)578 void html_text::done_sup (void)
579 {
580 shutdown(SUP_TAG);
581 }
582
583 /*
584 * done_sub - shuts downs a sub tag.
585 */
586
done_sub(void)587 void html_text::done_sub (void)
588 {
589 shutdown(SUB_TAG);
590 }
591
592 /*
593 * done_tt - shuts downs a tt tag.
594 */
595
done_tt(void)596 void html_text::done_tt (void)
597 {
598 shutdown(TT_TAG);
599 }
600
601 /*
602 * done_pre - shuts downs a pre tag.
603 */
604
done_pre(void)605 void html_text::done_pre (void)
606 {
607 shutdown(PRE_TAG);
608 }
609
610 /*
611 * done_small - shuts downs a small tag.
612 */
613
done_small(void)614 void html_text::done_small (void)
615 {
616 shutdown(SMALL_TAG);
617 }
618
619 /*
620 * done_big - shuts downs a big tag.
621 */
622
done_big(void)623 void html_text::done_big (void)
624 {
625 shutdown(BIG_TAG);
626 }
627
628 /*
629 * check_emit_text - ensures that all previous tags have been emitted (in order)
630 * before the text is written.
631 */
632
check_emit_text(tag_definition * t)633 void html_text::check_emit_text (tag_definition *t)
634 {
635 if ((t != NULL) && (! t->text_emitted)) {
636 check_emit_text(t->next);
637 t->text_emitted = TRUE;
638 start_tag(t);
639 }
640 }
641
642 /*
643 * do_emittext - tells the class that text was written during the current tag.
644 */
645
do_emittext(const char * s,int length)646 void html_text::do_emittext (const char *s, int length)
647 {
648 if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
649 do_para("", FALSE);
650
651 if (is_present(BREAK_TAG)) {
652 int text = remove_break();
653 check_emit_text(stackptr);
654 if (text) {
655 if (is_present(PRE_TAG)) {
656 out->nl();
657 } else
658 out->put_string("<br>").nl();
659 }
660 } else
661 check_emit_text(stackptr);
662
663 out->put_string(s, length);
664 space_emitted = FALSE;
665 blank_para = FALSE;
666 }
667
668 /*
669 * do_para - starts a new paragraph
670 */
671
do_para(const char * arg,html_indent * in,int space)672 void html_text::do_para (const char *arg, html_indent *in, int space)
673 {
674 if (! is_present(P_TAG)) {
675 if (is_present(PRE_TAG)) {
676 html_indent *i = remove_indent(PRE_TAG);
677 done_pre();
678 if ((arg == NULL || (strcmp(arg, "") == 0)) &&
679 (i == in || in == NULL))
680 in = i;
681 else
682 delete i;
683 }
684 remove_sub_sup();
685 push_para(P_TAG, (void *)arg, in);
686 start_space = space;
687 }
688 }
689
do_para(const char * arg,int space)690 void html_text::do_para (const char *arg, int space)
691 {
692 do_para(arg, NULL, space);
693 }
694
do_para(simple_output * op,const char * arg1,int indentation_value,int page_offset,int line_length,int 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)
698 {
699 html_indent *ind;
700
701 if (indentation_value == 0)
702 ind = NULL;
703 else
704 ind = new html_indent(op, indentation_value, page_offset, line_length);
705 do_para(arg1, ind, space);
706 }
707
708 /*
709 * done_para - shuts down a paragraph tag.
710 */
711
done_para(void)712 char *html_text::done_para (void)
713 {
714 char *result;
715 space_emitted = TRUE;
716 result = shutdown(P_TAG);
717 start_space = FALSE;
718 return result;
719 }
720
721 /*
722 * remove_indent - returns the indent associated with, tag.
723 * The indent associated with tag is set to NULL.
724 */
725
remove_indent(HTML_TAG tag)726 html_indent *html_text::remove_indent (HTML_TAG tag)
727 {
728 tag_definition *p=stackptr;
729
730 while (p != NULL) {
731 if (tag == p->type) {
732 html_indent *i = p->indent;
733 p->indent = NULL;
734 return i;
735 }
736 p = p->next;
737 }
738 return NULL;
739 }
740
741 /*
742 * remove_para_space - removes the leading space to a paragraph
743 * (effectively this trims off a leading `.sp' tag).
744 */
745
remove_para_space(void)746 void html_text::remove_para_space (void)
747 {
748 start_space = FALSE;
749 }
750
751 /*
752 * do_space - issues an end of paragraph
753 */
754
do_space(void)755 void html_text::do_space (void)
756 {
757 if (is_in_pre()) {
758 do_emittext("", 0);
759 out->force_nl();
760 space_emitted = TRUE;
761 } else {
762 html_indent *i = remove_indent(P_TAG);
763
764 do_para(done_para(), i, TRUE);
765 space_emitted = TRUE;
766 }
767 }
768
769 /*
770 * do_break - issue a break tag.
771 */
772
do_break(void)773 void html_text::do_break (void)
774 {
775 if (! is_present(PRE_TAG))
776 if (emitted_text())
777 if (! is_present(BREAK_TAG))
778 push_para(BREAK_TAG);
779
780 space_emitted = TRUE;
781 }
782
783 /*
784 * do_newline - issue a newline providing that we are inside a <pre> tag.
785 */
786
do_newline(void)787 void html_text::do_newline (void)
788 {
789 if (is_present(PRE_TAG)) {
790 do_emittext("\n", 1);
791 space_emitted = TRUE;
792 }
793 }
794
795 /*
796 * emitted_text - returns FALSE if white space has just been written.
797 */
798
emitted_text(void)799 int html_text::emitted_text (void)
800 {
801 return !space_emitted;
802 }
803
804 /*
805 * ever_emitted_text - returns TRUE if we have ever emitted text in this
806 * paragraph.
807 */
808
ever_emitted_text(void)809 int html_text::ever_emitted_text (void)
810 {
811 return !blank_para;
812 }
813
814 /*
815 * starts_with_space - returns TRUE if we started this paragraph with a .sp
816 */
817
starts_with_space(void)818 int html_text::starts_with_space (void)
819 {
820 return start_space;
821 }
822
823 /*
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.
828 */
829
retrieve_para_space(void)830 int html_text::retrieve_para_space (void)
831 {
832 if (start_space && blank_para) {
833 start_space = FALSE;
834 return TRUE;
835 }
836 else
837 return FALSE;
838 }
839
840 /*
841 * emit_space - writes a space providing that text was written beforehand.
842 */
843
emit_space(void)844 void html_text::emit_space (void)
845 {
846 if (is_present(PRE_TAG))
847 do_emittext(" ", 1);
848 else
849 out->space_or_newline();
850
851 space_emitted = TRUE;
852 }
853
854 /*
855 * remove_def - removes a definition, t, from the stack.
856 */
857
remove_def(tag_definition * t)858 void html_text::remove_def (tag_definition *t)
859 {
860 tag_definition *p = stackptr;
861 tag_definition *l = 0;
862 tag_definition *q = 0;
863
864 while ((p != 0) && (p != t)) {
865 l = p;
866 p = p->next;
867 }
868 if ((p != 0) && (p == t)) {
869 if (p == stackptr) {
870 stackptr = stackptr->next;
871 if (stackptr == NULL)
872 lastptr = NULL;
873 q = stackptr;
874 } else if (l == 0) {
875 error("stack list pointers are wrong");
876 } else {
877 l->next = p->next;
878 q = p->next;
879 if (l->next == NULL)
880 lastptr = l;
881 }
882 delete p;
883 }
884 }
885
886 /*
887 * remove_tag - removes a tag from the stack.
888 */
889
remove_tag(HTML_TAG tag)890 void html_text::remove_tag (HTML_TAG tag)
891 {
892 tag_definition *p = stackptr;
893
894 while ((p != 0) && (p->type != tag)) {
895 p = p->next;
896 }
897 if ((p != 0) && (p->type == tag))
898 remove_def(p);
899 }
900
901 /*
902 * remove_sub_sup - removes a sub or sup tag, should either exist
903 * on the stack.
904 */
905
remove_sub_sup(void)906 void html_text::remove_sub_sup (void)
907 {
908 if (is_present(SUB_TAG)) {
909 remove_tag(SUB_TAG);
910 }
911 if (is_present(SUP_TAG)) {
912 remove_tag(SUP_TAG);
913 }
914 if (is_present(PRE_TAG)) {
915 remove_tag(PRE_TAG);
916 }
917 }
918
919 /*
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.
922 */
923
remove_break(void)924 int html_text::remove_break (void)
925 {
926 tag_definition *p = stackptr;
927 tag_definition *l = 0;
928 tag_definition *q = 0;
929
930 while ((p != 0) && (p->type != BREAK_TAG)) {
931 l = p;
932 p = p->next;
933 }
934 if ((p != 0) && (p->type == BREAK_TAG)) {
935 if (p == stackptr) {
936 stackptr = stackptr->next;
937 if (stackptr == NULL)
938 lastptr = NULL;
939 q = stackptr;
940 } else if (l == 0)
941 error("stack list pointers are wrong");
942 else {
943 l->next = p->next;
944 q = p->next;
945 if (l->next == NULL)
946 lastptr = l;
947 }
948 delete p;
949 }
950 /*
951 * now determine whether text was issued before <br>
952 */
953 while (q != 0) {
954 if (q->text_emitted)
955 return TRUE;
956 else
957 q = q->next;
958 }
959 return FALSE;
960 }
961
962 /*
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.
966 */
967
remove_para_align(void)968 void html_text::remove_para_align (void)
969 {
970 if (is_present(P_TAG)) {
971 tag_definition *p=stackptr;
972
973 while (p != NULL) {
974 if (p->type == P_TAG && p->arg1 != NULL) {
975 html_indent *i = remove_indent(P_TAG);
976 int space = retrieve_para_space();
977 done_para();
978 do_para("", i, space);
979 return;
980 }
981 p = p->next;
982 }
983 }
984 }
985
986 /*
987 * get_alignment - returns the alignment for the paragraph.
988 * If no alignment was given then we return "".
989 */
990
get_alignment(void)991 char *html_text::get_alignment (void)
992 {
993 if (is_present(P_TAG)) {
994 tag_definition *p=stackptr;
995
996 while (p != NULL) {
997 if (p->type == P_TAG && p->arg1 != NULL)
998 return (char *)p->arg1;
999 p = p->next;
1000 }
1001 }
1002 return (char *)"";
1003 }
1004
1005 /*
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.
1009 */
1010
do_small(void)1011 void html_text::do_small (void)
1012 {
1013 if (is_present(BIG_TAG))
1014 done_big();
1015 else
1016 push_para(SMALL_TAG);
1017 }
1018
1019 /*
1020 * do_big - is the mirror image of do_small.
1021 */
1022
do_big(void)1023 void html_text::do_big (void)
1024 {
1025 if (is_present(SMALL_TAG))
1026 done_small();
1027 else
1028 push_para(BIG_TAG);
1029 }
1030
1031 /*
1032 * do_sup - save a superscript tag on the stack of tags.
1033 */
1034
do_sup(void)1035 void html_text::do_sup (void)
1036 {
1037 push_para(SUP_TAG);
1038 }
1039
1040 /*
1041 * do_sub - save a subscript tag on the stack of tags.
1042 */
1043
do_sub(void)1044 void html_text::do_sub (void)
1045 {
1046 push_para(SUB_TAG);
1047 }
1048