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