PageRenderTime 71ms CodeModel.GetById 12ms app.highlight 52ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/groff/src/devices/grohtml/html-text.cpp

https://bitbucket.org/freebsd/freebsd-head/
C++ | 1047 lines | 662 code | 160 blank | 225 comment | 195 complexity | f89a23d631b8fb8033801b6f84b3cb05 MD5 | raw file
   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/*
  14This file is part of groff.
  15
  16groff is free software; you can redistribute it and/or modify it under
  17the terms of the GNU General Public License as published by the Free
  18Software Foundation; either version 2, or (at your option) any later
  19version.
  20
  21groff is distributed in the hope that it will be useful, but WITHOUT ANY
  22WARRANTY; without even the implied warranty of MERCHANTABILITY or
  23FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  24for more details.
  25
  26You should have received a copy of the GNU General Public License along
  27with groff; see the file COPYING.  If not, write to the Free Software
  28Foundation, 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
  47html_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
  54html_text::~html_text ()
  55{
  56  flush_text();
  57}
  58
  59
  60#if defined(DEBUGGING)
  61static int debugStack = FALSE;
  62
  63
  64/*
  65 *  turnDebug - flip the debugStack boolean and return the new value.
  66 */
  67
  68static int turnDebug (void)
  69{
  70  debugStack = 1-debugStack;
  71  return debugStack;
  72}
  73
  74/*
  75 *  dump_stack_element - display an element of the html stack, p.
  76 */
  77
  78void html_text::dump_stack_element (tag_definition *p)
  79{
  80  fprintf(stderr, " | ");
  81  switch (p->type) {
  82
  83  case P_TAG:      if (p->indent == NULL) {
  84                      fprintf(stderr, "<P %s>", (char *)p->arg1); break;
  85                   } else {
  86                      fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
  87		   }
  88  case I_TAG:      fprintf(stderr, "<I>"); break;
  89  case B_TAG:      fprintf(stderr, "<B>"); break;
  90  case SUB_TAG:    fprintf(stderr, "<SUB>"); break;
  91  case SUP_TAG:    fprintf(stderr, "<SUP>"); break;
  92  case TT_TAG:     fprintf(stderr, "<TT>"); break;
  93  case PRE_TAG:    if (p->indent == NULL) {
  94                      fprintf(stderr, "<PRE>"); break;
  95                   } else {
  96                      fprintf(stderr, "<PRE [TABLE]>"); break;
  97		   }
  98  case SMALL_TAG:  fprintf(stderr, "<SMALL>"); break;
  99  case BIG_TAG:    fprintf(stderr, "<BIG>"); break;
 100  case BREAK_TAG:  fprintf(stderr, "<BREAK>"); break;
 101  case COLOR_TAG:  {
 102    if (p->col.is_default())
 103      fprintf(stderr, "<COLOR (default)>");
 104    else {
 105      unsigned int r, g, b;
 106      
 107      p->col.get_rgb(&r, &g, &b);
 108      fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
 109    }
 110    break;
 111  }
 112  default: fprintf(stderr, "unknown tag");
 113  }
 114  if (p->text_emitted)
 115    fprintf(stderr, "[t] ");
 116}
 117
 118/*
 119 *  dump_stack - debugging function only.
 120 */
 121
 122void html_text::dump_stack (void)
 123{
 124  if (debugStack) {
 125    tag_definition *p = stackptr;
 126
 127    while (p != NULL) {
 128      dump_stack_element(p);
 129      p = p->next;
 130    }
 131  }
 132  fprintf(stderr, "\n");
 133  fflush(stderr);
 134}
 135#else
 136void html_text::dump_stack (void) {}
 137#endif
 138
 139
 140/*
 141 *  end_tag - shuts down the tag.
 142 */
 143
 144void html_text::end_tag (tag_definition *t)
 145{
 146  switch (t->type) {
 147
 148  case I_TAG:      out->put_string("</i>"); break;
 149  case B_TAG:      out->put_string("</b>"); break;
 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
 184void 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
 208void 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
 229void 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
 275void 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
 296int 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
 313int 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
 325extern void stop();
 326
 327/*
 328 *  do_push - places, tag_definition, p, onto the stack
 329 */
 330
 331void 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
 375void 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
 390void html_text::push_para (HTML_TAG t)
 391{
 392  push_para(t, (void *)"", NULL);
 393}
 394
 395void 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
 412void 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
 422void 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
 432void 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
 442void 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
 462int 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
 471void 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
 481void html_text::done_color (void)
 482{
 483  shutdown(COLOR_TAG);
 484}
 485
 486/*
 487 *  shutdown - shuts down an html tag.
 488 */
 489
 490char *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
 560void html_text::done_bold (void)
 561{
 562  shutdown(B_TAG);
 563}
 564
 565/*
 566 *  done_italic - shuts downs an italic tag.
 567 */
 568
 569void html_text::done_italic (void)
 570{
 571  shutdown(I_TAG);
 572}
 573
 574/*
 575 *  done_sup - shuts downs a sup tag.
 576 */
 577
 578void html_text::done_sup (void)
 579{
 580  shutdown(SUP_TAG);
 581}
 582
 583/*
 584 *  done_sub - shuts downs a sub tag.
 585 */
 586
 587void html_text::done_sub (void)
 588{
 589  shutdown(SUB_TAG);
 590}
 591
 592/*
 593 *  done_tt - shuts downs a tt tag.
 594 */
 595
 596void html_text::done_tt (void)
 597{
 598  shutdown(TT_TAG);
 599}
 600
 601/*
 602 *  done_pre - shuts downs a pre tag.
 603 */
 604
 605void html_text::done_pre (void)
 606{
 607  shutdown(PRE_TAG);
 608}
 609
 610/*
 611 *  done_small - shuts downs a small tag.
 612 */
 613
 614void html_text::done_small (void)
 615{
 616  shutdown(SMALL_TAG);
 617}
 618
 619/*
 620 *  done_big - shuts downs a big tag.
 621 */
 622
 623void 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
 633void 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
 646void 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
 672void 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
 690void html_text::do_para (const char *arg, int space)
 691{
 692  do_para(arg, NULL, space);
 693}
 694
 695void 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
 712char *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
 726html_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
 746void html_text::remove_para_space (void)
 747{
 748  start_space = FALSE;
 749}
 750
 751/*
 752 *  do_space - issues an end of paragraph
 753 */
 754
 755void 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
 773void 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
 787void 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
 799int 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
 809int 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
 818int 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
 830int 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
 844void 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
 858void 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
 890void 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
 906void 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
 924int 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
 968void 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
 991char *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
1011void 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
1023void 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
1035void 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
1044void html_text::do_sub (void)
1045{
1046  push_para(SUB_TAG);
1047}