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