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