1114402Sru// -*- C++ -*-
2151497Sru/* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
3151497Sru * Free Software Foundation, Inc.
4114402Sru *
5114402Sru *  Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp
6114402Sru *
7114402Sru *  html-text.cpp
8114402Sru *
9114402Sru *  provide a troff like state machine interface which
10114402Sru *  generates html text.
11114402Sru */
12114402Sru
13114402Sru/*
14114402SruThis file is part of groff.
15114402Sru
16114402Srugroff is free software; you can redistribute it and/or modify it under
17114402Sruthe terms of the GNU General Public License as published by the Free
18114402SruSoftware Foundation; either version 2, or (at your option) any later
19114402Sruversion.
20114402Sru
21114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY
22114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or
23114402SruFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
24114402Srufor more details.
25114402Sru
26114402SruYou should have received a copy of the GNU General Public License along
27114402Sruwith groff; see the file COPYING.  If not, write to the Free Software
28151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
29114402Sru
30114402Sru#include "driver.h"
31114402Sru#include "stringclass.h"
32114402Sru#include "cset.h"
33114402Sru
34114402Sru#if !defined(TRUE)
35114402Sru#   define TRUE  (1==1)
36114402Sru#endif
37114402Sru#if !defined(FALSE)
38114402Sru#   define FALSE (1==0)
39114402Sru#endif
40114402Sru
41114402Sru
42114402Sru#include "html-text.h"
43114402Sru
44151497Sru#undef DEBUGGING
45114402Sru// #define DEBUGGING
46114402Sru
47114402Sruhtml_text::html_text (simple_output *op) :
48114402Sru  stackptr(NULL), lastptr(NULL), out(op), space_emitted(TRUE),
49114402Sru  current_indentation(-1), pageoffset(-1), linelength(-1),
50114402Sru  blank_para(TRUE), start_space(FALSE)
51114402Sru{
52114402Sru}
53114402Sru
54114402Sruhtml_text::~html_text ()
55114402Sru{
56114402Sru  flush_text();
57114402Sru}
58114402Sru
59114402Sru
60114402Sru#if defined(DEBUGGING)
61114402Srustatic int debugStack = FALSE;
62114402Sru
63114402Sru
64114402Sru/*
65114402Sru *  turnDebug - flip the debugStack boolean and return the new value.
66114402Sru */
67114402Sru
68114402Srustatic int turnDebug (void)
69114402Sru{
70114402Sru  debugStack = 1-debugStack;
71114402Sru  return debugStack;
72114402Sru}
73114402Sru
74114402Sru/*
75114402Sru *  dump_stack_element - display an element of the html stack, p.
76114402Sru */
77114402Sru
78114402Sruvoid html_text::dump_stack_element (tag_definition *p)
79114402Sru{
80114402Sru  fprintf(stderr, " | ");
81114402Sru  switch (p->type) {
82114402Sru
83114402Sru  case P_TAG:      if (p->indent == NULL) {
84114402Sru                      fprintf(stderr, "<P %s>", (char *)p->arg1); break;
85114402Sru                   } else {
86114402Sru                      fprintf(stderr, "<P %s [TABLE]>", (char *)p->arg1); break;
87114402Sru		   }
88114402Sru  case I_TAG:      fprintf(stderr, "<I>"); break;
89114402Sru  case B_TAG:      fprintf(stderr, "<B>"); break;
90114402Sru  case SUB_TAG:    fprintf(stderr, "<SUB>"); break;
91114402Sru  case SUP_TAG:    fprintf(stderr, "<SUP>"); break;
92114402Sru  case TT_TAG:     fprintf(stderr, "<TT>"); break;
93114402Sru  case PRE_TAG:    if (p->indent == NULL) {
94114402Sru                      fprintf(stderr, "<PRE>"); break;
95114402Sru                   } else {
96114402Sru                      fprintf(stderr, "<PRE [TABLE]>"); break;
97114402Sru		   }
98114402Sru  case SMALL_TAG:  fprintf(stderr, "<SMALL>"); break;
99114402Sru  case BIG_TAG:    fprintf(stderr, "<BIG>"); break;
100114402Sru  case BREAK_TAG:  fprintf(stderr, "<BREAK>"); break;
101114402Sru  case COLOR_TAG:  {
102114402Sru    if (p->col.is_default())
103114402Sru      fprintf(stderr, "<COLOR (default)>");
104114402Sru    else {
105114402Sru      unsigned int r, g, b;
106114402Sru
107114402Sru      p->col.get_rgb(&r, &g, &b);
108114402Sru      fprintf(stderr, "<COLOR %x %x %x>", r/0x101, g/0x101, b/0x101);
109114402Sru    }
110114402Sru    break;
111114402Sru  }
112114402Sru  default: fprintf(stderr, "unknown tag");
113114402Sru  }
114114402Sru  if (p->text_emitted)
115114402Sru    fprintf(stderr, "[t] ");
116114402Sru}
117114402Sru
118114402Sru/*
119114402Sru *  dump_stack - debugging function only.
120114402Sru */
121114402Sru
122114402Sruvoid html_text::dump_stack (void)
123114402Sru{
124114402Sru  if (debugStack) {
125114402Sru    tag_definition *p = stackptr;
126114402Sru
127114402Sru    while (p != NULL) {
128114402Sru      dump_stack_element(p);
129114402Sru      p = p->next;
130114402Sru    }
131114402Sru  }
132114402Sru  fprintf(stderr, "\n");
133114402Sru  fflush(stderr);
134114402Sru}
135114402Sru#else
136114402Sruvoid html_text::dump_stack (void) {}
137114402Sru#endif
138114402Sru
139114402Sru
140114402Sru/*
141114402Sru *  end_tag - shuts down the tag.
142114402Sru */
143114402Sru
144114402Sruvoid html_text::end_tag (tag_definition *t)
145114402Sru{
146114402Sru  switch (t->type) {
147114402Sru
148114402Sru  case I_TAG:      out->put_string("</i>"); break;
149114402Sru  case B_TAG:      out->put_string("</b>"); break;
150151497Sru  case P_TAG:      if (t->indent == NULL) {
151151497Sru                     out->put_string("</p>");
152151497Sru                   } else {
153114402Sru		     delete t->indent;
154114402Sru		     t->indent = NULL;
155151497Sru                     out->put_string("</p>");
156114402Sru		   }
157151497Sru		   out->enable_newlines(FALSE);
158114402Sru                   blank_para = TRUE; break;
159114402Sru  case SUB_TAG:    out->put_string("</sub>"); break;
160114402Sru  case SUP_TAG:    out->put_string("</sup>"); break;
161114402Sru  case TT_TAG:     out->put_string("</tt>"); break;
162151497Sru  case PRE_TAG:    out->put_string("</pre>"); out->enable_newlines(TRUE);
163151497Sru                   blank_para = TRUE;
164151497Sru                   if (t->indent != NULL)
165151497Sru		     delete t->indent;
166151497Sru		   t->indent = NULL;
167151497Sru                   break;
168114402Sru  case SMALL_TAG:  out->put_string("</small>"); break;
169114402Sru  case BIG_TAG:    out->put_string("</big>"); break;
170114402Sru  case COLOR_TAG:  out->put_string("</font>"); break;
171114402Sru
172114402Sru  default:
173114402Sru    error("unrecognised tag");
174114402Sru  }
175114402Sru}
176114402Sru
177114402Sru/*
178114402Sru *  issue_tag - writes out an html tag with argument.
179151497Sru *              space == 0 if no space is requested
180151497Sru *              space == 1 if a space is requested
181151497Sru *              space == 2 if tag should not have a space style
182114402Sru */
183114402Sru
184151497Sruvoid html_text::issue_tag (const char *tagname, const char *arg,
185151497Sru			   int space)
186114402Sru{
187151497Sru  if ((arg == 0) || (strlen(arg) == 0))
188114402Sru    out->put_string(tagname);
189151497Sru  else {
190114402Sru    out->put_string(tagname);
191114402Sru    out->put_string(" ");
192114402Sru    out->put_string(arg);
193114402Sru  }
194151497Sru  if (space == TRUE) {
195151497Sru    out->put_string(" style=\"margin-top: ");
196151497Sru    out->put_string(STYLE_VERTICAL_SPACE);
197151497Sru    out->put_string("\"");
198151497Sru  }
199151497Sru  if (space == TRUE || space == FALSE)
200151497Sru    out->put_string(" valign=\"top\"");
201151497Sru  out->put_string(">");
202114402Sru}
203114402Sru
204114402Sru/*
205114402Sru *  issue_color_begin - writes out an html color tag.
206114402Sru */
207114402Sru
208114402Sruvoid html_text::issue_color_begin (color *c)
209114402Sru{
210114402Sru  unsigned int r, g, b;
211114402Sru  char buf[6+1];
212114402Sru
213114402Sru  out->put_string("<font color=\"#");
214114402Sru  if (c->is_default())
215114402Sru    sprintf(buf, "000000");
216114402Sru  else {
217114402Sru    c->get_rgb(&r, &g, &b);
218114402Sru    // we have to scale 0..0xFFFF to 0..0xFF
219114402Sru    sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101);
220114402Sru  }
221114402Sru  out->put_string(buf);
222114402Sru  out->put_string("\">");
223114402Sru}
224114402Sru
225114402Sru/*
226114402Sru *  start_tag - starts a tag.
227114402Sru */
228114402Sru
229114402Sruvoid html_text::start_tag (tag_definition *t)
230114402Sru{
231114402Sru  switch (t->type) {
232114402Sru
233114402Sru  case I_TAG:      issue_tag("<i", (char *)t->arg1); break;
234114402Sru  case B_TAG:      issue_tag("<b", (char *)t->arg1); break;
235151497Sru  case P_TAG:      if (t->indent != NULL) {
236114402Sru                     out->nl();
237151497Sru#if defined(DEBUGGING)
238151497Sru		     out->simple_comment("INDENTATION");
239151497Sru#endif
240151497Sru		     out->put_string("\n<p");
241151497Sru		     t->indent->begin(start_space);
242151497Sru                     issue_tag("", (char *)t->arg1);
243114402Sru                   } else {
244151497Sru                     out->nl();
245151497Sru                     issue_tag("\n<p", (char *)t->arg1, start_space);
246114402Sru		   }
247114402Sru
248114402Sru                   out->enable_newlines(TRUE); break;
249114402Sru  case SUB_TAG:    issue_tag("<sub", (char *)t->arg1); break;
250114402Sru  case SUP_TAG:    issue_tag("<sup", (char *)t->arg1); break;
251114402Sru  case TT_TAG:     issue_tag("<tt", (char *)t->arg1); break;
252151497Sru  case PRE_TAG:    out->enable_newlines(TRUE);
253151497Sru                   out->nl(); out->put_string("<pre");
254151497Sru		   if (t->indent == NULL)
255151497Sru		     issue_tag("", (char *)t->arg1, start_space);
256151497Sru		   else {
257151497Sru		     t->indent->begin(start_space);
258151497Sru		     issue_tag("", (char *)t->arg1);
259151497Sru		   }
260114402Sru                   out->enable_newlines(FALSE); break;
261114402Sru  case SMALL_TAG:  issue_tag("<small", (char *)t->arg1); break;
262114402Sru  case BIG_TAG:    issue_tag("<big", (char *)t->arg1); break;
263114402Sru  case BREAK_TAG:  break;
264114402Sru  case COLOR_TAG:  issue_color_begin(&t->col); break;
265114402Sru
266114402Sru  default:
267114402Sru    error("unrecognised tag");
268114402Sru  }
269114402Sru}
270114402Sru
271114402Sru/*
272114402Sru *  flush_text - flushes html tags which are outstanding on the html stack.
273114402Sru */
274114402Sru
275114402Sruvoid html_text::flush_text (void)
276114402Sru{
277114402Sru  int notext=TRUE;
278114402Sru  tag_definition *p=stackptr;
279114402Sru
280114402Sru  while (stackptr != 0) {
281114402Sru    notext = (notext && (! stackptr->text_emitted));
282114402Sru    if (! notext) {
283114402Sru      end_tag(stackptr);
284114402Sru    }
285114402Sru    p = stackptr;
286114402Sru    stackptr = stackptr->next;
287151497Sru    delete p;
288114402Sru  }
289114402Sru  lastptr = NULL;
290114402Sru}
291114402Sru
292114402Sru/*
293114402Sru *  is_present - returns TRUE if tag is already present on the stack.
294114402Sru */
295114402Sru
296114402Sruint html_text::is_present (HTML_TAG t)
297114402Sru{
298114402Sru  tag_definition *p=stackptr;
299114402Sru
300114402Sru  while (p != NULL) {
301114402Sru    if (t == p->type)
302114402Sru      return TRUE;
303114402Sru    p = p->next;
304114402Sru  }
305114402Sru  return FALSE;
306114402Sru}
307114402Sru
308151497Sru/*
309151497Sru *  uses_indent - returns TRUE if the current paragraph is using a
310151497Sru *                html table to effect an indent.
311151497Sru */
312151497Sru
313151497Sruint html_text::uses_indent (void)
314151497Sru{
315151497Sru  tag_definition *p = stackptr;
316151497Sru
317151497Sru  while (p != NULL) {
318151497Sru    if (p->indent != NULL)
319151497Sru      return TRUE;
320151497Sru    p = p->next;
321151497Sru  }
322151497Sru  return FALSE;
323151497Sru}
324151497Sru
325114402Sruextern void stop();
326114402Sru
327114402Sru/*
328114402Sru *  do_push - places, tag_definition, p, onto the stack
329114402Sru */
330114402Sru
331114402Sruvoid html_text::do_push (tag_definition *p)
332114402Sru{
333114402Sru  HTML_TAG t = p->type;
334114402Sru
335114402Sru#if defined(DEBUGGING)
336114402Sru  if (t == PRE_TAG)
337114402Sru    stop();
338114402Sru  debugStack = TRUE;
339114402Sru  fprintf(stderr, "\nentering do_push (");
340114402Sru  dump_stack_element(p);
341114402Sru  fprintf(stderr, ")\n");
342114402Sru  dump_stack();
343114402Sru  fprintf(stderr, ")\n");
344114402Sru  fflush(stderr);
345114402Sru#endif
346114402Sru
347114402Sru  /*
348114402Sru   *  if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack.
349114402Sru   */
350114402Sru
351114402Sru  if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) {
352114402Sru    /*
353114402Sru     *  store, p, at the end
354114402Sru     */
355114402Sru    lastptr->next = p;
356114402Sru    lastptr       = p;
357114402Sru    p->next       = NULL;
358114402Sru  } else {
359114402Sru    p->next       = stackptr;
360114402Sru    if (stackptr == NULL)
361114402Sru      lastptr = p;
362114402Sru    stackptr      = p;
363114402Sru  }
364114402Sru
365114402Sru#if defined(DEBUGGING)
366114402Sru  dump_stack();
367114402Sru  fprintf(stderr, "exiting do_push\n");
368114402Sru#endif
369114402Sru}
370114402Sru
371114402Sru/*
372114402Sru *  push_para - adds a new entry onto the html paragraph stack.
373114402Sru */
374114402Sru
375114402Sruvoid html_text::push_para (HTML_TAG t, void *arg, html_indent *in)
376114402Sru{
377151497Sru  tag_definition *p= new tag_definition;
378114402Sru
379114402Sru  p->type         = t;
380114402Sru  p->arg1         = arg;
381114402Sru  p->text_emitted = FALSE;
382114402Sru  p->indent       = in;
383114402Sru
384114402Sru  if (t == PRE_TAG && is_present(PRE_TAG))
385114402Sru    fatal("cannot have multiple PRE_TAGs");
386114402Sru
387114402Sru  do_push(p);
388114402Sru}
389114402Sru
390114402Sruvoid html_text::push_para (HTML_TAG t)
391114402Sru{
392114402Sru  push_para(t, (void *)"", NULL);
393114402Sru}
394114402Sru
395114402Sruvoid html_text::push_para (color *c)
396114402Sru{
397151497Sru  tag_definition *p = new tag_definition;
398114402Sru
399114402Sru  p->type         = COLOR_TAG;
400114402Sru  p->arg1         = NULL;
401114402Sru  p->col          = *c;
402114402Sru  p->text_emitted = FALSE;
403114402Sru  p->indent       = NULL;
404114402Sru
405114402Sru  do_push(p);
406114402Sru}
407114402Sru
408114402Sru/*
409114402Sru *  do_italic - changes to italic
410114402Sru */
411114402Sru
412114402Sruvoid html_text::do_italic (void)
413114402Sru{
414114402Sru  if (! is_present(I_TAG))
415114402Sru    push_para(I_TAG);
416114402Sru}
417114402Sru
418114402Sru/*
419114402Sru *  do_bold - changes to bold.
420114402Sru */
421114402Sru
422114402Sruvoid html_text::do_bold (void)
423114402Sru{
424114402Sru  if (! is_present(B_TAG))
425114402Sru    push_para(B_TAG);
426114402Sru}
427114402Sru
428114402Sru/*
429114402Sru *  do_tt - changes to teletype.
430114402Sru */
431114402Sru
432114402Sruvoid html_text::do_tt (void)
433114402Sru{
434114402Sru  if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG)))
435114402Sru    push_para(TT_TAG);
436114402Sru}
437114402Sru
438114402Sru/*
439114402Sru *  do_pre - changes to preformated text.
440114402Sru */
441114402Sru
442114402Sruvoid html_text::do_pre (void)
443114402Sru{
444114402Sru  done_tt();
445114402Sru  if (is_present(P_TAG)) {
446114402Sru    html_indent *i = remove_indent(P_TAG);
447151497Sru    int space = retrieve_para_space();
448114402Sru    (void)done_para();
449114402Sru    if (! is_present(PRE_TAG))
450114402Sru      push_para(PRE_TAG, NULL, i);
451151497Sru    start_space = space;
452114402Sru  } else if (! is_present(PRE_TAG))
453114402Sru    push_para(PRE_TAG, NULL, NULL);
454114402Sru  dump_stack();
455114402Sru}
456114402Sru
457114402Sru/*
458114402Sru *  is_in_pre - returns TRUE if we are currently within a preformatted
459114402Sru *              <pre> block.
460114402Sru */
461114402Sru
462114402Sruint html_text::is_in_pre (void)
463114402Sru{
464114402Sru  return is_present(PRE_TAG);
465114402Sru}
466114402Sru
467114402Sru/*
468114402Sru *  do_color - initiates a new color tag.
469114402Sru */
470114402Sru
471114402Sruvoid html_text::do_color (color *c)
472114402Sru{
473114402Sru  shutdown(COLOR_TAG);   // shutdown a previous color tag, if present
474114402Sru  push_para(c);
475114402Sru}
476114402Sru
477114402Sru/*
478114402Sru *  done_color - shutdown an outstanding color tag, if it exists.
479114402Sru */
480114402Sru
481114402Sruvoid html_text::done_color (void)
482114402Sru{
483114402Sru  shutdown(COLOR_TAG);
484114402Sru}
485114402Sru
486114402Sru/*
487114402Sru *  shutdown - shuts down an html tag.
488114402Sru */
489114402Sru
490114402Sruchar *html_text::shutdown (HTML_TAG t)
491114402Sru{
492114402Sru  char *arg=NULL;
493114402Sru
494114402Sru  if (is_present(t)) {
495114402Sru    tag_definition *p    =stackptr;
496114402Sru    tag_definition *temp =NULL;
497114402Sru    int notext           =TRUE;
498114402Sru
499114402Sru    dump_stack();
500114402Sru    while ((stackptr != NULL) && (stackptr->type != t)) {
501114402Sru      notext = (notext && (! stackptr->text_emitted));
502114402Sru      if (! notext) {
503114402Sru	end_tag(stackptr);
504114402Sru      }
505114402Sru
506114402Sru      /*
507114402Sru       *  pop tag
508114402Sru       */
509114402Sru      p        = stackptr;
510114402Sru      stackptr = stackptr->next;
511114402Sru      if (stackptr == NULL)
512114402Sru	lastptr = NULL;
513114402Sru
514114402Sru      /*
515114402Sru       *  push tag onto temp stack
516114402Sru       */
517151497Sru      p->next = temp;
518151497Sru      temp    = p;
519114402Sru    }
520114402Sru
521114402Sru    /*
522114402Sru     *  and examine stackptr
523114402Sru     */
524114402Sru    if ((stackptr != NULL) && (stackptr->type == t)) {
525114402Sru      if (stackptr->text_emitted) {
526114402Sru	end_tag(stackptr);
527114402Sru      }
528114402Sru      if (t == P_TAG) {
529114402Sru	arg = (char *)stackptr->arg1;
530114402Sru      }
531114402Sru      p        = stackptr;
532114402Sru      stackptr = stackptr->next;
533114402Sru      if (stackptr == NULL)
534114402Sru	lastptr = NULL;
535114402Sru      if (p->indent != NULL)
536114402Sru	delete p->indent;
537151497Sru      delete p;
538114402Sru    }
539114402Sru
540114402Sru    /*
541114402Sru     *  and restore unaffected tags
542114402Sru     */
543114402Sru    while (temp != NULL) {
544114402Sru      if (temp->type == COLOR_TAG)
545114402Sru	push_para(&temp->col);
546114402Sru      else
547114402Sru	push_para(temp->type, temp->arg1, temp->indent);
548114402Sru      p    = temp;
549114402Sru      temp = temp->next;
550151497Sru      delete p;
551114402Sru    }
552114402Sru  }
553114402Sru  return arg;
554114402Sru}
555114402Sru
556114402Sru/*
557114402Sru *  done_bold - shuts downs a bold tag.
558114402Sru */
559114402Sru
560114402Sruvoid html_text::done_bold (void)
561114402Sru{
562114402Sru  shutdown(B_TAG);
563114402Sru}
564114402Sru
565114402Sru/*
566114402Sru *  done_italic - shuts downs an italic tag.
567114402Sru */
568114402Sru
569114402Sruvoid html_text::done_italic (void)
570114402Sru{
571114402Sru  shutdown(I_TAG);
572114402Sru}
573114402Sru
574114402Sru/*
575114402Sru *  done_sup - shuts downs a sup tag.
576114402Sru */
577114402Sru
578114402Sruvoid html_text::done_sup (void)
579114402Sru{
580114402Sru  shutdown(SUP_TAG);
581114402Sru}
582114402Sru
583114402Sru/*
584114402Sru *  done_sub - shuts downs a sub tag.
585114402Sru */
586114402Sru
587114402Sruvoid html_text::done_sub (void)
588114402Sru{
589114402Sru  shutdown(SUB_TAG);
590114402Sru}
591114402Sru
592114402Sru/*
593114402Sru *  done_tt - shuts downs a tt tag.
594114402Sru */
595114402Sru
596114402Sruvoid html_text::done_tt (void)
597114402Sru{
598114402Sru  shutdown(TT_TAG);
599114402Sru}
600114402Sru
601114402Sru/*
602114402Sru *  done_pre - shuts downs a pre tag.
603114402Sru */
604114402Sru
605114402Sruvoid html_text::done_pre (void)
606114402Sru{
607114402Sru  shutdown(PRE_TAG);
608114402Sru}
609114402Sru
610114402Sru/*
611114402Sru *  done_small - shuts downs a small tag.
612114402Sru */
613114402Sru
614114402Sruvoid html_text::done_small (void)
615114402Sru{
616114402Sru  shutdown(SMALL_TAG);
617114402Sru}
618114402Sru
619114402Sru/*
620114402Sru *  done_big - shuts downs a big tag.
621114402Sru */
622114402Sru
623114402Sruvoid html_text::done_big (void)
624114402Sru{
625114402Sru  shutdown(BIG_TAG);
626114402Sru}
627114402Sru
628114402Sru/*
629114402Sru *  check_emit_text - ensures that all previous tags have been emitted (in order)
630114402Sru *                    before the text is written.
631114402Sru */
632114402Sru
633114402Sruvoid html_text::check_emit_text (tag_definition *t)
634114402Sru{
635114402Sru  if ((t != NULL) && (! t->text_emitted)) {
636114402Sru    check_emit_text(t->next);
637114402Sru    t->text_emitted = TRUE;
638114402Sru    start_tag(t);
639114402Sru  }
640114402Sru}
641114402Sru
642114402Sru/*
643114402Sru *  do_emittext - tells the class that text was written during the current tag.
644114402Sru */
645114402Sru
646114402Sruvoid html_text::do_emittext (const char *s, int length)
647114402Sru{
648114402Sru  if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
649151497Sru    do_para("", FALSE);
650114402Sru
651114402Sru  if (is_present(BREAK_TAG)) {
652114402Sru    int text = remove_break();
653114402Sru    check_emit_text(stackptr);
654114402Sru    if (text) {
655114402Sru      if (is_present(PRE_TAG)) {
656114402Sru	out->nl();
657151497Sru      } else
658114402Sru	out->put_string("<br>").nl();
659114402Sru    }
660151497Sru  } else
661114402Sru    check_emit_text(stackptr);
662151497Sru
663114402Sru  out->put_string(s, length);
664114402Sru  space_emitted = FALSE;
665114402Sru  blank_para = FALSE;
666114402Sru}
667114402Sru
668114402Sru/*
669114402Sru *  do_para - starts a new paragraph
670114402Sru */
671114402Sru
672151497Sruvoid html_text::do_para (const char *arg, html_indent *in, int space)
673114402Sru{
674114402Sru  if (! is_present(P_TAG)) {
675114402Sru    if (is_present(PRE_TAG)) {
676114402Sru      html_indent *i = remove_indent(PRE_TAG);
677114402Sru      done_pre();
678151497Sru      if ((arg == NULL || (strcmp(arg, "") == 0)) &&
679151497Sru	  (i == in || in == NULL))
680114402Sru	in = i;
681114402Sru      else
682114402Sru	delete i;
683114402Sru    }
684114402Sru    remove_sub_sup();
685114402Sru    push_para(P_TAG, (void *)arg, in);
686151497Sru    start_space = space;
687114402Sru  }
688114402Sru}
689114402Sru
690151497Sruvoid html_text::do_para (const char *arg, int space)
691114402Sru{
692151497Sru  do_para(arg, NULL, space);
693114402Sru}
694114402Sru
695114402Sruvoid html_text::do_para (simple_output *op, const char *arg1,
696151497Sru			 int indentation_value, int page_offset,
697151497Sru			 int line_length, int space)
698114402Sru{
699151497Sru  html_indent *ind;
700114402Sru
701151497Sru  if (indentation_value == 0)
702151497Sru    ind = NULL;
703114402Sru  else
704151497Sru    ind = new html_indent(op, indentation_value, page_offset, line_length);
705151497Sru  do_para(arg1, ind, space);
706114402Sru}
707114402Sru
708114402Sru/*
709114402Sru *  done_para - shuts down a paragraph tag.
710114402Sru */
711114402Sru
712114402Sruchar *html_text::done_para (void)
713114402Sru{
714151497Sru  char *result;
715114402Sru  space_emitted = TRUE;
716151497Sru  result = shutdown(P_TAG);
717151497Sru  start_space = FALSE;
718151497Sru  return result;
719114402Sru}
720114402Sru
721114402Sru/*
722114402Sru *  remove_indent - returns the indent associated with, tag.
723114402Sru *                  The indent associated with tag is set to NULL.
724114402Sru */
725114402Sru
726114402Sruhtml_indent *html_text::remove_indent (HTML_TAG tag)
727114402Sru{
728114402Sru  tag_definition *p=stackptr;
729114402Sru
730114402Sru  while (p != NULL) {
731114402Sru    if (tag == p->type) {
732114402Sru      html_indent *i = p->indent;
733114402Sru      p->indent = NULL;
734114402Sru      return i;
735114402Sru    }
736114402Sru    p = p->next;
737114402Sru  }
738114402Sru  return NULL;
739114402Sru}
740114402Sru
741114402Sru/*
742151497Sru *  remove_para_space - removes the leading space to a paragraph
743151497Sru *                      (effectively this trims off a leading `.sp' tag).
744151497Sru */
745151497Sru
746151497Sruvoid html_text::remove_para_space (void)
747151497Sru{
748151497Sru  start_space = FALSE;
749151497Sru}
750151497Sru
751151497Sru/*
752114402Sru *  do_space - issues an end of paragraph
753114402Sru */
754114402Sru
755114402Sruvoid html_text::do_space (void)
756114402Sru{
757114402Sru  if (is_in_pre()) {
758151497Sru    do_emittext("", 0);
759151497Sru    out->force_nl();
760151497Sru    space_emitted = TRUE;
761114402Sru  } else {
762114402Sru    html_indent *i = remove_indent(P_TAG);
763114402Sru
764151497Sru    do_para(done_para(), i, TRUE);
765114402Sru    space_emitted = TRUE;
766114402Sru  }
767114402Sru}
768114402Sru
769114402Sru/*
770114402Sru *  do_break - issue a break tag.
771114402Sru */
772114402Sru
773114402Sruvoid html_text::do_break (void)
774114402Sru{
775151497Sru  if (! is_present(PRE_TAG))
776151497Sru    if (emitted_text())
777151497Sru      if (! is_present(BREAK_TAG))
778114402Sru	push_para(BREAK_TAG);
779151497Sru
780114402Sru  space_emitted = TRUE;
781114402Sru}
782114402Sru
783114402Sru/*
784114402Sru *  do_newline - issue a newline providing that we are inside a <pre> tag.
785114402Sru */
786114402Sru
787114402Sruvoid html_text::do_newline (void)
788114402Sru{
789114402Sru  if (is_present(PRE_TAG)) {
790114402Sru    do_emittext("\n", 1);
791114402Sru    space_emitted = TRUE;
792114402Sru  }
793114402Sru}
794114402Sru
795114402Sru/*
796114402Sru *  emitted_text - returns FALSE if white space has just been written.
797114402Sru */
798114402Sru
799114402Sruint html_text::emitted_text (void)
800114402Sru{
801114402Sru  return !space_emitted;
802114402Sru}
803114402Sru
804114402Sru/*
805151497Sru *  ever_emitted_text - returns TRUE if we have ever emitted text in this
806151497Sru *                      paragraph.
807114402Sru */
808114402Sru
809114402Sruint html_text::ever_emitted_text (void)
810114402Sru{
811114402Sru  return !blank_para;
812114402Sru}
813114402Sru
814114402Sru/*
815151497Sru *  starts_with_space - returns TRUE if we started this paragraph with a .sp
816114402Sru */
817114402Sru
818114402Sruint html_text::starts_with_space (void)
819114402Sru{
820114402Sru  return start_space;
821114402Sru}
822114402Sru
823114402Sru/*
824151497Sru *  retrieve_para_space - returns TRUE, if the paragraph starts with
825151497Sru *                        a space and text has not yet been emitted.
826151497Sru *                        If TRUE is returned, then the, start_space,
827151497Sru *                        variable is set to FALSE.
828151497Sru */
829151497Sru
830151497Sruint html_text::retrieve_para_space (void)
831151497Sru{
832151497Sru  if (start_space && blank_para) {
833151497Sru    start_space = FALSE;
834151497Sru    return TRUE;
835151497Sru  }
836151497Sru  else
837151497Sru    return FALSE;
838151497Sru}
839151497Sru
840151497Sru/*
841114402Sru *  emit_space - writes a space providing that text was written beforehand.
842114402Sru */
843114402Sru
844114402Sruvoid html_text::emit_space (void)
845114402Sru{
846151497Sru  if (is_present(PRE_TAG))
847151497Sru    do_emittext(" ", 1);
848151497Sru  else
849114402Sru    out->space_or_newline();
850151497Sru
851151497Sru  space_emitted = TRUE;
852114402Sru}
853114402Sru
854114402Sru/*
855114402Sru *  remove_def - removes a definition, t, from the stack.
856114402Sru */
857114402Sru
858114402Sruvoid html_text::remove_def (tag_definition *t)
859114402Sru{
860114402Sru  tag_definition *p    = stackptr;
861114402Sru  tag_definition *l    = 0;
862114402Sru  tag_definition *q    = 0;
863114402Sru
864114402Sru  while ((p != 0) && (p != t)) {
865114402Sru    l = p;
866114402Sru    p = p->next;
867114402Sru  }
868114402Sru  if ((p != 0) && (p == t)) {
869114402Sru    if (p == stackptr) {
870114402Sru      stackptr = stackptr->next;
871114402Sru      if (stackptr == NULL)
872114402Sru	lastptr = NULL;
873114402Sru      q = stackptr;
874114402Sru    } else if (l == 0) {
875114402Sru      error("stack list pointers are wrong");
876114402Sru    } else {
877114402Sru      l->next = p->next;
878114402Sru      q = p->next;
879114402Sru      if (l->next == NULL)
880114402Sru	lastptr = l;
881114402Sru    }
882151497Sru    delete p;
883114402Sru  }
884114402Sru}
885114402Sru
886114402Sru/*
887114402Sru *  remove_tag - removes a tag from the stack.
888114402Sru */
889114402Sru
890114402Sruvoid html_text::remove_tag (HTML_TAG tag)
891114402Sru{
892114402Sru  tag_definition *p = stackptr;
893114402Sru
894114402Sru  while ((p != 0) && (p->type != tag)) {
895114402Sru    p = p->next;
896114402Sru  }
897114402Sru  if ((p != 0) && (p->type == tag))
898114402Sru    remove_def(p);
899114402Sru}
900114402Sru
901114402Sru/*
902151497Sru *  remove_sub_sup - removes a sub or sup tag, should either exist
903151497Sru *                   on the stack.
904114402Sru */
905114402Sru
906114402Sruvoid html_text::remove_sub_sup (void)
907114402Sru{
908114402Sru  if (is_present(SUB_TAG)) {
909114402Sru    remove_tag(SUB_TAG);
910114402Sru  }
911114402Sru  if (is_present(SUP_TAG)) {
912114402Sru    remove_tag(SUP_TAG);
913114402Sru  }
914114402Sru  if (is_present(PRE_TAG)) {
915114402Sru    remove_tag(PRE_TAG);
916114402Sru  }
917114402Sru}
918114402Sru
919114402Sru/*
920114402Sru *  remove_break - break tags are not balanced thus remove it once it has been emitted.
921114402Sru *                 It returns TRUE if text was emitted before the <br> was issued.
922114402Sru */
923114402Sru
924114402Sruint html_text::remove_break (void)
925114402Sru{
926114402Sru  tag_definition *p    = stackptr;
927114402Sru  tag_definition *l    = 0;
928114402Sru  tag_definition *q    = 0;
929114402Sru
930114402Sru  while ((p != 0) && (p->type != BREAK_TAG)) {
931114402Sru    l = p;
932114402Sru    p = p->next;
933114402Sru  }
934114402Sru  if ((p != 0) && (p->type == BREAK_TAG)) {
935114402Sru    if (p == stackptr) {
936114402Sru      stackptr = stackptr->next;
937114402Sru      if (stackptr == NULL)
938114402Sru	lastptr = NULL;
939114402Sru      q = stackptr;
940114402Sru    } else if (l == 0)
941114402Sru      error("stack list pointers are wrong");
942114402Sru    else {
943114402Sru      l->next = p->next;
944114402Sru      q = p->next;
945114402Sru      if (l->next == NULL)
946114402Sru	lastptr = l;
947114402Sru    }
948151497Sru    delete p;
949114402Sru  }
950114402Sru  /*
951114402Sru   *  now determine whether text was issued before <br>
952114402Sru   */
953114402Sru  while (q != 0) {
954114402Sru    if (q->text_emitted)
955114402Sru      return TRUE;
956114402Sru    else
957114402Sru      q = q->next;
958114402Sru  }
959114402Sru  return FALSE;
960114402Sru}
961114402Sru
962114402Sru/*
963114402Sru *  remove_para_align - removes a paragraph which has a text
964114402Sru *                      argument. If the paragraph has no text
965114402Sru *                      argument then it is left alone.
966114402Sru */
967114402Sru
968114402Sruvoid html_text::remove_para_align (void)
969114402Sru{
970114402Sru  if (is_present(P_TAG)) {
971114402Sru    tag_definition *p=stackptr;
972114402Sru
973114402Sru    while (p != NULL) {
974114402Sru      if (p->type == P_TAG && p->arg1 != NULL) {
975114402Sru	html_indent *i = remove_indent(P_TAG);
976151497Sru	int          space = retrieve_para_space();
977114402Sru	done_para();
978151497Sru	do_para("", i, space);
979114402Sru	return;
980114402Sru      }
981114402Sru      p = p->next;
982114402Sru    }
983114402Sru  }
984114402Sru}
985114402Sru
986114402Sru/*
987151497Sru *  get_alignment - returns the alignment for the paragraph.
988151497Sru *                  If no alignment was given then we return "".
989151497Sru */
990151497Sru
991151497Sruchar *html_text::get_alignment (void)
992151497Sru{
993151497Sru  if (is_present(P_TAG)) {
994151497Sru    tag_definition *p=stackptr;
995151497Sru
996151497Sru    while (p != NULL) {
997151497Sru      if (p->type == P_TAG && p->arg1 != NULL)
998151497Sru	return (char *)p->arg1;
999151497Sru      p = p->next;
1000151497Sru    }
1001151497Sru  }
1002151497Sru  return (char *)"";
1003151497Sru}
1004151497Sru
1005151497Sru/*
1006114402Sru *  do_small - potentially inserts a <small> tag into the html stream.
1007114402Sru *             However we check for a <big> tag, if present then we terminate it.
1008114402Sru *             Otherwise a <small> tag is inserted.
1009114402Sru */
1010114402Sru
1011114402Sruvoid html_text::do_small (void)
1012114402Sru{
1013114402Sru  if (is_present(BIG_TAG))
1014114402Sru    done_big();
1015114402Sru  else
1016114402Sru    push_para(SMALL_TAG);
1017114402Sru}
1018114402Sru
1019114402Sru/*
1020114402Sru *  do_big - is the mirror image of do_small.
1021114402Sru */
1022114402Sru
1023114402Sruvoid html_text::do_big (void)
1024114402Sru{
1025114402Sru  if (is_present(SMALL_TAG))
1026114402Sru    done_small();
1027114402Sru  else
1028114402Sru    push_para(BIG_TAG);
1029114402Sru}
1030114402Sru
1031114402Sru/*
1032114402Sru *  do_sup - save a superscript tag on the stack of tags.
1033114402Sru */
1034114402Sru
1035114402Sruvoid html_text::do_sup (void)
1036114402Sru{
1037114402Sru  push_para(SUP_TAG);
1038114402Sru}
1039114402Sru
1040114402Sru/*
1041114402Sru *  do_sub - save a subscript tag on the stack of tags.
1042114402Sru */
1043114402Sru
1044114402Sruvoid html_text::do_sub (void)
1045114402Sru{
1046114402Sru  push_para(SUB_TAG);
1047114402Sru}
1048