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