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:
|