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