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