LCOV - code coverage report
Current view: top level - devices/grohtml - html-text.cpp (source / functions) Hit Total Coverage
Test: GNU roff Lines: 317 442 71.7 %
Date: 2026-01-16 17:51:41 Functions: 44 56 78.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14