xref: /freebsd-11-stable/contrib/groff/src/devices/grohtml/html-text.cpp (revision 22e7cbb8744990e63e02dc3985780d932c67b1a4)
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