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/*
16This file is part of groff.
17
18groff is free software; you can redistribute it and/or modify it under
19the terms of the GNU General Public License as published by the Free
20Software Foundation; either version 2, or (at your option) any later
21version.
22
23groff is distributed in the hope that it will be useful, but WITHOUT ANY
24WARRANTY; without even the implied warranty of MERCHANTABILITY or
25FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26for more details.
27
28You should have received a copy of the GNU General Public License along
29with groff; see the file COPYING.  If not, write to the Free Software
30Foundation, 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
49html_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
56html_text::~html_text ()
57{
58  flush_text();
59}
60
61
62#if defined(DEBUGGING)
63static int debugStack = FALSE;
64
65
66/*
67 *  turnDebug - flip the debugStack boolean and return the new value.
68 */
69
70static 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
80void 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
124void 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
138void html_text::dump_stack (void) {}
139#endif
140
141
142/*
143 *  end_tag - shuts down the tag.
144 */
145
146void 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
186void 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
210void 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
231void 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
277void 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
298int 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
315int 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
327extern void stop();
328
329/*
330 *  do_push - places, tag_definition, p, onto the stack
331 */
332
333void 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
377void 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
392void html_text::push_para (HTML_TAG t)
393{
394  push_para(t, (void *)"", NULL);
395}
396
397void 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
414void 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
424void 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
434void 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
444void 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
464int 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
473void 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
483void html_text::done_color (void)
484{
485  shutdown(COLOR_TAG);
486}
487
488/*
489 *  shutdown - shuts down an html tag.
490 */
491
492char *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
562void html_text::done_bold (void)
563{
564  shutdown(B_TAG);
565}
566
567/*
568 *  done_italic - shuts downs an italic tag.
569 */
570
571void html_text::done_italic (void)
572{
573  shutdown(I_TAG);
574}
575
576/*
577 *  done_sup - shuts downs a sup tag.
578 */
579
580void html_text::done_sup (void)
581{
582  shutdown(SUP_TAG);
583}
584
585/*
586 *  done_sub - shuts downs a sub tag.
587 */
588
589void html_text::done_sub (void)
590{
591  shutdown(SUB_TAG);
592}
593
594/*
595 *  done_tt - shuts downs a tt tag.
596 */
597
598void html_text::done_tt (void)
599{
600  shutdown(TT_TAG);
601}
602
603/*
604 *  done_pre - shuts downs a pre tag.
605 */
606
607void html_text::done_pre (void)
608{
609  shutdown(PRE_TAG);
610}
611
612/*
613 *  done_small - shuts downs a small tag.
614 */
615
616void html_text::done_small (void)
617{
618  shutdown(SMALL_TAG);
619}
620
621/*
622 *  done_big - shuts downs a big tag.
623 */
624
625void 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
635void 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
648void 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
674void 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
692void html_text::do_para (const char *arg, int space)
693{
694  do_para(arg, NULL, space);
695}
696
697void 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
714char *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
728html_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
748void html_text::remove_para_space (void)
749{
750  start_space = FALSE;
751}
752
753/*
754 *  do_space - issues an end of paragraph
755 */
756
757void 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
775void 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
789void 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
801int 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
811int 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
820int 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
832int 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
846void 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
860void 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
892void 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
908void 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
926int 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
970void 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
993char *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
1013void 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
1025void 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
1037void 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
1046void html_text::do_sub (void)
1047{
1048  push_para(SUB_TAG);
1049}
1050