From d318611dd6f23fcfedd50e9b9e24620b102ba96a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 21:44:05 +0200 Subject: Adding upstream version 1.23.0. Signed-off-by: Daniel Baumann --- src/devices/grohtml/html-text.cpp | 1056 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1056 insertions(+) create mode 100644 src/devices/grohtml/html-text.cpp (limited to 'src/devices/grohtml/html-text.cpp') diff --git a/src/devices/grohtml/html-text.cpp b/src/devices/grohtml/html-text.cpp new file mode 100644 index 0000000..b07cbe7 --- /dev/null +++ b/src/devices/grohtml/html-text.cpp @@ -0,0 +1,1056 @@ +// -*- C++ -*- +/* Copyright (C) 2000-2020 Free Software Foundation, Inc. + * + * Gaius Mulley (gaius@glam.ac.uk) wrote html-text.cpp + * + * html-text.cpp + * + * provide a troff like state machine interface which + * generates html text. + */ + +/* +This file is part of groff. + +groff is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation, either version 3 of the License, or +(at your option) any later version. + +groff is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . */ + +#include "driver.h" +#include "stringclass.h" +#include "cset.h" + +#if !defined(TRUE) +# define TRUE (1==1) +#endif +#if !defined(FALSE) +# define FALSE (1==0) +#endif + + +#include "html-text.h" + +html_text::html_text (simple_output *op, html_dialect d) : + stackptr(NULL), lastptr(NULL), out(op), dialect(d), + space_emitted(TRUE), current_indentation(-1), + pageoffset(-1), linelength(-1), blank_para(TRUE), + start_space(FALSE) +{ +} + +html_text::~html_text () +{ + flush_text(); +} + + +#if defined(DEBUGGING) +static int debugStack = FALSE; + + +/* + * turnDebug - flip the debugStack boolean and return the new value. + */ + +static int turnDebug (void) +{ + debugStack = 1-debugStack; + return debugStack; +} + +/* + * dump_stack_element - display an element of the html stack, p. + */ + +void html_text::dump_stack_element (tag_definition *p) +{ + fprintf(stderr, " | "); + switch (p->type) { + + case P_TAG: if (p->indent == NULL) { + fprintf(stderr, "

", (char *)p->arg1); break; + } else { + fprintf(stderr, "

", (char *)p->arg1); break; + } + case I_TAG: fprintf(stderr, ""); break; + case B_TAG: fprintf(stderr, ""); break; + case SUB_TAG: fprintf(stderr, ""); break; + case SUP_TAG: fprintf(stderr, ""); break; + case TT_TAG: fprintf(stderr, ""); break; + case PRE_TAG: if (p->indent == NULL) { + fprintf(stderr, "

"); break;
+                   } else {
+                      fprintf(stderr, "
"); break;
+		   }
+  case SMALL_TAG:  fprintf(stderr, ""); break;
+  case BIG_TAG:    fprintf(stderr, ""); break;
+  case BREAK_TAG:  fprintf(stderr, ""); break;
+  case COLOR_TAG:  {
+    if (p->col.is_default())
+      fprintf(stderr, "");
+    else {
+      unsigned int r, g, b;
+      
+      p->col.get_rgb(&r, &g, &b);
+      fprintf(stderr, "", r/0x101, g/0x101, b/0x101);
+    }
+    break;
+  }
+  default: fprintf(stderr, "unknown tag");
+  }
+  if (p->text_emitted)
+    fprintf(stderr, "[t] ");
+}
+
+/*
+ *  dump_stack - debugging function only.
+ */
+
+void html_text::dump_stack (void)
+{
+  if (debugStack) {
+    tag_definition *p = stackptr;
+
+    while (p != NULL) {
+      dump_stack_element(p);
+      p = p->next;
+    }
+  }
+  fprintf(stderr, "\n");
+  fflush(stderr);
+}
+#else
+void html_text::dump_stack (void) {}
+#endif
+
+
+/*
+ *  end_tag - shuts down the tag.
+ */
+
+void html_text::end_tag (tag_definition *t)
+{
+  switch (t->type) {
+
+  case I_TAG:      out->put_string(""); break;
+  case B_TAG:      out->put_string(""); break;
+  case P_TAG:      if (t->indent == NULL) {
+                     out->put_string("

"); + } else { + delete t->indent; + t->indent = NULL; + out->put_string("

"); + } + out->enable_newlines(FALSE); + blank_para = TRUE; break; + case SUB_TAG: out->put_string(""); break; + case SUP_TAG: out->put_string(""); break; + case TT_TAG: out->put_string("
"); break; + case PRE_TAG: out->put_string("
"); out->enable_newlines(TRUE); + blank_para = TRUE; + if (t->indent != NULL) + delete t->indent; + t->indent = NULL; + break; + case SMALL_TAG: if (! is_in_pre ()) + out->put_string(""); + break; + case BIG_TAG: if (! is_in_pre ()) + out->put_string(""); + break; + case COLOR_TAG: if (! is_in_pre ()) + out->put_string(""); + break; + + default: + error("unrecognised tag"); + } +} + +/* + * issue_tag - writes out an html tag with argument. + * space == 0 if no space is requested + * space == 1 if a space is requested + * space == 2 if tag should not have a space style + */ + +void html_text::issue_tag (const char *tagname, const char *arg, + int space) +{ + if ((arg == 0) || (strlen(arg) == 0)) + out->put_string(tagname); + else { + out->put_string(tagname); + out->put_string(" "); + out->put_string(arg); + } + if (space == TRUE) { + out->put_string(" style=\"margin-top: "); + out->put_string(STYLE_VERTICAL_SPACE); + out->put_string("\""); + } +#if 0 + if (space == TRUE || space == FALSE) + out->put_string(" valign=\"top\""); +#endif + out->put_string(">"); +} + +/* + * issue_color_begin - writes out an html color tag. + */ + +void html_text::issue_color_begin (color *c) +{ + char buf[(INT_HEXDIGITS * 3) + 1]; + unsigned int r, g, b; + + out->put_string("is_default()) + sprintf(buf, "000000"); + else { + c->get_rgb(&r, &g, &b); + // we have to scale 0..0xFFFF to 0..0xFF + sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); + } + out->put_string(buf); + out->put_string("\">"); +} + +/* + * start_tag - starts a tag. + */ + +void html_text::start_tag (tag_definition *t) +{ + switch (t->type) { + + case I_TAG: issue_tag("arg1); break; + case B_TAG: issue_tag("arg1); break; + case P_TAG: if (t->indent != NULL) { + out->nl(); +#if defined(DEBUGGING) + out->simple_comment("INDENTATION"); +#endif + out->put_string("\nindent->begin(start_space); + issue_tag("", (char *)t->arg1); + } else { + out->nl(); + issue_tag("\narg1, start_space); + } + + out->enable_newlines(TRUE); break; + case SUB_TAG: issue_tag("arg1); break; + case SUP_TAG: issue_tag("arg1); break; + case TT_TAG: issue_tag("arg1); break; + case PRE_TAG: out->enable_newlines(TRUE); + out->nl(); out->put_string("indent == NULL) + issue_tag("", (char *)t->arg1, start_space); + else { + t->indent->begin(start_space); + issue_tag("", (char *)t->arg1); + } + out->enable_newlines(FALSE); break; + case SMALL_TAG: if (! is_in_pre ()) + issue_tag("arg1); + break; + case BIG_TAG: if (! is_in_pre ()) + issue_tag("arg1); + break; + case BREAK_TAG: break; + case COLOR_TAG: if (! is_in_pre ()) + issue_color_begin(&t->col); + break; + + default: + error("unrecognised tag"); + } +} + +/* + * flush_text - flushes html tags which are outstanding on the html stack. + */ + +void html_text::flush_text (void) +{ + int notext=TRUE; + tag_definition *p=stackptr; + + while (stackptr != 0) { + notext = (notext && (! stackptr->text_emitted)); + if (! notext) { + end_tag(stackptr); + } + p = stackptr; + stackptr = stackptr->next; + delete p; + } + lastptr = NULL; +} + +/* + * is_present - returns TRUE if tag is already present on the stack. + */ + +int html_text::is_present (HTML_TAG t) +{ + tag_definition *p=stackptr; + + while (p != NULL) { + if (t == p->type) + return TRUE; + p = p->next; + } + return FALSE; +} + +/* + * uses_indent - returns TRUE if the current paragraph is using a + * html table to effect an indent. + */ + +int html_text::uses_indent (void) +{ + tag_definition *p = stackptr; + + while (p != NULL) { + if (p->indent != NULL) + return TRUE; + p = p->next; + } + return FALSE; +} + +extern void stop(); + +/* + * do_push - places, tag_definition, p, onto the stack + */ + +void html_text::do_push (tag_definition *p) +{ + HTML_TAG t = p->type; + +#if defined(DEBUGGING) + if (t == PRE_TAG) + stop(); + debugStack = TRUE; + fprintf(stderr, "\nentering do_push ("); + dump_stack_element(p); + fprintf(stderr, ")\n"); + dump_stack(); + fprintf(stderr, ")\n"); + fflush(stderr); +#endif + + /* + * if t is a P_TAG or PRE_TAG make sure it goes on the end of the stack. + */ + + if (((t == P_TAG) || (t == PRE_TAG)) && (lastptr != NULL)) { + /* + * store, p, at the end + */ + lastptr->next = p; + lastptr = p; + p->next = NULL; + } else { + p->next = stackptr; + if (stackptr == NULL) + lastptr = p; + stackptr = p; + } + +#if defined(DEBUGGING) + dump_stack(); + fprintf(stderr, "exiting do_push\n"); +#endif +} + +/* + * push_para - adds a new entry onto the html paragraph stack. + */ + +void html_text::push_para (HTML_TAG t, void *arg, html_indent *in) +{ + tag_definition *p= new tag_definition; + + p->type = t; + p->arg1 = arg; + p->text_emitted = FALSE; + p->indent = in; + + if (t == PRE_TAG && is_present(PRE_TAG)) + fatal("cannot have multiple PRE_TAGs"); + + do_push(p); +} + +void html_text::push_para (HTML_TAG t) +{ + push_para(t, (void *)"", NULL); +} + +void html_text::push_para (color *c) +{ + tag_definition *p = new tag_definition; + + p->type = COLOR_TAG; + p->arg1 = NULL; + p->col = *c; + p->text_emitted = FALSE; + p->indent = NULL; + + do_push(p); +} + +/* + * do_italic - changes to italic + */ + +void html_text::do_italic (void) +{ + if (! is_present(I_TAG)) + push_para(I_TAG); +} + +/* + * do_bold - changes to bold. + */ + +void html_text::do_bold (void) +{ + if (! is_present(B_TAG)) + push_para(B_TAG); +} + +/* + * do_tt - changes to teletype. + */ + +void html_text::do_tt (void) +{ + if ((! is_present(TT_TAG)) && (! is_present(PRE_TAG))) + push_para(TT_TAG); +} + +/* + * do_pre - changes to preformated text. + */ + +void html_text::do_pre (void) +{ + done_tt(); + if (is_present(P_TAG)) { + html_indent *i = remove_indent(P_TAG); + int space = retrieve_para_space(); + (void)done_para(); + if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, i); + start_space = space; + } else if (! is_present(PRE_TAG)) + push_para(PRE_TAG, NULL, NULL); + dump_stack(); +} + +/* + * is_in_pre - returns TRUE if we are currently within a preformatted + *
 block.
+ */
+
+int html_text::is_in_pre (void)
+{
+  return is_present(PRE_TAG);
+}
+
+/*
+ *  do_color - initiates a new color tag.
+ */
+
+void html_text::do_color (color *c)
+{
+  shutdown(COLOR_TAG);   // shutdown a previous color tag, if present
+  push_para(c);
+}
+
+/*
+ *  done_color - shutdown an outstanding color tag, if it exists.
+ */
+
+void html_text::done_color (void)
+{
+  shutdown(COLOR_TAG);
+}
+
+/*
+ *  shutdown - shuts down an html tag.
+ */
+
+char *html_text::shutdown (HTML_TAG t)
+{
+  char *arg=NULL;
+
+  if (is_present(t)) {
+    tag_definition *p    =stackptr;
+    tag_definition *temp =NULL;
+    int notext           =TRUE;
+    
+    dump_stack();
+    while ((stackptr != NULL) && (stackptr->type != t)) {
+      notext = (notext && (! stackptr->text_emitted));
+      if (! notext) {
+	end_tag(stackptr);
+      }
+
+      /*
+       *  pop tag
+       */
+      p        = stackptr;
+      stackptr = stackptr->next;
+      if (stackptr == NULL)
+	lastptr = NULL;
+    
+      /*
+       *  push tag onto temp stack
+       */
+      p->next = temp;
+      temp    = p;
+    }
+
+    /*
+     *  and examine stackptr
+     */
+    if ((stackptr != NULL) && (stackptr->type == t)) {
+      if (stackptr->text_emitted) {
+	end_tag(stackptr);
+      }
+      if (t == P_TAG) {
+	arg = (char *)stackptr->arg1;
+      }
+      p        = stackptr;
+      stackptr = stackptr->next;
+      if (stackptr == NULL)
+	lastptr = NULL;
+      if (p->indent != NULL)
+	delete p->indent;
+      delete p;
+    }
+
+    /*
+     *  and restore unaffected tags
+     */
+    while (temp != NULL) {
+      if (temp->type == COLOR_TAG)
+	push_para(&temp->col);
+      else
+	push_para(temp->type, temp->arg1, temp->indent);
+      p    = temp;
+      temp = temp->next;
+      delete p;
+    }
+  }
+  return arg;
+}
+
+/*
+ *  done_bold - shuts downs a bold tag.
+ */
+
+void html_text::done_bold (void)
+{
+  shutdown(B_TAG);
+}
+
+/*
+ *  done_italic - shuts downs an italic tag.
+ */
+
+void html_text::done_italic (void)
+{
+  shutdown(I_TAG);
+}
+
+/*
+ *  done_sup - shuts downs a sup tag.
+ */
+
+void html_text::done_sup (void)
+{
+  shutdown(SUP_TAG);
+}
+
+/*
+ *  done_sub - shuts downs a sub tag.
+ */
+
+void html_text::done_sub (void)
+{
+  shutdown(SUB_TAG);
+}
+
+/*
+ *  done_tt - shuts downs a tt tag.
+ */
+
+void html_text::done_tt (void)
+{
+  shutdown(TT_TAG);
+}
+
+/*
+ *  done_pre - shuts downs a pre tag.
+ */
+
+void html_text::done_pre (void)
+{
+  shutdown(PRE_TAG);
+}
+
+/*
+ *  done_small - shuts downs a small tag.
+ */
+
+void html_text::done_small (void)
+{
+  shutdown(SMALL_TAG);
+}
+
+/*
+ *  done_big - shuts downs a big tag.
+ */
+
+void html_text::done_big (void)
+{
+  shutdown(BIG_TAG);
+}
+
+/*
+ *  check_emit_text - ensures that all previous tags have been emitted (in order)
+ *                    before the text is written.
+ */
+
+void html_text::check_emit_text (tag_definition *t)
+{
+  if ((t != NULL) && (! t->text_emitted)) {
+    check_emit_text(t->next);
+    t->text_emitted = TRUE;
+    start_tag(t);
+  }
+}
+
+/*
+ *  do_emittext - tells the class that text was written during the current tag.
+ */
+
+void html_text::do_emittext (const char *s, int length)
+{
+  if ((! is_present(P_TAG)) && (! is_present(PRE_TAG)))
+    do_para("", FALSE);
+
+  if (is_present(BREAK_TAG)) {
+    int text = remove_break();
+    check_emit_text(stackptr);
+    if (text) {
+      if (is_present(PRE_TAG))
+	out->nl();
+      else if (dialect == xhtml)
+	out->put_string("
").nl(); + else + out->put_string("
").nl(); + } + } else + check_emit_text(stackptr); + + out->put_string(s, length); + space_emitted = FALSE; + blank_para = FALSE; +} + +/* + * do_para - starts a new paragraph + */ + +void html_text::do_para (const char *arg, html_indent *in, int space) +{ + if (! is_present(P_TAG)) { + if (is_present(PRE_TAG)) { + html_indent *i = remove_indent(PRE_TAG); + done_pre(); + if ((arg == NULL || (strcmp(arg, "") == 0)) && + (i == in || in == NULL)) + in = i; + else + delete i; + } + remove_sub_sup(); + push_para(P_TAG, (void *)arg, in); + start_space = space; + } +} + +void html_text::do_para (const char *arg, int space) +{ + do_para(arg, NULL, space); +} + +void html_text::do_para (simple_output *op, const char *arg1, + int indentation_value, int page_offset, + int line_length, int space) +{ + html_indent *ind; + + if (indentation_value == 0) + ind = NULL; + else + ind = new html_indent(op, indentation_value, page_offset, line_length); + do_para(arg1, ind, space); +} + +/* + * done_para - shuts down a paragraph tag. + */ + +char *html_text::done_para (void) +{ + char *result; + space_emitted = TRUE; + result = shutdown(P_TAG); + start_space = FALSE; + return result; +} + +/* + * remove_indent - returns the indent associated with, tag. + * The indent associated with tag is set to NULL. + */ + +html_indent *html_text::remove_indent (HTML_TAG tag) +{ + tag_definition *p=stackptr; + + while (p != NULL) { + if (tag == p->type) { + html_indent *i = p->indent; + p->indent = NULL; + return i; + } + p = p->next; + } + return NULL; +} + +/* + * remove_para_space - removes the leading space to a paragraph + * (effectively this trims off a leading '.sp' tag). + */ + +void html_text::remove_para_space (void) +{ + start_space = FALSE; +} + +/* + * do_space - issues an end of paragraph + */ + +void html_text::do_space (void) +{ + if (is_in_pre()) { + do_emittext("", 0); + out->force_nl(); + space_emitted = TRUE; + } else { + html_indent *i = remove_indent(P_TAG); + + do_para(done_para(), i, TRUE); + space_emitted = TRUE; + } +} + +/* + * do_break - issue a break tag. + */ + +void html_text::do_break (void) +{ + if (! is_present(PRE_TAG)) + if (emitted_text()) + if (! is_present(BREAK_TAG)) + push_para(BREAK_TAG); + + space_emitted = TRUE; +} + +/* + * do_newline - issue a newline providing that we are inside a
 tag.
+ */
+
+void html_text::do_newline (void)
+{
+  if (is_present(PRE_TAG)) {
+    do_emittext("\n", 1);
+    space_emitted = TRUE;
+  }
+}
+
+/*
+ *  emitted_text - returns FALSE if white space has just been written.
+ */
+
+int html_text::emitted_text (void)
+{
+  return !space_emitted;
+}
+
+/*
+ *  ever_emitted_text - returns TRUE if we have ever emitted text in this
+ *                      paragraph.
+ */
+
+int html_text::ever_emitted_text (void)
+{
+  return !blank_para;
+}
+
+/*
+ *  starts_with_space - returns TRUE if we started this paragraph with a .sp
+ */
+
+int html_text::starts_with_space (void)
+{
+  return start_space;
+}
+
+/*
+ *  retrieve_para_space - returns TRUE, if the paragraph starts with
+ *                        a space and text has not yet been emitted.
+ *                        If TRUE is returned, then the, start_space,
+ *                        variable is set to FALSE.
+ */
+
+int html_text::retrieve_para_space (void)
+{
+  if (start_space && blank_para) {
+    start_space = FALSE;
+    return TRUE;
+  }
+  else
+    return FALSE;
+}
+
+/*
+ *  emit_space - writes a space providing that text was written beforehand.
+ */
+
+void html_text::emit_space (void)
+{
+  if (is_present(PRE_TAG))
+    do_emittext(" ", 1);
+  else
+    out->space_or_newline();
+
+  space_emitted = TRUE;
+}
+
+/*
+ *  remove_def - removes a definition, t, from the stack.
+ */
+
+void html_text::remove_def (tag_definition *t)
+{
+  tag_definition *p = stackptr;
+  tag_definition *l = 0;
+    
+  while ((p != 0) && (p != t)) {
+    l = p;
+    p = p->next;
+  }
+  if ((p != 0) && (p == t)) {
+    if (p == stackptr) {
+      stackptr = stackptr->next;
+      if (stackptr == NULL)
+	lastptr = NULL;
+    } else if (l == 0) {
+      error("stack list pointers are wrong");
+    } else {
+      l->next = p->next;
+      if (l->next == NULL)
+	lastptr = l;
+    }
+    delete p;
+  }
+}
+
+/*
+ *  remove_tag - removes a tag from the stack.
+ */
+
+void html_text::remove_tag (HTML_TAG tag)
+{
+  tag_definition *p = stackptr;
+    
+  while ((p != 0) && (p->type != tag)) {
+    p = p->next;
+  }
+  if ((p != 0) && (p->type == tag))
+    remove_def(p);
+}
+
+/*
+ *  remove_sub_sup - removes a sub or sup tag, should either exist
+ *                   on the stack.
+ */
+
+void html_text::remove_sub_sup (void)
+{
+  if (is_present(SUB_TAG)) {
+    remove_tag(SUB_TAG);
+  }
+  if (is_present(SUP_TAG)) {
+    remove_tag(SUP_TAG);
+  }
+  if (is_present(PRE_TAG)) {
+    remove_tag(PRE_TAG);
+  }
+}
+
+/*
+ *  remove_break - break tags are not balanced thus remove it once it has been emitted.
+ *                 It returns TRUE if text was emitted before the 
was issued. + */ + +int html_text::remove_break (void) +{ + tag_definition *p = stackptr; + tag_definition *l = 0; + tag_definition *q = 0; + + while ((p != 0) && (p->type != BREAK_TAG)) { + l = p; + p = p->next; + } + if ((p != 0) && (p->type == BREAK_TAG)) { + if (p == stackptr) { + stackptr = stackptr->next; + if (stackptr == NULL) + lastptr = NULL; + q = stackptr; + } else if (l == 0) + error("stack list pointers are wrong"); + else { + l->next = p->next; + q = p->next; + if (l->next == NULL) + lastptr = l; + } + delete p; + } + /* + * now determine whether text was issued before
+ */ + while (q != 0) { + if (q->text_emitted) + return TRUE; + else + q = q->next; + } + return FALSE; +} + +/* + * remove_para_align - removes a paragraph which has a text + * argument. If the paragraph has no text + * argument then it is left alone. + */ + +void html_text::remove_para_align (void) +{ + if (is_present(P_TAG)) { + tag_definition *p=stackptr; + + while (p != NULL) { + if (p->type == P_TAG && p->arg1 != NULL) { + html_indent *i = remove_indent(P_TAG); + int space = retrieve_para_space(); + done_para(); + do_para("", i, space); + return; + } + p = p->next; + } + } +} + +/* + * get_alignment - returns the alignment for the paragraph. + * If no alignment was given then we return "". + */ + +char *html_text::get_alignment (void) +{ + if (is_present(P_TAG)) { + tag_definition *p=stackptr; + + while (p != NULL) { + if (p->type == P_TAG && p->arg1 != NULL) + return (char *)p->arg1; + p = p->next; + } + } + return (char *)""; +} + +/* + * do_small - potentially inserts a tag into the html stream. + * However we check for a tag, if present then we terminate it. + * Otherwise a tag is inserted. + */ + +void html_text::do_small (void) +{ + if (is_present(BIG_TAG)) + done_big(); + else + push_para(SMALL_TAG); +} + +/* + * do_big - is the mirror image of do_small. + */ + +void html_text::do_big (void) +{ + if (is_present(SMALL_TAG)) + done_small(); + else + push_para(BIG_TAG); +} + +/* + * do_sup - save a superscript tag on the stack of tags. + */ + +void html_text::do_sup (void) +{ + push_para(SUP_TAG); +} + +/* + * do_sub - save a subscript tag on the stack of tags. + */ + +void html_text::do_sub (void) +{ + push_para(SUB_TAG); +} -- cgit v1.2.3