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 post-html.cpp 6114402Sru * but it owes a huge amount of ideas and raw code from 7114402Sru * James Clark (jjc@jclark.com) grops/ps.cpp. 8114402Sru */ 9114402Sru 10114402Sru/* 11114402SruThis file is part of groff. 12114402Sru 13114402Srugroff is free software; you can redistribute it and/or modify it under 14114402Sruthe terms of the GNU General Public License as published by the Free 15114402SruSoftware Foundation; either version 2, or (at your option) any later 16114402Sruversion. 17114402Sru 18114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 19114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 20114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 21114402Srufor more details. 22114402Sru 23114402SruYou should have received a copy of the GNU General Public License along 24114402Sruwith groff; see the file COPYING. If not, write to the Free Software 25151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 26114402Sru 27114402Sru#include "driver.h" 28114402Sru#include "stringclass.h" 29114402Sru#include "cset.h" 30114402Sru#include "html.h" 31114402Sru#include "html-text.h" 32114402Sru#include "html-table.h" 33114402Sru 34114402Sru#include <time.h> 35114402Sru 36114402Sru#ifdef HAVE_UNISTD_H 37114402Sru#include <unistd.h> 38114402Sru#endif 39114402Sru 40114402Sru#include <stdio.h> 41114402Sru#include <fcntl.h> 42151497Sru#include <string.h> 43114402Sru 44114402Sruextern "C" const char *Version_string; 45114402Sru 46114402Sru#if !defined(TRUE) 47114402Sru# define TRUE (1==1) 48114402Sru#endif 49114402Sru#if !defined(FALSE) 50114402Sru# define FALSE (1==0) 51114402Sru#endif 52114402Sru 53114402Sru#define MAX_LINE_LENGTH 60 /* maximum characters we want in a line */ 54114402Sru#define SIZE_INCREMENT 2 /* font size increment <big> = +2 */ 55151497Sru#define CENTER_TOLERANCE 2 /* how many pixels off center do we allow */ 56114402Sru#define ANCHOR_TEMPLATE "heading" /* if simple anchor is set we use this */ 57114402Sru#define UNICODE_DESC_START 0x80 /* all character entities above this are */ 58114402Sru /* either encoded by their glyph names or if */ 59114402Sru /* there is no name then we use &#nnn; */ 60114402Srutypedef enum {CENTERED, LEFT, RIGHT, INLINE} TAG_ALIGNMENT; 61114402Srutypedef enum {col_tag, tab_tag, tab0_tag, none} colType; 62114402Sru 63114402Sru#undef DEBUG_TABLES 64151497Sru// #define DEBUG_TABLES 65114402Sru 66114402Sru/* 67114402Sru * prototypes 68114402Sru */ 69114402Sru 70114402Sruchar *get_html_translation (font *f, const string &name); 71114402Sruint char_translate_to_html (font *f, char *buf, int buflen, unsigned char ch, int b, int and_single); 72114402Sru 73114402Sru 74114402Srustatic int auto_links = TRUE; /* by default we enable automatic links at */ 75114402Sru /* top of the document. */ 76114402Srustatic int auto_rule = TRUE; /* by default we enable an automatic rule */ 77114402Sru /* at the top and bottom of the document */ 78114402Srustatic int simple_anchors = FALSE; /* default to anchors with heading text */ 79114402Srustatic int manufacture_headings = FALSE; /* default is to use the Hn html headings, */ 80114402Sru /* rather than manufacture our own. */ 81114402Srustatic color *default_background = NULL; /* has user requested initial bg color? */ 82151497Srustatic string job_name; /* if set then the output is split into */ 83151497Sru /* multiple files with `job_name'-%d.html */ 84151497Srustatic int multiple_files = FALSE; /* must we the output be divided into */ 85151497Sru /* multiple html files, one for each */ 86151497Sru /* heading? */ 87151497Srustatic int base_point_size = 0; /* which troff font size maps onto html */ 88151497Sru /* size 3? */ 89151497Srustatic int split_level = 2; /* what heading level to split at? */ 90151497Srustatic string head_info; /* user supplied information to be placed */ 91151497Sru /* into <head> </head> */ 92114402Sru 93114402Sru 94114402Sru/* 95114402Sru * start with a few favorites 96114402Sru */ 97114402Sru 98114402Sruvoid stop () {} 99114402Sru 100114402Srustatic int min (int a, int b) 101114402Sru{ 102114402Sru if (a < b) 103114402Sru return a; 104114402Sru else 105114402Sru return b; 106114402Sru} 107114402Sru 108114402Srustatic int max (int a, int b) 109114402Sru{ 110114402Sru if (a > b) 111114402Sru return a; 112114402Sru else 113114402Sru return b; 114114402Sru} 115114402Sru 116114402Sru/* 117114402Sru * is_intersection - returns TRUE if range a1..a2 intersects with b1..b2 118114402Sru */ 119114402Sru 120114402Srustatic int is_intersection (int a1, int a2, int b1, int b2) 121114402Sru{ 122114402Sru // easier to prove NOT outside limits 123151497Sru return ! ((a1 > b2) || (a2 < b1)); 124114402Sru} 125114402Sru 126114402Sru/* 127114402Sru * is_digit - returns TRUE if character, ch, is a digit. 128114402Sru */ 129114402Sru 130114402Srustatic int is_digit (char ch) 131114402Sru{ 132151497Sru return (ch >= '0') && (ch <= '9'); 133114402Sru} 134114402Sru 135114402Sru/* 136114402Sru * the classes and methods for maintaining a list of files. 137114402Sru */ 138114402Sru 139114402Srustruct file { 140114402Sru FILE *fp; 141114402Sru file *next; 142151497Sru int new_output_file; 143151497Sru int require_links; 144151497Sru string output_file_name; 145114402Sru 146114402Sru file (FILE *f); 147114402Sru}; 148114402Sru 149114402Sru/* 150114402Sru * file - initialize all fields to NULL 151114402Sru */ 152114402Sru 153114402Srufile::file (FILE *f) 154151497Sru : fp(f), next(NULL), new_output_file(FALSE), 155151497Sru require_links(FALSE), output_file_name("") 156114402Sru{ 157114402Sru} 158114402Sru 159114402Sruclass files { 160114402Srupublic: 161151497Sru files (); 162151497Sru FILE *get_file (void); 163151497Sru void start_of_list (void); 164151497Sru void move_next (void); 165151497Sru void add_new_file (FILE *f); 166151497Sru void set_file_name (string name); 167151497Sru void set_links_required (void); 168151497Sru int are_links_required (void); 169151497Sru int is_new_output_file (void); 170151497Sru string file_name (void); 171151497Sru string next_file_name (void); 172114402Sruprivate: 173151497Sru file *head; 174151497Sru file *tail; 175151497Sru file *ptr; 176114402Sru}; 177114402Sru 178114402Sru/* 179114402Sru * files - create an empty list of files. 180114402Sru */ 181114402Sru 182114402Srufiles::files () 183151497Sru : head(NULL), tail(NULL), ptr(NULL) 184114402Sru{ 185114402Sru} 186114402Sru 187114402Sru/* 188114402Sru * get_file - returns the FILE associated with ptr. 189114402Sru */ 190114402Sru 191114402SruFILE *files::get_file (void) 192114402Sru{ 193151497Sru if (ptr) 194151497Sru return ptr->fp; 195151497Sru else 196151497Sru return NULL; 197114402Sru} 198114402Sru 199114402Sru/* 200114402Sru * start_of_list - reset the ptr to the start of the list. 201114402Sru */ 202114402Sru 203114402Sruvoid files::start_of_list (void) 204114402Sru{ 205114402Sru ptr = head; 206114402Sru} 207114402Sru 208114402Sru/* 209114402Sru * move_next - moves the ptr to the next element on the list. 210114402Sru */ 211114402Sru 212114402Sruvoid files::move_next (void) 213114402Sru{ 214151497Sru if (ptr != NULL) 215114402Sru ptr = ptr->next; 216114402Sru} 217114402Sru 218114402Sru/* 219114402Sru * add_new_file - adds a new file, f, to the list. 220114402Sru */ 221114402Sru 222114402Sruvoid files::add_new_file (FILE *f) 223114402Sru{ 224151497Sru if (head == NULL) { 225114402Sru head = new file(f); 226114402Sru tail = head; 227114402Sru } else { 228114402Sru tail->next = new file(f); 229114402Sru tail = tail->next; 230114402Sru } 231114402Sru ptr = tail; 232114402Sru} 233114402Sru 234114402Sru/* 235151497Sru * set_file_name - sets the final file name to contain the html 236151497Sru * data to name. 237151497Sru */ 238151497Sru 239151497Sruvoid files::set_file_name (string name) 240151497Sru{ 241151497Sru if (ptr != NULL) { 242151497Sru ptr->output_file_name = name; 243151497Sru ptr->new_output_file = TRUE; 244151497Sru } 245151497Sru} 246151497Sru 247151497Sru/* 248151497Sru * set_links_required - issue links when processing this component 249151497Sru * of the file. 250151497Sru */ 251151497Sru 252151497Sruvoid files::set_links_required (void) 253151497Sru{ 254151497Sru if (ptr != NULL) 255151497Sru ptr->require_links = TRUE; 256151497Sru} 257151497Sru 258151497Sru/* 259151497Sru * are_links_required - returns TRUE if this section of the file 260151497Sru * requires that links should be issued. 261151497Sru */ 262151497Sru 263151497Sruint files::are_links_required (void) 264151497Sru{ 265151497Sru if (ptr != NULL) 266151497Sru return ptr->require_links; 267151497Sru return FALSE; 268151497Sru} 269151497Sru 270151497Sru/* 271151497Sru * is_new_output_file - returns TRUE if this component of the file 272151497Sru * is the start of a new output file. 273151497Sru */ 274151497Sru 275151497Sruint files::is_new_output_file (void) 276151497Sru{ 277151497Sru if (ptr != NULL) 278151497Sru return ptr->new_output_file; 279151497Sru return FALSE; 280151497Sru} 281151497Sru 282151497Sru/* 283151497Sru * file_name - returns the name of the file. 284151497Sru */ 285151497Sru 286151497Srustring files::file_name (void) 287151497Sru{ 288151497Sru if (ptr != NULL) 289151497Sru return ptr->output_file_name; 290151497Sru return string(""); 291151497Sru} 292151497Sru 293151497Sru/* 294151497Sru * next_file_name - returns the name of the next file. 295151497Sru */ 296151497Sru 297151497Srustring files::next_file_name (void) 298151497Sru{ 299151497Sru if (ptr != NULL && ptr->next != NULL) 300151497Sru return ptr->next->output_file_name; 301151497Sru return string(""); 302151497Sru} 303151497Sru 304151497Sru/* 305114402Sru * the class and methods for styles 306114402Sru */ 307114402Sru 308114402Srustruct style { 309114402Sru font *f; 310114402Sru int point_size; 311114402Sru int font_no; 312114402Sru int height; 313114402Sru int slant; 314114402Sru color col; 315114402Sru style (); 316114402Sru style (font *, int, int, int, int, color); 317114402Sru int operator == (const style &) const; 318114402Sru int operator != (const style &) const; 319114402Sru}; 320114402Sru 321114402Srustyle::style() 322151497Sru : f(NULL) 323114402Sru{ 324114402Sru} 325114402Sru 326114402Srustyle::style(font *p, int sz, int h, int sl, int no, color c) 327114402Sru : f(p), point_size(sz), font_no(no), height(h), slant(sl), col(c) 328114402Sru{ 329114402Sru} 330114402Sru 331114402Sruint style::operator==(const style &s) const 332114402Sru{ 333114402Sru return (f == s.f && point_size == s.point_size 334114402Sru && height == s.height && slant == s.slant && col == s.col); 335114402Sru} 336114402Sru 337114402Sruint style::operator!=(const style &s) const 338114402Sru{ 339114402Sru return !(*this == s); 340114402Sru} 341114402Sru 342114402Sru/* 343114402Sru * the class and methods for retaining ascii text 344114402Sru */ 345114402Sru 346114402Srustruct char_block { 347114402Sru enum { SIZE = 256 }; 348114402Sru char *buffer; 349114402Sru int used; 350114402Sru char_block *next; 351114402Sru 352114402Sru char_block(); 353114402Sru char_block(int length); 354114402Sru ~char_block(); 355114402Sru}; 356114402Sru 357114402Sruchar_block::char_block() 358151497Sru: buffer(NULL), used(0), next(NULL) 359114402Sru{ 360114402Sru} 361114402Sru 362114402Sruchar_block::char_block(int length) 363151497Sru: used(0), next(NULL) 364114402Sru{ 365151497Sru buffer = new char[max(length, char_block::SIZE)]; 366114402Sru if (buffer == NULL) 367114402Sru fatal("out of memory error"); 368114402Sru} 369114402Sru 370114402Sruchar_block::~char_block() 371114402Sru{ 372114402Sru if (buffer != NULL) 373151497Sru a_delete buffer; 374114402Sru} 375114402Sru 376114402Sruclass char_buffer { 377114402Srupublic: 378114402Sru char_buffer(); 379114402Sru ~char_buffer(); 380114402Sru char *add_string(const char *, unsigned int); 381114402Sru char *add_string(const string &); 382114402Sruprivate: 383114402Sru char_block *head; 384114402Sru char_block *tail; 385114402Sru}; 386114402Sru 387114402Sruchar_buffer::char_buffer() 388151497Sru: head(NULL), tail(NULL) 389114402Sru{ 390114402Sru} 391114402Sru 392114402Sruchar_buffer::~char_buffer() 393114402Sru{ 394151497Sru while (head != NULL) { 395114402Sru char_block *temp = head; 396114402Sru head = head->next; 397114402Sru delete temp; 398114402Sru } 399114402Sru} 400114402Sru 401114402Sruchar *char_buffer::add_string (const char *s, unsigned int length) 402114402Sru{ 403114402Sru int i=0; 404114402Sru unsigned int old_used; 405114402Sru 406114402Sru if (s == NULL || length == 0) 407114402Sru return NULL; 408114402Sru 409151497Sru if (tail == NULL) { 410114402Sru tail = new char_block(length+1); 411114402Sru head = tail; 412114402Sru } else { 413114402Sru if (tail->used + length+1 > char_block::SIZE) { 414114402Sru tail->next = new char_block(length+1); 415114402Sru tail = tail->next; 416114402Sru } 417114402Sru } 418114402Sru 419114402Sru old_used = tail->used; 420114402Sru do { 421114402Sru tail->buffer[tail->used] = s[i]; 422114402Sru tail->used++; 423114402Sru i++; 424114402Sru length--; 425114402Sru } while (length>0); 426114402Sru 427114402Sru // add terminating nul character 428114402Sru 429114402Sru tail->buffer[tail->used] = '\0'; 430114402Sru tail->used++; 431114402Sru 432114402Sru // and return start of new string 433114402Sru 434151497Sru return &tail->buffer[old_used]; 435114402Sru} 436114402Sru 437114402Sruchar *char_buffer::add_string (const string &s) 438114402Sru{ 439114402Sru return add_string(s.contents(), s.length()); 440114402Sru} 441114402Sru 442114402Sru/* 443114402Sru * the classes and methods for maintaining glyph positions. 444114402Sru */ 445114402Sru 446114402Sruclass text_glob { 447114402Srupublic: 448114402Sru void text_glob_html (style *s, char *str, int length, 449114402Sru int min_vertical, int min_horizontal, 450114402Sru int max_vertical, int max_horizontal); 451114402Sru void text_glob_special (style *s, char *str, int length, 452114402Sru int min_vertical, int min_horizontal, 453114402Sru int max_vertical, int max_horizontal); 454114402Sru void text_glob_line (style *s, 455114402Sru int min_vertical, int min_horizontal, 456114402Sru int max_vertical, int max_horizontal, 457114402Sru int thickness); 458114402Sru void text_glob_auto_image(style *s, char *str, int length, 459114402Sru int min_vertical, int min_horizontal, 460114402Sru int max_vertical, int max_horizontal); 461114402Sru void text_glob_tag (style *s, char *str, int length, 462114402Sru int min_vertical, int min_horizontal, 463114402Sru int max_vertical, int max_horizontal); 464114402Sru 465114402Sru text_glob (void); 466114402Sru ~text_glob (void); 467114402Sru int is_a_line (void); 468114402Sru int is_a_tag (void); 469114402Sru int is_eol (void); 470114402Sru int is_auto_img (void); 471114402Sru int is_br (void); 472114402Sru int is_in (void); 473114402Sru int is_po (void); 474114402Sru int is_ti (void); 475151497Sru int is_ll (void); 476114402Sru int is_ce (void); 477151497Sru int is_tl (void); 478151497Sru int is_eo_tl (void); 479114402Sru int is_eol_ce (void); 480114402Sru int is_col (void); 481114402Sru int is_tab (void); 482114402Sru int is_tab0 (void); 483114402Sru int is_ta (void); 484114402Sru int is_tab_ts (void); 485114402Sru int is_tab_te (void); 486114402Sru int is_nf (void); 487114402Sru int is_fi (void); 488151497Sru int is_eo_h (void); 489114402Sru int get_arg (void); 490114402Sru int get_tab_args (char *align); 491114402Sru 492114402Sru void remember_table (html_table *t); 493114402Sru html_table *get_table (void); 494114402Sru 495114402Sru style text_style; 496114402Sru const char *text_string; 497114402Sru unsigned int text_length; 498114402Sru int minv, minh, maxv, maxh; 499114402Sru int is_tag; // is this a .br, .sp, .tl etc 500114402Sru int is_img_auto; // image created by eqn delim 501114402Sru int is_special; // text has come via 'x X html:' 502114402Sru int is_line; // is the command a <line>? 503114402Sru int thickness; // the thickness of a line 504114402Sru html_table *tab; // table description 505114402Sru 506114402Sruprivate: 507114402Sru text_glob (style *s, const char *str, int length, 508114402Sru int min_vertical , int min_horizontal, 509114402Sru int max_vertical , int max_horizontal, 510114402Sru bool is_troff_command, 511114402Sru bool is_auto_image, bool is_special_command, 512114402Sru bool is_a_line , int thickness); 513114402Sru}; 514114402Sru 515114402Srutext_glob::text_glob (style *s, const char *str, int length, 516114402Sru int min_vertical, int min_horizontal, 517114402Sru int max_vertical, int max_horizontal, 518114402Sru bool is_troff_command, 519114402Sru bool is_auto_image, bool is_special_command, 520151497Sru bool is_a_line_flag, int line_thickness) 521114402Sru : text_style(*s), text_string(str), text_length(length), 522114402Sru minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal), 523114402Sru is_tag(is_troff_command), is_img_auto(is_auto_image), is_special(is_special_command), 524151497Sru is_line(is_a_line_flag), thickness(line_thickness), tab(NULL) 525114402Sru{ 526114402Sru} 527114402Sru 528114402Srutext_glob::text_glob () 529151497Sru : text_string(NULL), text_length(0), minv(-1), minh(-1), maxv(-1), maxh(-1), 530114402Sru is_tag(FALSE), is_special(FALSE), is_line(FALSE), thickness(0), tab(NULL) 531114402Sru{ 532114402Sru} 533114402Sru 534114402Srutext_glob::~text_glob () 535114402Sru{ 536114402Sru if (tab != NULL) 537114402Sru delete tab; 538114402Sru} 539114402Sru 540114402Sru/* 541114402Sru * text_glob_html - used to place html text into the glob buffer. 542114402Sru */ 543114402Sru 544114402Sruvoid text_glob::text_glob_html (style *s, char *str, int length, 545114402Sru int min_vertical , int min_horizontal, 546114402Sru int max_vertical , int max_horizontal) 547114402Sru{ 548114402Sru text_glob *g = new text_glob(s, str, length, 549114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal, 550114402Sru FALSE, FALSE, FALSE, FALSE, 0); 551114402Sru *this = *g; 552114402Sru delete g; 553114402Sru} 554114402Sru 555114402Sru/* 556114402Sru * text_glob_html - used to place html specials into the glob buffer. 557114402Sru * This text is essentially html commands coming through 558114402Sru * from the macro sets, with special designated sequences of 559114402Sru * characters translated into html. See add_and_encode. 560114402Sru */ 561114402Sru 562114402Sruvoid text_glob::text_glob_special (style *s, char *str, int length, 563114402Sru int min_vertical , int min_horizontal, 564114402Sru int max_vertical , int max_horizontal) 565114402Sru{ 566114402Sru text_glob *g = new text_glob(s, str, length, 567114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal, 568114402Sru FALSE, FALSE, TRUE, FALSE, 0); 569114402Sru *this = *g; 570114402Sru delete g; 571114402Sru} 572114402Sru 573114402Sru/* 574114402Sru * text_glob_line - record horizontal draw line commands. 575114402Sru */ 576114402Sru 577114402Sruvoid text_glob::text_glob_line (style *s, 578114402Sru int min_vertical , int min_horizontal, 579114402Sru int max_vertical , int max_horizontal, 580151497Sru int thickness_value) 581114402Sru{ 582114402Sru text_glob *g = new text_glob(s, "", 0, 583114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal, 584151497Sru FALSE, FALSE, FALSE, TRUE, thickness_value); 585114402Sru *this = *g; 586114402Sru delete g; 587114402Sru} 588114402Sru 589114402Sru/* 590114402Sru * text_glob_auto_image - record the presence of a .auto-image tag command. 591114402Sru * Used to mark that an image has been created automatically 592114402Sru * by a preprocessor and (pre-grohtml/troff) combination. 593114402Sru * Under some circumstances images may not be created. 594114402Sru * (consider .EQ 595114402Sru * delim $$ 596114402Sru * .EN 597114402Sru * .TS 598114402Sru * tab(!), center; 599114402Sru * l!l. 600114402Sru * $1 over x$!recripical of x 601114402Sru * .TE 602114402Sru * 603114402Sru * the first auto-image marker is created via .EQ/.EN pair 604114402Sru * and no image is created. 605114402Sru * The second auto-image marker occurs at $1 over x$ 606114402Sru * Currently this image will not be created 607114402Sru * as the whole of the table is created as an image. 608114402Sru * (Once html tables are handled by grohtml this will change. 609114402Sru * Shortly this will be the case). 610114402Sru */ 611114402Sru 612114402Sruvoid text_glob::text_glob_auto_image(style *s, char *str, int length, 613114402Sru int min_vertical, int min_horizontal, 614114402Sru int max_vertical, int max_horizontal) 615114402Sru{ 616114402Sru text_glob *g = new text_glob(s, str, length, 617114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal, 618114402Sru TRUE, TRUE, FALSE, FALSE, 0); 619114402Sru *this = *g; 620114402Sru delete g; 621114402Sru} 622114402Sru 623114402Sru/* 624114402Sru * text_glob_tag - records a troff tag. 625114402Sru */ 626114402Sru 627114402Sruvoid text_glob::text_glob_tag (style *s, char *str, int length, 628114402Sru int min_vertical, int min_horizontal, 629114402Sru int max_vertical, int max_horizontal) 630114402Sru{ 631114402Sru text_glob *g = new text_glob(s, str, length, 632114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal, 633114402Sru TRUE, FALSE, FALSE, FALSE, 0); 634114402Sru *this = *g; 635114402Sru delete g; 636114402Sru} 637114402Sru 638114402Sru/* 639114402Sru * is_a_line - returns TRUE if glob should be converted into an <hr> 640114402Sru */ 641114402Sru 642114402Sruint text_glob::is_a_line (void) 643114402Sru{ 644114402Sru return is_line; 645114402Sru} 646114402Sru 647114402Sru/* 648114402Sru * is_a_tag - returns TRUE if glob contains a troff directive. 649114402Sru */ 650114402Sru 651114402Sruint text_glob::is_a_tag (void) 652114402Sru{ 653114402Sru return is_tag; 654114402Sru} 655114402Sru 656114402Sru/* 657114402Sru * is_eol - returns TRUE if glob contains the tag eol 658114402Sru */ 659114402Sru 660114402Sruint text_glob::is_eol (void) 661114402Sru{ 662151497Sru return is_tag && (strcmp(text_string, "devtag:.eol") == 0); 663114402Sru} 664114402Sru 665114402Sru/* 666114402Sru * is_eol_ce - returns TRUE if glob contains the tag eol.ce 667114402Sru */ 668114402Sru 669114402Sruint text_glob::is_eol_ce (void) 670114402Sru{ 671151497Sru return is_tag && (strcmp(text_string, "devtag:eol.ce") == 0); 672114402Sru} 673114402Sru 674151497Sru/* 675151497Sru * is_tl - returns TRUE if glob contains the tag .tl 676151497Sru */ 677114402Sru 678151497Sruint text_glob::is_tl (void) 679151497Sru{ 680151497Sru return is_tag && (strcmp(text_string, "devtag:.tl") == 0); 681151497Sru} 682151497Sru 683114402Sru/* 684151497Sru * is_eo_tl - returns TRUE if glob contains the tag eo.tl 685114402Sru */ 686114402Sru 687151497Sruint text_glob::is_eo_tl (void) 688151497Sru{ 689151497Sru return is_tag && (strcmp(text_string, "devtag:.eo.tl") == 0); 690151497Sru} 691151497Sru 692151497Sru/* 693151497Sru * is_nf - returns TRUE if glob contains the tag .fi 0 694151497Sru */ 695151497Sru 696114402Sruint text_glob::is_nf (void) 697114402Sru{ 698151497Sru return is_tag && (strncmp(text_string, "devtag:.fi", 699151497Sru strlen("devtag:.fi")) == 0) && 700151497Sru (get_arg() == 0); 701114402Sru} 702114402Sru 703114402Sru/* 704151497Sru * is_fi - returns TRUE if glob contains the tag .fi 1 705114402Sru */ 706114402Sru 707114402Sruint text_glob::is_fi (void) 708114402Sru{ 709151497Sru return( is_tag && (strncmp(text_string, "devtag:.fi", 710151497Sru strlen("devtag:.fi")) == 0) && 711151497Sru (get_arg() == 1) ); 712114402Sru} 713114402Sru 714114402Sru/* 715151497Sru * is_eo_h - returns TRUE if glob contains the tag .eo.h 716151497Sru */ 717151497Sru 718151497Sruint text_glob::is_eo_h (void) 719151497Sru{ 720151497Sru return is_tag && (strcmp(text_string, "devtag:.eo.h") == 0); 721151497Sru} 722151497Sru 723151497Sru/* 724114402Sru * is_ce - returns TRUE if glob contains the tag .ce 725114402Sru */ 726114402Sru 727114402Sruint text_glob::is_ce (void) 728114402Sru{ 729151497Sru return is_tag && (strncmp(text_string, "devtag:.ce", 730151497Sru strlen("devtag:.ce")) == 0); 731114402Sru} 732114402Sru 733114402Sru/* 734114402Sru * is_in - returns TRUE if glob contains the tag .in 735114402Sru */ 736114402Sru 737114402Sruint text_glob::is_in (void) 738114402Sru{ 739151497Sru return is_tag && (strncmp(text_string, "devtag:.in ", 740151497Sru strlen("devtag:.in ")) == 0); 741114402Sru} 742114402Sru 743114402Sru/* 744114402Sru * is_po - returns TRUE if glob contains the tag .po 745114402Sru */ 746114402Sru 747114402Sruint text_glob::is_po (void) 748114402Sru{ 749151497Sru return is_tag && (strncmp(text_string, "devtag:.po ", 750151497Sru strlen("devtag:.po ")) == 0); 751114402Sru} 752114402Sru 753114402Sru/* 754114402Sru * is_ti - returns TRUE if glob contains the tag .ti 755114402Sru */ 756114402Sru 757114402Sruint text_glob::is_ti (void) 758114402Sru{ 759151497Sru return is_tag && (strncmp(text_string, "devtag:.ti ", 760151497Sru strlen("devtag:.ti ")) == 0); 761114402Sru} 762114402Sru 763114402Sru/* 764151497Sru * is_ll - returns TRUE if glob contains the tag .ll 765151497Sru */ 766151497Sru 767151497Sruint text_glob::is_ll (void) 768151497Sru{ 769151497Sru return is_tag && (strncmp(text_string, "devtag:.ll ", 770151497Sru strlen("devtag:.ll ")) == 0); 771151497Sru} 772151497Sru 773151497Sru/* 774114402Sru * is_col - returns TRUE if glob contains the tag .col 775114402Sru */ 776114402Sru 777114402Sruint text_glob::is_col (void) 778114402Sru{ 779151497Sru return is_tag && (strncmp(text_string, "devtag:.col", 780151497Sru strlen("devtag:.col")) == 0); 781114402Sru} 782114402Sru 783114402Sru/* 784114402Sru * is_tab_ts - returns TRUE if glob contains the tag .tab_ts 785114402Sru */ 786114402Sru 787114402Sruint text_glob::is_tab_ts (void) 788114402Sru{ 789151497Sru return is_tag && (strcmp(text_string, "devtag:.tab-ts") == 0); 790114402Sru} 791114402Sru 792114402Sru/* 793114402Sru * is_tab_te - returns TRUE if glob contains the tag .tab_te 794114402Sru */ 795114402Sru 796114402Sruint text_glob::is_tab_te (void) 797114402Sru{ 798151497Sru return is_tag && (strcmp(text_string, "devtag:.tab-te") == 0); 799114402Sru} 800114402Sru 801114402Sru/* 802114402Sru * is_ta - returns TRUE if glob contains the tag .ta 803114402Sru */ 804114402Sru 805114402Sruint text_glob::is_ta (void) 806114402Sru{ 807151497Sru return is_tag && (strncmp(text_string, "devtag:.ta ", 808151497Sru strlen("devtag:.ta ")) == 0); 809114402Sru} 810114402Sru 811114402Sru/* 812114402Sru * is_tab - returns TRUE if glob contains the tag tab 813114402Sru */ 814114402Sru 815114402Sruint text_glob::is_tab (void) 816114402Sru{ 817151497Sru return is_tag && (strncmp(text_string, "devtag:tab ", 818151497Sru strlen("devtag:tab ")) == 0); 819114402Sru} 820114402Sru 821114402Sru/* 822114402Sru * is_tab0 - returns TRUE if glob contains the tag tab0 823114402Sru */ 824114402Sru 825114402Sruint text_glob::is_tab0 (void) 826114402Sru{ 827151497Sru return is_tag && (strncmp(text_string, "devtag:tab0", 828151497Sru strlen("devtag:tab0")) == 0); 829114402Sru} 830114402Sru 831114402Sru/* 832114402Sru * is_auto_img - returns TRUE if the glob contains an automatically 833114402Sru * generated image. 834114402Sru */ 835114402Sru 836114402Sruint text_glob::is_auto_img (void) 837114402Sru{ 838114402Sru return is_img_auto; 839114402Sru} 840114402Sru 841114402Sru/* 842114402Sru * is_br - returns TRUE if the glob is a tag containing a .br 843114402Sru * or an implied .br. Note that we do not include .nf or .fi 844114402Sru * as grohtml will place a .br after these commands if they 845114402Sru * should break the line. 846114402Sru */ 847114402Sru 848114402Sruint text_glob::is_br (void) 849114402Sru{ 850151497Sru return is_a_tag() && ((strcmp ("devtag:.br", text_string) == 0) || 851151497Sru (strncmp("devtag:.sp", text_string, 852151497Sru strlen("devtag:.sp")) == 0)); 853114402Sru} 854114402Sru 855114402Sruint text_glob::get_arg (void) 856114402Sru{ 857151497Sru if (strncmp("devtag:", text_string, strlen("devtag:")) == 0) { 858114402Sru const char *p = text_string; 859114402Sru 860114402Sru while ((*p != (char)0) && (!isspace(*p))) 861114402Sru p++; 862114402Sru while ((*p != (char)0) && (isspace(*p))) 863114402Sru p++; 864114402Sru if (*p == (char)0) 865114402Sru return -1; 866114402Sru return atoi(p); 867114402Sru } 868114402Sru return -1; 869114402Sru} 870114402Sru 871114402Sru/* 872114402Sru * get_tab_args - returns the tab position and alignment of the tab tag 873114402Sru */ 874114402Sru 875114402Sruint text_glob::get_tab_args (char *align) 876114402Sru{ 877151497Sru if (strncmp("devtag:", text_string, strlen("devtag:")) == 0) { 878114402Sru const char *p = text_string; 879114402Sru 880114402Sru // firstly the alignment C|R|L 881114402Sru while ((*p != (char)0) && (!isspace(*p))) 882114402Sru p++; 883114402Sru while ((*p != (char)0) && (isspace(*p))) 884114402Sru p++; 885114402Sru *align = *p; 886114402Sru // now the int value 887114402Sru while ((*p != (char)0) && (!isspace(*p))) 888114402Sru p++; 889114402Sru while ((*p != (char)0) && (isspace(*p))) 890114402Sru p++; 891114402Sru if (*p == (char)0) 892114402Sru return -1; 893114402Sru return atoi(p); 894114402Sru } 895114402Sru return -1; 896114402Sru} 897114402Sru 898114402Sru/* 899114402Sru * remember_table - saves table, t, in the text_glob. 900114402Sru */ 901114402Sru 902114402Sruvoid text_glob::remember_table (html_table *t) 903114402Sru{ 904114402Sru if (tab != NULL) 905114402Sru delete tab; 906114402Sru tab = t; 907114402Sru} 908114402Sru 909114402Sru/* 910114402Sru * get_table - returns the stored table description. 911114402Sru */ 912114402Sru 913114402Sruhtml_table *text_glob::get_table (void) 914114402Sru{ 915114402Sru return tab; 916114402Sru} 917114402Sru 918114402Sru/* 919151497Sru * the class and methods used to construct ordered double linked 920151497Sru * lists. In a previous implementation we used templates via 921151497Sru * #include "ordered-list.h", but this does assume that all C++ 922151497Sru * compilers can handle this feature. Pragmatically it is safer to 923151497Sru * assume this is not the case. 924114402Sru */ 925114402Sru 926114402Srustruct element_list { 927114402Sru element_list *right; 928114402Sru element_list *left; 929114402Sru text_glob *datum; 930114402Sru int lineno; 931114402Sru int minv, minh, maxv, maxh; 932114402Sru 933114402Sru element_list (text_glob *d, 934114402Sru int line_number, 935114402Sru int min_vertical, int min_horizontal, 936114402Sru int max_vertical, int max_horizontal); 937114402Sru element_list (); 938114402Sru ~element_list (); 939114402Sru}; 940114402Sru 941114402Sruelement_list::element_list () 942114402Sru : right(0), left(0), datum(0), lineno(0), minv(-1), minh(-1), maxv(-1), maxh(-1) 943114402Sru{ 944114402Sru} 945114402Sru 946114402Sru/* 947114402Sru * element_list - create a list element assigning the datum and region parameters. 948114402Sru */ 949114402Sru 950114402Sruelement_list::element_list (text_glob *in, 951114402Sru int line_number, 952114402Sru int min_vertical, int min_horizontal, 953114402Sru int max_vertical, int max_horizontal) 954114402Sru : right(0), left(0), datum(in), lineno(line_number), 955114402Sru minv(min_vertical), minh(min_horizontal), maxv(max_vertical), maxh(max_horizontal) 956114402Sru{ 957114402Sru} 958114402Sru 959114402Sruelement_list::~element_list () 960114402Sru{ 961114402Sru if (datum != NULL) 962114402Sru delete datum; 963114402Sru} 964114402Sru 965114402Sruclass list { 966114402Srupublic: 967114402Sru list (); 968114402Sru ~list (); 969114402Sru int is_less (element_list *a, element_list *b); 970114402Sru void add (text_glob *in, 971114402Sru int line_number, 972114402Sru int min_vertical, int min_horizontal, 973114402Sru int max_vertical, int max_horizontal); 974114402Sru void sub_move_right (void); 975114402Sru void move_right (void); 976114402Sru void move_left (void); 977114402Sru int is_empty (void); 978114402Sru int is_equal_to_tail (void); 979114402Sru int is_equal_to_head (void); 980114402Sru void start_from_head (void); 981114402Sru void start_from_tail (void); 982114402Sru void insert (text_glob *in); 983114402Sru void move_to (text_glob *in); 984114402Sru text_glob *move_right_get_data (void); 985114402Sru text_glob *move_left_get_data (void); 986114402Sru text_glob *get_data (void); 987114402Sruprivate: 988114402Sru element_list *head; 989114402Sru element_list *tail; 990114402Sru element_list *ptr; 991114402Sru}; 992114402Sru 993114402Sru/* 994114402Sru * list - construct an empty list. 995114402Sru */ 996114402Sru 997114402Srulist::list () 998114402Sru : head(NULL), tail(NULL), ptr(NULL) 999114402Sru{ 1000114402Sru} 1001114402Sru 1002114402Sru/* 1003114402Sru * ~list - destroy a complete list. 1004114402Sru */ 1005114402Sru 1006114402Srulist::~list() 1007114402Sru{ 1008114402Sru element_list *temp=head; 1009114402Sru 1010114402Sru do { 1011114402Sru temp = head; 1012114402Sru if (temp != NULL) { 1013114402Sru head = head->right; 1014114402Sru delete temp; 1015114402Sru } 1016114402Sru } while ((head != NULL) && (head != tail)); 1017114402Sru} 1018114402Sru 1019114402Sru/* 1020114402Sru * is_less - returns TRUE if a is left of b if on the same line or 1021114402Sru * if a is higher up the page than b. 1022114402Sru */ 1023114402Sru 1024114402Sruint list::is_less (element_list *a, element_list *b) 1025114402Sru{ 1026114402Sru // was if (is_intersection(a->minv+1, a->maxv-1, b->minv+1, b->maxv-1)) { 1027114402Sru if (a->lineno < b->lineno) { 1028114402Sru return( TRUE ); 1029114402Sru } else if (a->lineno > b->lineno) { 1030114402Sru return( FALSE ); 1031114402Sru } else if (is_intersection(a->minv, a->maxv, b->minv, b->maxv)) { 1032114402Sru return( a->minh < b->minh ); 1033114402Sru } else { 1034114402Sru return( a->maxv < b->maxv ); 1035114402Sru } 1036114402Sru} 1037114402Sru 1038114402Sru/* 1039151497Sru * add - adds a datum to the list in the order specified by the 1040151497Sru * region position. 1041114402Sru */ 1042114402Sru 1043114402Sruvoid list::add (text_glob *in, int line_number, int min_vertical, int min_horizontal, int max_vertical, int max_horizontal) 1044114402Sru{ 1045114402Sru // create a new list element with datum and position fields initialized 1046114402Sru element_list *t = new element_list(in, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); 1047114402Sru element_list *last; 1048114402Sru 1049151497Sru#if 0 1050151497Sru fprintf(stderr, "[%s %d,%d,%d,%d] ", 1051151497Sru in->text_string, min_vertical, min_horizontal, max_vertical, max_horizontal); 1052151497Sru fflush(stderr); 1053151497Sru#endif 1054151497Sru 1055151497Sru if (head == NULL) { 1056114402Sru head = t; 1057114402Sru tail = t; 1058114402Sru ptr = t; 1059114402Sru t->left = t; 1060114402Sru t->right = t; 1061114402Sru } else { 1062114402Sru last = tail; 1063114402Sru 1064151497Sru while ((last != head) && (is_less(t, last))) 1065114402Sru last = last->left; 1066114402Sru 1067114402Sru if (is_less(t, last)) { 1068114402Sru t->right = last; 1069114402Sru last->left->right = t; 1070114402Sru t->left = last->left; 1071114402Sru last->left = t; 1072114402Sru // now check for a new head 1073151497Sru if (last == head) 1074114402Sru head = t; 1075114402Sru } else { 1076114402Sru // add t beyond last 1077114402Sru t->right = last->right; 1078114402Sru t->left = last; 1079114402Sru last->right->left = t; 1080114402Sru last->right = t; 1081114402Sru // now check for a new tail 1082151497Sru if (last == tail) 1083114402Sru tail = t; 1084114402Sru } 1085114402Sru } 1086114402Sru} 1087114402Sru 1088114402Sru/* 1089114402Sru * sub_move_right - removes the element which is currently pointed to by ptr 1090114402Sru * from the list and moves ptr to the right. 1091114402Sru */ 1092114402Sru 1093114402Sruvoid list::sub_move_right (void) 1094114402Sru{ 1095114402Sru element_list *t=ptr->right; 1096114402Sru 1097114402Sru if (head == tail) { 1098151497Sru head = NULL; 1099151497Sru if (tail != NULL) 1100114402Sru delete tail; 1101151497Sru 1102151497Sru tail = NULL; 1103151497Sru ptr = NULL; 1104114402Sru } else { 1105151497Sru if (head == ptr) 1106114402Sru head = head->right; 1107151497Sru if (tail == ptr) 1108114402Sru tail = tail->left; 1109114402Sru ptr->left->right = ptr->right; 1110114402Sru ptr->right->left = ptr->left; 1111151497Sru ptr = t; 1112114402Sru } 1113114402Sru} 1114114402Sru 1115114402Sru/* 1116114402Sru * start_from_head - assigns ptr to the head. 1117114402Sru */ 1118114402Sru 1119114402Sruvoid list::start_from_head (void) 1120114402Sru{ 1121114402Sru ptr = head; 1122114402Sru} 1123114402Sru 1124114402Sru/* 1125114402Sru * start_from_tail - assigns ptr to the tail. 1126114402Sru */ 1127114402Sru 1128114402Sruvoid list::start_from_tail (void) 1129114402Sru{ 1130114402Sru ptr = tail; 1131114402Sru} 1132114402Sru 1133114402Sru/* 1134114402Sru * is_empty - returns TRUE if the list has no elements. 1135114402Sru */ 1136114402Sru 1137114402Sruint list::is_empty (void) 1138114402Sru{ 1139151497Sru return head == NULL; 1140114402Sru} 1141114402Sru 1142114402Sru/* 1143114402Sru * is_equal_to_tail - returns TRUE if the ptr equals the tail. 1144114402Sru */ 1145114402Sru 1146114402Sruint list::is_equal_to_tail (void) 1147114402Sru{ 1148151497Sru return ptr == tail; 1149114402Sru} 1150114402Sru 1151114402Sru/* 1152114402Sru * is_equal_to_head - returns TRUE if the ptr equals the head. 1153114402Sru */ 1154114402Sru 1155114402Sruint list::is_equal_to_head (void) 1156114402Sru{ 1157151497Sru return ptr == head; 1158114402Sru} 1159114402Sru 1160114402Sru/* 1161114402Sru * move_left - moves the ptr left. 1162114402Sru */ 1163114402Sru 1164114402Sruvoid list::move_left (void) 1165114402Sru{ 1166114402Sru ptr = ptr->left; 1167114402Sru} 1168114402Sru 1169114402Sru/* 1170114402Sru * move_right - moves the ptr right. 1171114402Sru */ 1172114402Sru 1173114402Sruvoid list::move_right (void) 1174114402Sru{ 1175114402Sru ptr = ptr->right; 1176114402Sru} 1177114402Sru 1178114402Sru/* 1179114402Sru * get_datum - returns the datum referenced via ptr. 1180114402Sru */ 1181114402Sru 1182114402Srutext_glob* list::get_data (void) 1183114402Sru{ 1184151497Sru return ptr->datum; 1185114402Sru} 1186114402Sru 1187114402Sru/* 1188114402Sru * move_right_get_data - returns the datum referenced via ptr and moves 1189114402Sru * ptr right. 1190114402Sru */ 1191114402Sru 1192114402Srutext_glob* list::move_right_get_data (void) 1193114402Sru{ 1194114402Sru ptr = ptr->right; 1195151497Sru if (ptr == head) 1196151497Sru return NULL; 1197151497Sru else 1198151497Sru return ptr->datum; 1199114402Sru} 1200114402Sru 1201114402Sru/* 1202114402Sru * move_left_get_data - returns the datum referenced via ptr and moves 1203114402Sru * ptr right. 1204114402Sru */ 1205114402Sru 1206114402Srutext_glob* list::move_left_get_data (void) 1207114402Sru{ 1208114402Sru ptr = ptr->left; 1209151497Sru if (ptr == tail) 1210151497Sru return NULL; 1211151497Sru else 1212151497Sru return ptr->datum; 1213114402Sru} 1214114402Sru 1215114402Sru/* 1216114402Sru * insert - inserts data after the current position. 1217114402Sru */ 1218114402Sru 1219114402Sruvoid list::insert (text_glob *in) 1220114402Sru{ 1221114402Sru if (is_empty()) 1222114402Sru fatal("list must not be empty if we are inserting data"); 1223114402Sru else { 1224151497Sru if (ptr == NULL) 1225114402Sru ptr = head; 1226114402Sru 1227114402Sru element_list *t = new element_list(in, ptr->lineno, ptr->minv, ptr->minh, ptr->maxv, ptr->maxh); 1228114402Sru if (ptr == tail) 1229114402Sru tail = t; 1230114402Sru ptr->right->left = t; 1231114402Sru t->right = ptr->right; 1232114402Sru ptr->right = t; 1233114402Sru t->left = ptr; 1234114402Sru } 1235114402Sru} 1236114402Sru 1237114402Sru/* 1238114402Sru * move_to - moves the current position to the point where data, in, exists. 1239114402Sru * This is an expensive method and should be used sparingly. 1240114402Sru */ 1241114402Sru 1242114402Sruvoid list::move_to (text_glob *in) 1243114402Sru{ 1244114402Sru ptr = head; 1245114402Sru while (ptr != tail && ptr->datum != in) 1246114402Sru ptr = ptr->right; 1247114402Sru} 1248114402Sru 1249114402Sru/* 1250114402Sru * page class and methods 1251114402Sru */ 1252114402Sru 1253114402Sruclass page { 1254114402Srupublic: 1255114402Sru page (void); 1256114402Sru void add (style *s, const string &str, 1257114402Sru int line_number, 1258114402Sru int min_vertical, int min_horizontal, 1259114402Sru int max_vertical, int max_horizontal); 1260114402Sru void add_tag (style *s, const string &str, 1261114402Sru int line_number, 1262114402Sru int min_vertical, int min_horizontal, 1263114402Sru int max_vertical, int max_horizontal); 1264114402Sru void add_and_encode (style *s, const string &str, 1265114402Sru int line_number, 1266114402Sru int min_vertical, int min_horizontal, 1267151497Sru int max_vertical, int max_horizontal, 1268151497Sru int is_tag); 1269114402Sru void add_line (style *s, 1270114402Sru int line_number, 1271114402Sru int x1, int y1, int x2, int y2, 1272114402Sru int thickness); 1273114402Sru void insert_tag (const string &str); 1274114402Sru void dump_page (void); // debugging method 1275114402Sru 1276114402Sru // and the data 1277114402Sru 1278114402Sru list glyphs; // position of glyphs and specials on page 1279114402Sru char_buffer buffer; // all characters for this page 1280114402Sru}; 1281114402Sru 1282114402Srupage::page() 1283114402Sru{ 1284114402Sru} 1285114402Sru 1286114402Sru/* 1287114402Sru * insert_tag - inserts a tag after the current position. 1288114402Sru */ 1289114402Sru 1290114402Sruvoid page::insert_tag (const string &str) 1291114402Sru{ 1292114402Sru if (str.length() > 0) { 1293114402Sru text_glob *g=new text_glob(); 1294114402Sru text_glob *f=glyphs.get_data(); 1295114402Sru g->text_glob_tag(&f->text_style, buffer.add_string(str), str.length(), 1296114402Sru f->minv, f->minh, f->maxv, f->maxh); 1297114402Sru glyphs.insert(g); 1298114402Sru } 1299114402Sru} 1300114402Sru 1301114402Sru/* 1302114402Sru * add - add html text to the list of glyphs. 1303114402Sru */ 1304114402Sru 1305114402Sruvoid page::add (style *s, const string &str, 1306114402Sru int line_number, 1307114402Sru int min_vertical, int min_horizontal, 1308114402Sru int max_vertical, int max_horizontal) 1309114402Sru{ 1310114402Sru if (str.length() > 0) { 1311114402Sru text_glob *g=new text_glob(); 1312114402Sru g->text_glob_html(s, buffer.add_string(str), str.length(), 1313114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal); 1314114402Sru glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); 1315114402Sru } 1316114402Sru} 1317114402Sru 1318114402Sru/* 1319114402Sru * add_tag - adds a troff tag, for example: .tl .sp .br 1320114402Sru */ 1321114402Sru 1322114402Sruvoid page::add_tag (style *s, const string &str, 1323114402Sru int line_number, 1324114402Sru int min_vertical, int min_horizontal, 1325114402Sru int max_vertical, int max_horizontal) 1326114402Sru{ 1327114402Sru if (str.length() > 0) { 1328114402Sru text_glob *g; 1329114402Sru 1330151497Sru if (strncmp((str+'\0').contents(), "devtag:.auto-image", 1331151497Sru strlen("devtag:.auto-image")) == 0) { 1332114402Sru g = new text_glob(); 1333114402Sru g->text_glob_auto_image(s, buffer.add_string(str), str.length(), 1334114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal); 1335114402Sru } else { 1336114402Sru g = new text_glob(); 1337114402Sru g->text_glob_tag(s, buffer.add_string(str), str.length(), 1338114402Sru min_vertical, min_horizontal, max_vertical, max_horizontal); 1339114402Sru } 1340114402Sru glyphs.add(g, line_number, min_vertical, min_horizontal, max_vertical, max_horizontal); 1341114402Sru } 1342114402Sru} 1343114402Sru 1344114402Sru/* 1345114402Sru * add_line - adds the <line> primitive providing that y1==y2 1346114402Sru */ 1347114402Sru 1348114402Sruvoid page::add_line (style *s, 1349114402Sru int line_number, 1350151497Sru int x_1, int y_1, int x_2, int y_2, 1351114402Sru int thickness) 1352114402Sru{ 1353151497Sru if (y_1 == y_2) { 1354114402Sru text_glob *g = new text_glob(); 1355114402Sru g->text_glob_line(s, 1356151497Sru min(y_1, y_2), min(x_1, x_2), 1357151497Sru max(y_1, y_2), max(x_1, x_2), 1358114402Sru thickness); 1359151497Sru glyphs.add(g, line_number, 1360151497Sru min(y_1, y_2), min(x_1, x_2), 1361151497Sru max(y_1, y_2), max(x_1, x_2)); 1362114402Sru } 1363114402Sru} 1364114402Sru 1365114402Sru/* 1366114402Sru * to_unicode - returns a unicode translation of int, ch. 1367114402Sru */ 1368114402Sru 1369114402Srustatic char *to_unicode (unsigned int ch) 1370114402Sru{ 1371114402Sru static char buf[30]; 1372114402Sru 1373114402Sru sprintf(buf, "&#%u;", ch); 1374114402Sru return buf; 1375114402Sru} 1376114402Sru 1377114402Sru/* 1378114402Sru * add_and_encode - adds a special string to the page, it translates the string 1379114402Sru * into html glyphs. The special string will have come from x X html: 1380114402Sru * and can contain troff character encodings which appear as 1381114402Sru * \(char\). A sequence of \\ represents \. 1382114402Sru * So for example we can write: 1383114402Sru * "cost = \(Po\)3.00 file = \\foo\\bar" 1384114402Sru * which is translated into: 1385114402Sru * "cost = £3.00 file = \foo\bar" 1386114402Sru */ 1387114402Sru 1388114402Sruvoid page::add_and_encode (style *s, const string &str, 1389114402Sru int line_number, 1390114402Sru int min_vertical, int min_horizontal, 1391151497Sru int max_vertical, int max_horizontal, 1392151497Sru int is_tag) 1393114402Sru{ 1394114402Sru string html_string; 1395114402Sru char *html_glyph; 1396114402Sru int i=0; 1397114402Sru 1398114402Sru if (s->f == NULL) 1399114402Sru return; 1400114402Sru while (i < str.length()) { 1401114402Sru if ((i+1<str.length()) && (str.substring(i, 2) == string("\\("))) { 1402114402Sru // start of escape 1403114402Sru i += 2; // move over \( 1404114402Sru int a = i; 1405114402Sru while ((i+1<str.length()) && (str.substring(i, 2) != string("\\)"))) { 1406114402Sru i++; 1407114402Sru } 1408114402Sru int n = i; 1409114402Sru if ((i+1<str.length()) && (str.substring(i, 2) == string("\\)"))) 1410114402Sru i++; 1411114402Sru else 1412114402Sru n = -1; 1413114402Sru if (n > 0) { 1414114402Sru string troff_charname = str.substring(a, n-a); 1415114402Sru html_glyph = get_html_translation(s->f, troff_charname); 1416114402Sru if (html_glyph) 1417114402Sru html_string += html_glyph; 1418114402Sru else { 1419151497Sru int idx=s->f->name_to_index((troff_charname + '\0').contents()); 1420114402Sru 1421151497Sru if (s->f->contains(idx) && (idx != 0)) 1422151497Sru html_string += s->f->get_code(idx); 1423114402Sru } 1424114402Sru } 1425114402Sru } else 1426114402Sru html_string += str[i]; 1427114402Sru i++; 1428114402Sru } 1429114402Sru if (html_string.length() > 0) { 1430114402Sru text_glob *g=new text_glob(); 1431151497Sru if (is_tag) 1432151497Sru g->text_glob_tag(s, buffer.add_string(html_string), 1433151497Sru html_string.length(), 1434151497Sru min_vertical, min_horizontal, 1435151497Sru max_vertical, max_horizontal); 1436151497Sru else 1437151497Sru g->text_glob_special(s, buffer.add_string(html_string), 1438151497Sru html_string.length(), 1439151497Sru min_vertical, min_horizontal, 1440151497Sru max_vertical, max_horizontal); 1441151497Sru glyphs.add(g, line_number, min_vertical, 1442151497Sru min_horizontal, max_vertical, max_horizontal); 1443114402Sru } 1444114402Sru} 1445114402Sru 1446114402Sru/* 1447114402Sru * dump_page - dump the page contents for debugging purposes. 1448114402Sru */ 1449114402Sru 1450114402Sruvoid page::dump_page(void) 1451114402Sru{ 1452114402Sru#if defined(DEBUG_TABLES) 1453114402Sru text_glob *old_pos = glyphs.get_data(); 1454114402Sru text_glob *g; 1455114402Sru 1456114402Sru printf("\n<!--\n"); 1457114402Sru printf("\n\ndebugging start\n"); 1458114402Sru glyphs.start_from_head(); 1459114402Sru do { 1460114402Sru g = glyphs.get_data(); 1461114402Sru if (g->is_tab_ts()) { 1462114402Sru printf("\n\n"); 1463114402Sru if (g->get_table() != NULL) 1464114402Sru g->get_table()->dump_table(); 1465114402Sru } 1466114402Sru printf("%s ", g->text_string); 1467114402Sru if (g->is_tab_te()) 1468114402Sru printf("\n\n"); 1469114402Sru glyphs.move_right(); 1470114402Sru } while (! glyphs.is_equal_to_head()); 1471114402Sru glyphs.move_to(old_pos); 1472114402Sru printf("\ndebugging end\n\n"); 1473114402Sru printf("\n-->\n"); 1474114402Sru fflush(stdout); 1475114402Sru#endif 1476114402Sru} 1477114402Sru 1478114402Sru/* 1479114402Sru * font classes and methods 1480114402Sru */ 1481114402Sru 1482114402Sruclass html_font : public font { 1483114402Sru html_font(const char *); 1484114402Srupublic: 1485114402Sru int encoding_index; 1486114402Sru char *encoding; 1487114402Sru char *reencoded_name; 1488114402Sru ~html_font(); 1489114402Sru static html_font *load_html_font(const char *); 1490114402Sru}; 1491114402Sru 1492114402Sruhtml_font *html_font::load_html_font(const char *s) 1493114402Sru{ 1494114402Sru html_font *f = new html_font(s); 1495114402Sru if (!f->load()) { 1496114402Sru delete f; 1497114402Sru return 0; 1498114402Sru } 1499114402Sru return f; 1500114402Sru} 1501114402Sru 1502114402Sruhtml_font::html_font(const char *nm) 1503114402Sru: font(nm) 1504114402Sru{ 1505114402Sru} 1506114402Sru 1507114402Sruhtml_font::~html_font() 1508114402Sru{ 1509114402Sru} 1510114402Sru 1511114402Sru/* 1512114402Sru * a simple class to contain the header to this document 1513114402Sru */ 1514114402Sru 1515114402Sruclass title_desc { 1516114402Srupublic: 1517114402Sru title_desc (); 1518114402Sru ~title_desc (); 1519114402Sru 1520114402Sru int has_been_written; 1521114402Sru int has_been_found; 1522114402Sru int with_h1; 1523114402Sru string text; 1524114402Sru}; 1525114402Sru 1526114402Sru 1527114402Srutitle_desc::title_desc () 1528114402Sru : has_been_written(FALSE), has_been_found(FALSE), with_h1(FALSE) 1529114402Sru{ 1530114402Sru} 1531114402Sru 1532114402Srutitle_desc::~title_desc () 1533114402Sru{ 1534114402Sru} 1535114402Sru 1536114402Sruclass header_desc { 1537114402Srupublic: 1538114402Sru header_desc (); 1539114402Sru ~header_desc (); 1540114402Sru 1541151497Sru int no_of_level_one_headings; // how many .SH or .NH 1 have we found? 1542151497Sru int no_of_headings; // how many headings have we found? 1543151497Sru char_buffer headings; // all the headings used in the document 1544151497Sru list headers; // list of headers built from .NH and .SH 1545151497Sru list header_filename; // in which file is this header? 1546151497Sru int header_level; // current header level 1547151497Sru int written_header; // have we written the header yet? 1548151497Sru string header_buffer; // current header text 1549114402Sru 1550114402Sru void write_headings (FILE *f, int force); 1551114402Sru}; 1552114402Sru 1553114402Sruheader_desc::header_desc () 1554151497Sru : no_of_level_one_headings(0), no_of_headings(0), 1555151497Sru header_level(2), written_header(0) 1556114402Sru{ 1557114402Sru} 1558114402Sru 1559114402Sruheader_desc::~header_desc () 1560114402Sru{ 1561114402Sru} 1562114402Sru 1563114402Sru/* 1564114402Sru * write_headings - emits a list of links for the headings in this document 1565114402Sru */ 1566114402Sru 1567114402Sruvoid header_desc::write_headings (FILE *f, int force) 1568114402Sru{ 1569114402Sru text_glob *g; 1570114402Sru 1571114402Sru if (auto_links || force) { 1572114402Sru if (! headers.is_empty()) { 1573114402Sru int h=1; 1574114402Sru 1575114402Sru headers.start_from_head(); 1576151497Sru header_filename.start_from_head(); 1577114402Sru do { 1578114402Sru g = headers.get_data(); 1579151497Sru fputs("<a href=\"", f); 1580151497Sru if (multiple_files && (! header_filename.is_empty())) { 1581151497Sru text_glob *fn = header_filename.get_data(); 1582151497Sru fputs(fn->text_string, f); 1583151497Sru } 1584151497Sru fputs("#", f); 1585114402Sru if (simple_anchors) { 1586114402Sru string buffer(ANCHOR_TEMPLATE); 1587114402Sru 1588114402Sru buffer += as_string(h); 1589114402Sru buffer += '\0'; 1590222083Sbenl fputs(buffer.contents(), f); 1591114402Sru } else 1592114402Sru fputs(g->text_string, f); 1593114402Sru h++; 1594114402Sru fputs("\">", f); 1595114402Sru fputs(g->text_string, f); 1596114402Sru fputs("</a><br>\n", f); 1597114402Sru headers.move_right(); 1598151497Sru if (multiple_files && (! header_filename.is_empty())) 1599151497Sru header_filename.move_right(); 1600114402Sru } while (! headers.is_equal_to_head()); 1601114402Sru fputs("\n", f); 1602114402Sru } 1603114402Sru } 1604114402Sru} 1605114402Sru 1606151497Srustruct assert_pos { 1607151497Sru assert_pos *next; 1608151497Sru const char *val; 1609151497Sru const char *id; 1610151497Sru}; 1611151497Sru 1612151497Sruclass assert_state { 1613151497Srupublic: 1614151497Sru assert_state (); 1615151497Sru ~assert_state (); 1616151497Sru 1617151497Sru void addx (const char *c, const char *i, const char *v, 1618151497Sru const char *f, const char *l); 1619151497Sru void addy (const char *c, const char *i, const char *v, 1620151497Sru const char *f, const char *l); 1621151497Sru void build(const char *c, const char *v, 1622151497Sru const char *f, const char *l); 1623151497Sru void check_br (int br); 1624151497Sru void check_ce (int ce); 1625151497Sru void check_fi (int fi); 1626151497Sru void check_sp (int sp); 1627151497Sru void reset (void); 1628151497Sru 1629151497Sruprivate: 1630151497Sru int check_br_flag; 1631151497Sru int check_ce_flag; 1632151497Sru int check_fi_flag; 1633151497Sru int check_sp_flag; 1634151497Sru const char *val_br; 1635151497Sru const char *val_ce; 1636151497Sru const char *val_fi; 1637151497Sru const char *val_sp; 1638151497Sru const char *file_br; 1639151497Sru const char *file_ce; 1640151497Sru const char *file_fi; 1641151497Sru const char *file_sp; 1642151497Sru const char *line_br; 1643151497Sru const char *line_ce; 1644151497Sru const char *line_fi; 1645151497Sru const char *line_sp; 1646151497Sru 1647151497Sru assert_pos *xhead; 1648151497Sru assert_pos *yhead; 1649151497Sru 1650151497Sru void add (assert_pos **h, 1651151497Sru const char *c, const char *i, const char *v, 1652151497Sru const char *f, const char *l); 1653151497Sru void compare(assert_pos *t, 1654151497Sru const char *v, const char *f, const char *l); 1655151497Sru void close (const char *c); 1656151497Sru void set (const char *c, const char *v, 1657151497Sru const char *f, const char *l); 1658151497Sru void check_value (const char *s, int v, const char *name, 1659151497Sru const char *f, const char *l, int *flag); 1660151497Sru int check_value_error (int c, int v, const char *s, 1661151497Sru const char *name, 1662151497Sru const char *f, const char *l, int flag); 1663151497Sru}; 1664151497Sru 1665151497Sruassert_state::assert_state () 1666151497Sru{ 1667151497Sru reset(); 1668151497Sru val_br = NULL; 1669151497Sru val_ce = NULL; 1670151497Sru val_fi = NULL; 1671151497Sru val_sp = NULL; 1672151497Sru file_br = NULL; 1673151497Sru file_ce = NULL; 1674151497Sru file_fi = NULL; 1675151497Sru file_sp = NULL; 1676151497Sru line_br = NULL; 1677151497Sru line_ce = NULL; 1678151497Sru line_fi = NULL; 1679151497Sru line_sp = NULL; 1680151497Sru xhead = NULL; 1681151497Sru yhead = NULL; 1682151497Sru} 1683151497Sru 1684151497Sruassert_state::~assert_state () 1685151497Sru{ 1686151497Sru assert_pos *t; 1687151497Sru 1688151497Sru while (xhead != NULL) { 1689151497Sru t = xhead; 1690151497Sru xhead = xhead->next; 1691151497Sru a_delete (char *)t->val; 1692151497Sru a_delete (char *)t->id; 1693151497Sru delete t; 1694151497Sru } 1695151497Sru while (yhead != NULL) { 1696151497Sru t = yhead; 1697151497Sru yhead = yhead->next; 1698151497Sru a_delete (char *)t->val; 1699151497Sru a_delete (char *)t->id; 1700151497Sru delete t; 1701151497Sru } 1702151497Sru} 1703151497Sru 1704151497Sruvoid assert_state::reset (void) 1705151497Sru{ 1706151497Sru check_br_flag = 0; 1707151497Sru check_ce_flag = 0; 1708151497Sru check_fi_flag = 0; 1709151497Sru check_sp_flag = 0; 1710151497Sru} 1711151497Sru 1712151497Sruvoid assert_state::add (assert_pos **h, 1713151497Sru const char *c, const char *i, const char *v, 1714151497Sru const char *f, const char *l) 1715151497Sru{ 1716151497Sru assert_pos *t = *h; 1717151497Sru 1718151497Sru while (t != NULL) { 1719151497Sru if (strcmp(t->id, i) == 0) 1720151497Sru break; 1721151497Sru t = t->next; 1722151497Sru } 1723151497Sru if (t != NULL && v != NULL && (v[0] != '=')) 1724151497Sru compare(t, v, f, l); 1725151497Sru else { 1726151497Sru if (t == NULL) { 1727151497Sru t = new assert_pos; 1728151497Sru t->next = *h; 1729151497Sru (*h) = t; 1730151497Sru } 1731151497Sru if (v == NULL || v[0] != '=') { 1732151497Sru if (f == NULL) 1733151497Sru f = "stdin"; 1734151497Sru if (l == NULL) 1735151497Sru l = "<none>"; 1736151497Sru if (v == NULL) 1737151497Sru v = "no value at all"; 1738151497Sru fprintf(stderr, "%s:%s:error in assert format of id=%s expecting value to be prefixed with an `=' got %s\n", 1739151497Sru f, l, i, v); 1740151497Sru } 1741151497Sru t->id = i; 1742151497Sru t->val = v; 1743151497Sru a_delete (char *)c; 1744151497Sru a_delete (char *)f; 1745151497Sru a_delete (char *)l; 1746151497Sru } 1747151497Sru} 1748151497Sru 1749151497Sruvoid assert_state::addx (const char *c, const char *i, const char *v, 1750151497Sru const char *f, const char *l) 1751151497Sru{ 1752151497Sru add(&xhead, c, i, v, f, l); 1753151497Sru} 1754151497Sru 1755151497Sruvoid assert_state::addy (const char *c, const char *i, const char *v, 1756151497Sru const char *f, const char *l) 1757151497Sru{ 1758151497Sru add(&yhead, c, i, v, f, l); 1759151497Sru} 1760151497Sru 1761151497Sruvoid assert_state::compare(assert_pos *t, 1762151497Sru const char *v, const char *f, const char *l) 1763151497Sru{ 1764151497Sru const char *s=t->val; 1765151497Sru 1766151497Sru while ((*v) == '=') 1767151497Sru v++; 1768151497Sru while ((*s) == '=') 1769151497Sru s++; 1770151497Sru 1771151497Sru if (strcmp(v, s) != 0) { 1772151497Sru if (f == NULL) 1773151497Sru f = "stdin"; 1774151497Sru if (l == NULL) 1775151497Sru l = "<none>"; 1776151497Sru fprintf(stderr, "%s:%s: grohtml assertion failed at id%s expecting %s and was given %s\n", 1777151497Sru f, l, t->id, s, v); 1778151497Sru } 1779151497Sru} 1780151497Sru 1781151497Sruvoid assert_state::close (const char *c) 1782151497Sru{ 1783151497Sru if (strcmp(c, "sp") == 0) 1784151497Sru check_sp_flag = 0; 1785151497Sru else if (strcmp(c, "br") == 0) 1786151497Sru check_br_flag = 0; 1787151497Sru else if (strcmp(c, "fi") == 0) 1788151497Sru check_fi_flag = 0; 1789151497Sru else if (strcmp(c, "nf") == 0) 1790151497Sru check_fi_flag = 0; 1791151497Sru else if (strcmp(c, "ce") == 0) 1792151497Sru check_ce_flag = 0; 1793151497Sru else 1794151497Sru fprintf(stderr, "internal error: unrecognised tag in grohtml (%s)\n", c); 1795151497Sru} 1796151497Sru 1797151497Sruconst char *replace_negate_str (const char *before, char *after) 1798151497Sru{ 1799151497Sru if (before != NULL) 1800151497Sru a_delete (char *)before; 1801151497Sru 1802151497Sru if (strlen(after) > 0) { 1803151497Sru int d = atoi(after); 1804151497Sru 1805151497Sru if (d < 0 || d > 1) { 1806151497Sru fprintf(stderr, "expecting nf/fi value to be 0 or 1 not %d\n", d); 1807151497Sru d = 0; 1808151497Sru } 1809151497Sru if (d == 0) 1810151497Sru after[0] = '1'; 1811151497Sru else 1812151497Sru after[0] = '0'; 1813151497Sru after[1] = (char)0; 1814151497Sru } 1815151497Sru return after; 1816151497Sru} 1817151497Sru 1818151497Sruconst char *replace_str (const char *before, const char *after) 1819151497Sru{ 1820151497Sru if (before != NULL) 1821151497Sru a_delete (char *)before; 1822151497Sru return after; 1823151497Sru} 1824151497Sru 1825151497Sruvoid assert_state::set (const char *c, const char *v, 1826151497Sru const char *f, const char *l) 1827151497Sru{ 1828151497Sru if (l == NULL) 1829151497Sru l = "<none>"; 1830151497Sru if (f == NULL) 1831151497Sru f = "stdin"; 1832151497Sru 1833151497Sru // fprintf(stderr, "%s:%s:setting %s to %s\n", f, l, c, v); 1834151497Sru if (strcmp(c, "sp") == 0) { 1835151497Sru check_sp_flag = 1; 1836151497Sru val_sp = replace_str(val_sp, strsave(v)); 1837151497Sru file_sp = replace_str(file_sp, strsave(f)); 1838151497Sru line_sp = replace_str(line_sp, strsave(l)); 1839151497Sru } else if (strcmp(c, "br") == 0) { 1840151497Sru check_br_flag = 1; 1841151497Sru val_br = replace_str(val_br, strsave(v)); 1842151497Sru file_br = replace_str(file_br, strsave(f)); 1843151497Sru line_br = replace_str(line_br, strsave(l)); 1844151497Sru } else if (strcmp(c, "fi") == 0) { 1845151497Sru check_fi_flag = 1; 1846151497Sru val_fi = replace_str(val_fi, strsave(v)); 1847151497Sru file_fi = replace_str(file_fi, strsave(f)); 1848151497Sru line_fi = replace_str(line_fi, strsave(l)); 1849151497Sru } else if (strcmp(c, "nf") == 0) { 1850151497Sru check_fi_flag = 1; 1851151497Sru val_fi = replace_negate_str(val_fi, strsave(v)); 1852151497Sru file_fi = replace_str(file_fi, strsave(f)); 1853151497Sru line_fi = replace_str(line_fi, strsave(l)); 1854151497Sru } else if (strcmp(c, "ce") == 0) { 1855151497Sru check_ce_flag = 1; 1856151497Sru val_ce = replace_str(val_ce, strsave(v)); 1857151497Sru file_ce = replace_str(file_ce, strsave(f)); 1858151497Sru line_ce = replace_str(line_ce, strsave(l)); 1859151497Sru } 1860151497Sru} 1861151497Sru 1862151497Sru/* 1863151497Sru * build - builds the troff state assertion. 1864151497Sru * see tmac/www.tmac for cmd examples. 1865151497Sru */ 1866151497Sru 1867151497Sruvoid assert_state::build (const char *c, const char *v, 1868151497Sru const char *f, const char *l) 1869151497Sru{ 1870151497Sru if (c[0] == '{') 1871151497Sru set(&c[1], v, f, l); 1872151497Sru if (c[0] == '}') 1873151497Sru close(&c[1]); 1874151497Sru} 1875151497Sru 1876151497Sruint assert_state::check_value_error (int c, int v, const char *s, 1877151497Sru const char *name, 1878151497Sru const char *f, const char *l, int flag) 1879151497Sru{ 1880151497Sru if (! c) { 1881151497Sru if (f == NULL) 1882151497Sru f = "stdin"; 1883151497Sru if (l == NULL) 1884151497Sru l = "<none>"; 1885151497Sru fprintf(stderr, "%s:%s:grohtml (troff state) assertion failed, expected %s to be %s but found it to contain %d\n", 1886151497Sru f, l, name, s, v); 1887151497Sru return 0; 1888151497Sru } 1889151497Sru return flag; 1890151497Sru} 1891151497Sru 1892151497Sruvoid assert_state::check_value (const char *s, int v, const char *name, 1893151497Sru const char *f, const char *l, int *flag) 1894151497Sru{ 1895151497Sru if (strncmp(s, "<=", 2) == 0) 1896151497Sru *flag = check_value_error(v <= atoi(&s[2]), v, s, name, f, l, *flag); 1897151497Sru else if (strncmp(s, ">=", 2) == 0) 1898151497Sru *flag = check_value_error(v >= atoi(&s[2]), v, s, name, f, l, *flag); 1899151497Sru else if (strncmp(s, "==", 2) == 0) 1900151497Sru *flag = check_value_error(v == atoi(&s[2]), v, s, name, f, l, *flag); 1901151497Sru else if (strncmp(s, "!=", 2) == 0) 1902151497Sru *flag = check_value_error(v != atoi(&s[2]), v, s, name, f, l, *flag); 1903151497Sru else if (strncmp(s, "<", 1) == 0) 1904151497Sru *flag = check_value_error(v < atoi(&s[2]), v, s, name, f, l, *flag); 1905151497Sru else if (strncmp(s, ">", 1) == 0) 1906151497Sru *flag = check_value_error(v > atoi(&s[2]), v, s, name, f, l, *flag); 1907151497Sru else if (strncmp(s, "=", 1) == 0) 1908151497Sru *flag = check_value_error(v == atoi(&s[1]), v, s, name, f, l, *flag); 1909151497Sru else 1910151497Sru *flag = check_value_error(v == atoi(s), v, s, name, f, l, *flag); 1911151497Sru} 1912151497Sru 1913151497Sruvoid assert_state::check_sp (int sp) 1914151497Sru{ 1915151497Sru if (check_sp_flag) 1916151497Sru check_value(val_sp, sp, "sp", file_sp, line_sp, &check_sp_flag); 1917151497Sru} 1918151497Sru 1919151497Sruvoid assert_state::check_fi (int fi) 1920151497Sru{ 1921151497Sru if (check_fi_flag) 1922151497Sru check_value(val_fi, fi, "fi", file_fi, line_fi, &check_fi_flag); 1923151497Sru} 1924151497Sru 1925151497Sruvoid assert_state::check_br (int br) 1926151497Sru{ 1927151497Sru if (check_br_flag) 1928151497Sru check_value(val_br, br, "br", file_br, line_br, &check_br_flag); 1929151497Sru} 1930151497Sru 1931151497Sruvoid assert_state::check_ce (int ce) 1932151497Sru{ 1933151497Sru if (check_ce_flag) 1934151497Sru check_value(val_ce, ce, "ce", file_ce, line_ce, &check_ce_flag); 1935151497Sru} 1936151497Sru 1937114402Sruclass html_printer : public printer { 1938114402Sru files file_list; 1939114402Sru simple_output html; 1940114402Sru int res; 1941114402Sru int space_char_index; 1942114402Sru int space_width; 1943114402Sru int no_of_printed_pages; 1944114402Sru int paper_length; 1945114402Sru string sbuf; 1946114402Sru int sbuf_start_hpos; 1947114402Sru int sbuf_vpos; 1948114402Sru int sbuf_end_hpos; 1949114402Sru int sbuf_prev_hpos; 1950114402Sru int sbuf_kern; 1951114402Sru style sbuf_style; 1952114402Sru int last_sbuf_length; 1953114402Sru int overstrike_detected; 1954114402Sru style output_style; 1955114402Sru int output_hpos; 1956114402Sru int output_vpos; 1957114402Sru int output_vpos_max; 1958114402Sru int output_draw_point_size; 1959114402Sru int line_thickness; 1960114402Sru int output_line_thickness; 1961114402Sru unsigned char output_space_code; 1962114402Sru char *inside_font_style; 1963114402Sru int page_number; 1964114402Sru title_desc title; 1965114402Sru header_desc header; 1966114402Sru int header_indent; 1967114402Sru int supress_sub_sup; 1968114402Sru int cutoff_heading; 1969114402Sru page *page_contents; 1970114402Sru html_text *current_paragraph; 1971114402Sru html_indent *indent; 1972114402Sru html_table *table; 1973114402Sru int end_center; 1974114402Sru int end_tempindent; 1975114402Sru TAG_ALIGNMENT next_tag; 1976114402Sru int fill_on; 1977114402Sru int max_linelength; 1978114402Sru int linelength; 1979114402Sru int pageoffset; 1980151497Sru int troff_indent; 1981151497Sru int device_indent; 1982151497Sru int temp_indent; 1983114402Sru int pointsize; 1984114402Sru int vertical_spacing; 1985114402Sru int line_number; 1986114402Sru color *background; 1987151497Sru int seen_indent; 1988151497Sru int next_indent; 1989151497Sru int seen_pageoffset; 1990151497Sru int next_pageoffset; 1991151497Sru int seen_linelength; 1992151497Sru int next_linelength; 1993151497Sru int seen_center; 1994151497Sru int next_center; 1995151497Sru int seen_space; 1996151497Sru int seen_break; 1997151497Sru int current_column; 1998151497Sru int row_space; 1999151497Sru assert_state as; 2000114402Sru 2001114402Sru void flush_sbuf (); 2002114402Sru void set_style (const style &); 2003114402Sru void set_space_code (unsigned char c); 2004114402Sru void do_exec (char *, const environment *); 2005114402Sru void do_import (char *, const environment *); 2006114402Sru void do_def (char *, const environment *); 2007114402Sru void do_mdef (char *, const environment *); 2008114402Sru void do_file (char *, const environment *); 2009114402Sru void set_line_thickness (const environment *); 2010114402Sru void terminate_current_font (void); 2011114402Sru void flush_font (void); 2012114402Sru void add_to_sbuf (int index, const string &s); 2013114402Sru void write_title (int in_head); 2014114402Sru int sbuf_continuation (int index, const char *name, const environment *env, int w); 2015114402Sru void flush_page (void); 2016114402Sru void troff_tag (text_glob *g); 2017114402Sru void flush_globs (void); 2018114402Sru void emit_line (text_glob *g); 2019114402Sru void emit_raw (text_glob *g); 2020114402Sru void emit_html (text_glob *g); 2021114402Sru void determine_space (text_glob *g); 2022114402Sru void start_font (const char *name); 2023114402Sru void end_font (const char *name); 2024114402Sru int is_font_courier (font *f); 2025151497Sru int is_line_start (int nf); 2026114402Sru int is_courier_until_eol (void); 2027114402Sru void start_size (int from, int to); 2028114402Sru void do_font (text_glob *g); 2029114402Sru void do_center (char *arg); 2030151497Sru void do_check_center (void); 2031114402Sru void do_break (void); 2032151497Sru void do_space (char *arg); 2033114402Sru void do_eol (void); 2034114402Sru void do_eol_ce (void); 2035114402Sru void do_title (void); 2036151497Sru void do_fill (char *arg); 2037114402Sru void do_heading (char *arg); 2038114402Sru void write_header (void); 2039114402Sru void determine_header_level (int level); 2040114402Sru void do_linelength (char *arg); 2041114402Sru void do_pageoffset (char *arg); 2042114402Sru void do_indentation (char *arg); 2043114402Sru void do_tempindent (char *arg); 2044114402Sru void do_indentedparagraph (void); 2045114402Sru void do_verticalspacing (char *arg); 2046114402Sru void do_pointsize (char *arg); 2047114402Sru void do_centered_image (void); 2048114402Sru void do_left_image (void); 2049114402Sru void do_right_image (void); 2050114402Sru void do_auto_image (text_glob *g, const char *filename); 2051114402Sru void do_links (void); 2052114402Sru void do_flush (void); 2053151497Sru void do_job_name (char *name); 2054151497Sru void do_head (char *name); 2055151497Sru void insert_split_file (void); 2056114402Sru int is_in_middle (int left, int right); 2057114402Sru void do_sup_or_sub (text_glob *g); 2058114402Sru int start_subscript (text_glob *g); 2059114402Sru int end_subscript (text_glob *g); 2060114402Sru int start_superscript (text_glob *g); 2061114402Sru int end_superscript (text_glob *g); 2062114402Sru void outstanding_eol (int n); 2063114402Sru int is_bold (font *f); 2064114402Sru font *make_bold (font *f); 2065114402Sru int overstrike (int index, const char *name, const environment *env, int w); 2066114402Sru void do_body (void); 2067114402Sru int next_horiz_pos (text_glob *g, int nf); 2068114402Sru void lookahead_for_tables (void); 2069114402Sru void insert_tab_te (void); 2070114402Sru text_glob *insert_tab_ts (text_glob *where); 2071114402Sru void insert_tab0_foreach_tab (void); 2072114402Sru void insert_tab_0 (text_glob *where); 2073114402Sru void do_indent (int in, int pageoff, int linelen); 2074114402Sru void shutdown_table (void); 2075114402Sru void do_tab_ts (text_glob *g); 2076114402Sru void do_tab_te (void); 2077114402Sru void do_col (char *s); 2078114402Sru void do_tab (char *s); 2079114402Sru void do_tab0 (void); 2080114402Sru int calc_nf (text_glob *g, int nf); 2081114402Sru void calc_po_in (text_glob *g, int nf); 2082114402Sru void remove_tabs (void); 2083114402Sru void remove_courier_tabs (void); 2084114402Sru void update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g); 2085114402Sru void add_table_end (const char *); 2086151497Sru void do_file_components (void); 2087151497Sru void write_navigation (const string &top, const string &prev, 2088151497Sru const string &next, const string ¤t); 2089151497Sru void emit_link (const string &to, const char *name); 2090151497Sru int get_troff_indent (void); 2091151497Sru void restore_troff_indent (void); 2092151497Sru void handle_assertion (int minv, int minh, int maxv, int maxh, const char *s); 2093151497Sru void handle_state_assertion (text_glob *g); 2094151497Sru void do_end_para (text_glob *g); 2095151497Sru int round_width (int x); 2096151497Sru void handle_tag_within_title (text_glob *g); 2097151497Sru void writeHeadMetaStyle (void); 2098114402Sru // ADD HERE 2099114402Sru 2100114402Srupublic: 2101114402Sru html_printer (); 2102114402Sru ~html_printer (); 2103114402Sru void set_char (int i, font *f, const environment *env, int w, const char *name); 2104114402Sru void set_numbered_char(int num, const environment *env, int *widthp); 2105151497Sru int set_char_and_width(const char *nm, const environment *env, 2106151497Sru int *widthp, font **f); 2107114402Sru void draw (int code, int *p, int np, const environment *env); 2108114402Sru void begin_page (int); 2109114402Sru void end_page (int); 2110114402Sru void special (char *arg, const environment *env, char type); 2111151497Sru void devtag (char *arg, const environment *env, char type); 2112114402Sru font *make_font (const char *); 2113114402Sru void end_of_line (); 2114114402Sru}; 2115114402Sru 2116114402Sruprinter *make_printer() 2117114402Sru{ 2118114402Sru return new html_printer; 2119114402Sru} 2120114402Sru 2121114402Srustatic void usage(FILE *stream); 2122114402Sru 2123114402Sruvoid html_printer::set_style(const style &sty) 2124114402Sru{ 2125114402Sru const char *fontname = sty.f->get_name(); 2126114402Sru if (fontname == NULL) 2127114402Sru fatal("no internalname specified for font"); 2128114402Sru 2129114402Sru#if 0 2130114402Sru change_font(fontname, (font::res/(72*font::sizescale))*sty.point_size); 2131114402Sru#endif 2132114402Sru} 2133114402Sru 2134114402Sru/* 2135114402Sru * is_bold - returns TRUE if font, f, is bold. 2136114402Sru */ 2137114402Sru 2138114402Sruint html_printer::is_bold (font *f) 2139114402Sru{ 2140114402Sru const char *fontname = f->get_name(); 2141114402Sru return (strcmp(fontname, "B") == 0) || (strcmp(fontname, "BI") == 0); 2142114402Sru} 2143114402Sru 2144114402Sru/* 2145114402Sru * make_bold - if a bold font of, f, exists then return it. 2146114402Sru */ 2147114402Sru 2148114402Srufont *html_printer::make_bold (font *f) 2149114402Sru{ 2150114402Sru const char *fontname = f->get_name(); 2151114402Sru 2152114402Sru if (strcmp(fontname, "B") == 0) 2153114402Sru return f; 2154114402Sru if (strcmp(fontname, "I") == 0) 2155114402Sru return font::load_font("BI"); 2156114402Sru if (strcmp(fontname, "BI") == 0) 2157114402Sru return f; 2158114402Sru return NULL; 2159114402Sru} 2160114402Sru 2161114402Sruvoid html_printer::end_of_line() 2162114402Sru{ 2163114402Sru flush_sbuf(); 2164114402Sru line_number++; 2165114402Sru} 2166114402Sru 2167114402Sru/* 2168114402Sru * emit_line - writes out a horizontal rule. 2169114402Sru */ 2170114402Sru 2171114402Sruvoid html_printer::emit_line (text_glob *) 2172114402Sru{ 2173114402Sru // --fixme-- needs to know the length in percentage 2174114402Sru html.put_string("<hr>"); 2175114402Sru} 2176114402Sru 2177114402Sru/* 2178151497Sru * restore_troff_indent - is called when we have temporarily shutdown 2179151497Sru * indentation (typically done when we have 2180151497Sru * centered an image). 2181151497Sru */ 2182151497Sru 2183151497Sruvoid html_printer::restore_troff_indent (void) 2184151497Sru{ 2185151497Sru troff_indent = next_indent; 2186151497Sru if (troff_indent > 0) { 2187151497Sru /* 2188151497Sru * force device indentation 2189151497Sru */ 2190151497Sru device_indent = 0; 2191151497Sru do_indent(get_troff_indent(), pageoffset, linelength); 2192151497Sru } 2193151497Sru} 2194151497Sru 2195151497Sru/* 2196114402Sru * emit_raw - writes the raw html information directly to the device. 2197114402Sru */ 2198114402Sru 2199114402Sruvoid html_printer::emit_raw (text_glob *g) 2200114402Sru{ 2201114402Sru do_font(g); 2202114402Sru if (next_tag == INLINE) { 2203114402Sru determine_space(g); 2204114402Sru current_paragraph->do_emittext(g->text_string, g->text_length); 2205114402Sru } else { 2206151497Sru int space = current_paragraph->retrieve_para_space() || seen_space; 2207151497Sru 2208114402Sru current_paragraph->done_para(); 2209151497Sru shutdown_table(); 2210114402Sru switch (next_tag) { 2211114402Sru 2212114402Sru case CENTERED: 2213151497Sru current_paragraph->do_para("align=center", space); 2214114402Sru break; 2215114402Sru case LEFT: 2216151497Sru current_paragraph->do_para(&html, "align=left", get_troff_indent(), pageoffset, linelength, space); 2217114402Sru break; 2218114402Sru case RIGHT: 2219151497Sru current_paragraph->do_para(&html, "align=right", get_troff_indent(), pageoffset, linelength, space); 2220114402Sru break; 2221114402Sru default: 2222114402Sru fatal("unknown enumeration"); 2223114402Sru } 2224114402Sru current_paragraph->do_emittext(g->text_string, g->text_length); 2225114402Sru current_paragraph->done_para(); 2226114402Sru next_tag = INLINE; 2227114402Sru supress_sub_sup = TRUE; 2228151497Sru seen_space = FALSE; 2229151497Sru restore_troff_indent(); 2230114402Sru } 2231114402Sru} 2232114402Sru 2233114402Sru/* 2234151497Sru * handle_tag_within_title - handle a limited number of tags within 2235151497Sru * the context of a table. Those tags which 2236151497Sru * set values rather than generate spaces 2237151497Sru * and paragraphs. 2238151497Sru */ 2239151497Sru 2240151497Sruvoid html_printer::handle_tag_within_title (text_glob *g) 2241151497Sru{ 2242151497Sru if (g->is_in() || g->is_ti() || g->is_po() || g->is_ce() || g->is_ll() 2243151497Sru || g->is_fi() || g->is_nf()) 2244151497Sru troff_tag(g); 2245151497Sru} 2246151497Sru 2247151497Sru/* 2248114402Sru * do_center - handle the .ce commands from troff. 2249114402Sru */ 2250114402Sru 2251114402Sruvoid html_printer::do_center (char *arg) 2252114402Sru{ 2253151497Sru next_center = atoi(arg); 2254151497Sru seen_center = TRUE; 2255114402Sru} 2256114402Sru 2257114402Sru/* 2258151497Sru * do_centered_image - set a flag such that the next devtag is 2259114402Sru * placed inside a centered paragraph. 2260114402Sru */ 2261114402Sru 2262114402Sruvoid html_printer::do_centered_image (void) 2263114402Sru{ 2264114402Sru next_tag = CENTERED; 2265114402Sru} 2266114402Sru 2267114402Sru/* 2268151497Sru * do_right_image - set a flag such that the next devtag is 2269114402Sru * placed inside a right aligned paragraph. 2270114402Sru */ 2271114402Sru 2272114402Sruvoid html_printer::do_right_image (void) 2273114402Sru{ 2274114402Sru next_tag = RIGHT; 2275114402Sru} 2276114402Sru 2277114402Sru/* 2278151497Sru * do_left_image - set a flag such that the next devtag is 2279114402Sru * placed inside a left aligned paragraph. 2280114402Sru */ 2281114402Sru 2282114402Sruvoid html_printer::do_left_image (void) 2283114402Sru{ 2284114402Sru next_tag = LEFT; 2285114402Sru} 2286114402Sru 2287114402Sru/* 2288114402Sru * exists - returns TRUE if filename exists. 2289114402Sru */ 2290114402Sru 2291114402Srustatic int exists (const char *filename) 2292114402Sru{ 2293114402Sru FILE *fp = fopen(filename, "r"); 2294114402Sru 2295114402Sru if (fp == 0) { 2296114402Sru return( FALSE ); 2297114402Sru } else { 2298114402Sru fclose(fp); 2299114402Sru return( TRUE ); 2300114402Sru } 2301114402Sru} 2302114402Sru 2303114402Sru/* 2304114402Sru * generate_img_src - returns a html image tag for the filename 2305114402Sru * providing that the image exists. 2306114402Sru */ 2307114402Sru 2308114402Srustatic string &generate_img_src (const char *filename) 2309114402Sru{ 2310114402Sru string *s = new string(""); 2311114402Sru 2312114402Sru while (filename && (filename[0] == ' ')) { 2313114402Sru filename++; 2314114402Sru } 2315114402Sru if (exists(filename)) 2316151497Sru *s += string("<img src=\"") + filename + "\" " 2317151497Sru + "alt=\"Image " + filename + "\">"; 2318114402Sru return *s; 2319114402Sru} 2320114402Sru 2321114402Sru/* 2322114402Sru * do_auto_image - tests whether the image, indicated by filename, 2323114402Sru * is present, if so then it emits an html image tag. 2324114402Sru * An image tag may be passed through from pic, eqn 2325114402Sru * but the corresponding image might not be created. 2326114402Sru * Consider .EQ delim $$ .EN or an empty .PS .PE. 2327114402Sru */ 2328114402Sru 2329114402Sruvoid html_printer::do_auto_image (text_glob *g, const char *filename) 2330114402Sru{ 2331114402Sru string buffer = generate_img_src(filename); 2332114402Sru 2333114402Sru if (! buffer.empty()) { 2334114402Sru /* 2335114402Sru * utilize emit_raw by creating a new text_glob. 2336114402Sru */ 2337114402Sru text_glob h = *g; 2338114402Sru 2339114402Sru h.text_string = buffer.contents(); 2340114402Sru h.text_length = buffer.length(); 2341114402Sru emit_raw(&h); 2342114402Sru } else 2343114402Sru next_tag = INLINE; 2344114402Sru} 2345114402Sru 2346114402Sru/* 2347114402Sru * outstanding_eol - call do_eol, n, times. 2348114402Sru */ 2349114402Sru 2350114402Sruvoid html_printer::outstanding_eol (int n) 2351114402Sru{ 2352114402Sru while (n > 0) { 2353114402Sru do_eol(); 2354114402Sru n--; 2355114402Sru } 2356114402Sru} 2357114402Sru 2358114402Sru/* 2359114402Sru * do_title - handle the .tl commands from troff. 2360114402Sru */ 2361114402Sru 2362114402Sruvoid html_printer::do_title (void) 2363114402Sru{ 2364114402Sru text_glob *t; 2365114402Sru int removed_from_head; 2366114402Sru 2367114402Sru if (page_number == 1) { 2368114402Sru int found_title_start = FALSE; 2369114402Sru if (! page_contents->glyphs.is_empty()) { 2370114402Sru page_contents->glyphs.sub_move_right(); /* move onto next word */ 2371114402Sru do { 2372114402Sru t = page_contents->glyphs.get_data(); 2373114402Sru removed_from_head = FALSE; 2374114402Sru if (t->is_auto_img()) { 2375114402Sru string img = generate_img_src((char *)(t->text_string + 20)); 2376114402Sru 2377114402Sru if (! img.empty()) { 2378114402Sru if (found_title_start) 2379114402Sru title.text += " "; 2380114402Sru found_title_start = TRUE; 2381114402Sru title.has_been_found = TRUE; 2382114402Sru title.text += img; 2383114402Sru } 2384114402Sru page_contents->glyphs.sub_move_right(); /* move onto next word */ 2385114402Sru removed_from_head = ((!page_contents->glyphs.is_empty()) && 2386114402Sru (page_contents->glyphs.is_equal_to_head())); 2387151497Sru } else if (t->is_eo_tl()) { 2388114402Sru /* end of title found 2389114402Sru */ 2390114402Sru title.has_been_found = TRUE; 2391114402Sru return; 2392114402Sru } else if (t->is_a_tag()) { 2393151497Sru handle_tag_within_title(t); 2394151497Sru page_contents->glyphs.sub_move_right(); /* move onto next word */ 2395151497Sru removed_from_head = ((!page_contents->glyphs.is_empty()) && 2396151497Sru (page_contents->glyphs.is_equal_to_head())); 2397114402Sru } else if (found_title_start) { 2398114402Sru title.text += " " + string(t->text_string, t->text_length); 2399114402Sru page_contents->glyphs.sub_move_right(); /* move onto next word */ 2400114402Sru removed_from_head = ((!page_contents->glyphs.is_empty()) && 2401114402Sru (page_contents->glyphs.is_equal_to_head())); 2402114402Sru } else { 2403114402Sru title.text += string(t->text_string, t->text_length); 2404114402Sru found_title_start = TRUE; 2405114402Sru title.has_been_found = TRUE; 2406114402Sru page_contents->glyphs.sub_move_right(); /* move onto next word */ 2407114402Sru removed_from_head = ((!page_contents->glyphs.is_empty()) && 2408114402Sru (page_contents->glyphs.is_equal_to_head())); 2409114402Sru } 2410151497Sru } while ((! page_contents->glyphs.is_equal_to_head()) || 2411151497Sru (removed_from_head)); 2412114402Sru } 2413114402Sru } 2414114402Sru} 2415114402Sru 2416114402Sruvoid html_printer::write_header (void) 2417114402Sru{ 2418114402Sru if (! header.header_buffer.empty()) { 2419151497Sru int space = current_paragraph->retrieve_para_space() || seen_space; 2420151497Sru 2421114402Sru if (header.header_level > 7) { 2422114402Sru header.header_level = 7; 2423114402Sru } 2424114402Sru 2425114402Sru // firstly we must terminate any font and type faces 2426114402Sru current_paragraph->done_para(); 2427114402Sru supress_sub_sup = TRUE; 2428114402Sru 2429114402Sru if (cutoff_heading+2 > header.header_level) { 2430114402Sru // now we save the header so we can issue a list of links 2431114402Sru header.no_of_headings++; 2432114402Sru style st; 2433114402Sru 2434114402Sru text_glob *h=new text_glob(); 2435114402Sru h->text_glob_html(&st, 2436114402Sru header.headings.add_string(header.header_buffer), 2437114402Sru header.header_buffer.length(), 2438114402Sru header.no_of_headings, header.header_level, 2439114402Sru header.no_of_headings, header.header_level); 2440114402Sru 2441114402Sru header.headers.add(h, 2442114402Sru header.no_of_headings, 2443114402Sru header.no_of_headings, header.no_of_headings, 2444114402Sru header.no_of_headings, header.no_of_headings); // and add this header to the header list 2445114402Sru 2446114402Sru // lastly we generate a tag 2447114402Sru 2448151497Sru html.nl().nl().put_string("<a name=\""); 2449114402Sru if (simple_anchors) { 2450114402Sru string buffer(ANCHOR_TEMPLATE); 2451114402Sru 2452114402Sru buffer += as_string(header.no_of_headings); 2453114402Sru buffer += '\0'; 2454114402Sru html.put_string(buffer.contents()); 2455114402Sru } else { 2456114402Sru html.put_string(header.header_buffer); 2457114402Sru } 2458114402Sru html.put_string("\"></a>").nl(); 2459114402Sru } 2460114402Sru 2461114402Sru if (manufacture_headings) { 2462114402Sru // line break before a header 2463114402Sru if (!current_paragraph->emitted_text()) 2464114402Sru current_paragraph->do_space(); 2465114402Sru // user wants manufactured headings which look better than <Hn></Hn> 2466114402Sru if (header.header_level<4) { 2467114402Sru html.put_string("<b><font size=\"+1\">"); 2468114402Sru html.put_string(header.header_buffer); 2469114402Sru html.put_string("</font></b>").nl(); 2470114402Sru } 2471114402Sru else { 2472114402Sru html.put_string("<b>"); 2473114402Sru html.put_string(header.header_buffer); 2474114402Sru html.put_string("</b>").nl(); 2475114402Sru } 2476114402Sru } 2477114402Sru else { 2478114402Sru // and now we issue the real header 2479114402Sru html.put_string("<h"); 2480114402Sru html.put_number(header.header_level); 2481114402Sru html.put_string(">"); 2482114402Sru html.put_string(header.header_buffer); 2483114402Sru html.put_string("</h"); 2484114402Sru html.put_number(header.header_level); 2485114402Sru html.put_string(">").nl(); 2486114402Sru } 2487114402Sru 2488151497Sru /* and now we save the file name in which this header will occur */ 2489151497Sru 2490151497Sru style st; // fake style to enable us to use the list data structure 2491151497Sru 2492151497Sru text_glob *h=new text_glob(); 2493151497Sru h->text_glob_html(&st, 2494151497Sru header.headings.add_string(file_list.file_name()), 2495151497Sru file_list.file_name().length(), 2496151497Sru header.no_of_headings, header.header_level, 2497151497Sru header.no_of_headings, header.header_level); 2498151497Sru 2499151497Sru header.header_filename.add(h, 2500151497Sru header.no_of_headings, 2501151497Sru header.no_of_headings, header.no_of_headings, 2502151497Sru header.no_of_headings, header.no_of_headings); 2503151497Sru 2504151497Sru current_paragraph->do_para(&html, "", get_troff_indent(), pageoffset, linelength, space); 2505114402Sru } 2506114402Sru} 2507114402Sru 2508114402Sruvoid html_printer::determine_header_level (int level) 2509114402Sru{ 2510114402Sru if (level == 0) { 2511114402Sru int i; 2512114402Sru 2513114402Sru for (i=0; ((i<header.header_buffer.length()) 2514114402Sru && ((header.header_buffer[i] == '.') 2515114402Sru || is_digit(header.header_buffer[i]))) ; i++) { 2516114402Sru if (header.header_buffer[i] == '.') { 2517114402Sru level++; 2518114402Sru } 2519114402Sru } 2520114402Sru } 2521114402Sru header.header_level = level+1; 2522151497Sru if (header.header_level >= 2 && header.header_level <= split_level) { 2523151497Sru header.no_of_level_one_headings++; 2524151497Sru insert_split_file(); 2525151497Sru } 2526114402Sru} 2527114402Sru 2528114402Sru/* 2529114402Sru * do_heading - handle the .SH and .NH and equivalent commands from troff. 2530114402Sru */ 2531114402Sru 2532114402Sruvoid html_printer::do_heading (char *arg) 2533114402Sru{ 2534114402Sru text_glob *g; 2535114402Sru int level=atoi(arg); 2536151497Sru int horiz; 2537114402Sru 2538114402Sru header.header_buffer.clear(); 2539114402Sru page_contents->glyphs.move_right(); 2540114402Sru if (! page_contents->glyphs.is_equal_to_head()) { 2541114402Sru g = page_contents->glyphs.get_data(); 2542151497Sru horiz = g->minh; 2543114402Sru do { 2544114402Sru if (g->is_auto_img()) { 2545114402Sru string img=generate_img_src((char *)(g->text_string + 20)); 2546114402Sru 2547114402Sru if (! img.empty()) { 2548114402Sru simple_anchors = TRUE; // we cannot use full heading anchors with images 2549151497Sru if (horiz < g->minh) 2550114402Sru header.header_buffer += " "; 2551114402Sru 2552114402Sru header.header_buffer += img; 2553114402Sru } 2554151497Sru } 2555151497Sru else if (g->is_in() || g->is_ti() || g->is_po() || g->is_ce() || g->is_ll()) 2556151497Sru troff_tag(g); 2557151497Sru else if (g->is_fi()) 2558151497Sru fill_on = 1; 2559151497Sru else if (g->is_nf()) 2560151497Sru fill_on = 0; 2561151497Sru else if (! (g->is_a_line() || g->is_a_tag())) { 2562114402Sru /* 2563151497Sru * we ignore the other tag commands when constructing a heading 2564114402Sru */ 2565151497Sru if (horiz < g->minh) 2566114402Sru header.header_buffer += " "; 2567114402Sru 2568151497Sru horiz = g->maxh; 2569114402Sru header.header_buffer += string(g->text_string, g->text_length); 2570114402Sru } 2571114402Sru page_contents->glyphs.move_right(); 2572114402Sru g = page_contents->glyphs.get_data(); 2573114402Sru } while ((! page_contents->glyphs.is_equal_to_head()) && 2574151497Sru (! g->is_eo_h())); 2575114402Sru } 2576114402Sru 2577114402Sru determine_header_level(level); 2578114402Sru write_header(); 2579114402Sru 2580114402Sru // finally set the output to neutral for after the header 2581114402Sru g = page_contents->glyphs.get_data(); 2582114402Sru page_contents->glyphs.move_left(); // so that next time we use old g 2583114402Sru} 2584114402Sru 2585114402Sru/* 2586114402Sru * is_courier_until_eol - returns TRUE if we can see a whole line which is courier 2587114402Sru */ 2588114402Sru 2589114402Sruint html_printer::is_courier_until_eol (void) 2590114402Sru{ 2591114402Sru text_glob *orig = page_contents->glyphs.get_data(); 2592114402Sru int result = TRUE; 2593114402Sru text_glob *g; 2594114402Sru 2595114402Sru if (! page_contents->glyphs.is_equal_to_tail()) { 2596114402Sru page_contents->glyphs.move_right(); 2597114402Sru do { 2598114402Sru g = page_contents->glyphs.get_data(); 2599114402Sru if (! g->is_a_tag() && (! is_font_courier(g->text_style.f))) 2600114402Sru result = FALSE; 2601114402Sru page_contents->glyphs.move_right(); 2602114402Sru } while (result && 2603114402Sru (! page_contents->glyphs.is_equal_to_head()) && 2604114402Sru (! g->is_fi()) && (! g->is_eol())); 2605114402Sru 2606114402Sru /* 2607114402Sru * now restore our previous position. 2608114402Sru */ 2609114402Sru while (page_contents->glyphs.get_data() != orig) 2610114402Sru page_contents->glyphs.move_left(); 2611114402Sru } 2612114402Sru return result; 2613114402Sru} 2614114402Sru 2615114402Sru/* 2616114402Sru * do_linelength - handle the .ll command from troff. 2617114402Sru */ 2618114402Sru 2619114402Sruvoid html_printer::do_linelength (char *arg) 2620114402Sru{ 2621114402Sru if (max_linelength == -1) 2622114402Sru max_linelength = atoi(arg); 2623114402Sru 2624151497Sru next_linelength = atoi(arg); 2625151497Sru seen_linelength = TRUE; 2626114402Sru} 2627114402Sru 2628114402Sru/* 2629114402Sru * do_pageoffset - handle the .po command from troff. 2630114402Sru */ 2631114402Sru 2632114402Sruvoid html_printer::do_pageoffset (char *arg) 2633114402Sru{ 2634151497Sru next_pageoffset = atoi(arg); 2635151497Sru seen_pageoffset = TRUE; 2636114402Sru} 2637114402Sru 2638114402Sru/* 2639151497Sru * get_troff_indent - returns the indent value. 2640151497Sru */ 2641151497Sru 2642151497Sruint html_printer::get_troff_indent (void) 2643151497Sru{ 2644151497Sru if (end_tempindent > 0) 2645151497Sru return temp_indent; 2646151497Sru else 2647151497Sru return troff_indent; 2648151497Sru} 2649151497Sru 2650151497Sru/* 2651114402Sru * do_indentation - handle the .in command from troff. 2652114402Sru */ 2653114402Sru 2654114402Sruvoid html_printer::do_indentation (char *arg) 2655114402Sru{ 2656151497Sru next_indent = atoi(arg); 2657151497Sru seen_indent = TRUE; 2658114402Sru} 2659114402Sru 2660114402Sru/* 2661114402Sru * do_tempindent - handle the .ti command from troff. 2662114402Sru */ 2663114402Sru 2664114402Sruvoid html_printer::do_tempindent (char *arg) 2665114402Sru{ 2666114402Sru if (fill_on) { 2667151497Sru /* 2668151497Sru * we set the end_tempindent to 2 as the first .br 2669151497Sru * activates the .ti and the second terminates it. 2670151497Sru */ 2671151497Sru end_tempindent = 2; 2672151497Sru temp_indent = atoi(arg); 2673114402Sru } 2674114402Sru} 2675114402Sru 2676114402Sru/* 2677114402Sru * shutdown_table - shuts down the current table. 2678114402Sru */ 2679114402Sru 2680114402Sruvoid html_printer::shutdown_table (void) 2681114402Sru{ 2682114402Sru if (table != NULL) { 2683114402Sru current_paragraph->done_para(); 2684114402Sru table->emit_finish_table(); 2685114402Sru // dont delete this table as it will be deleted when we destroy the text_glob 2686114402Sru table = NULL; 2687114402Sru } 2688114402Sru} 2689114402Sru 2690114402Sru/* 2691114402Sru * do_indent - remember the indent parameters and if 2692114402Sru * indent is > pageoff and indent has changed 2693114402Sru * then we start a html table to implement the indentation. 2694114402Sru */ 2695114402Sru 2696114402Sruvoid html_printer::do_indent (int in, int pageoff, int linelen) 2697114402Sru{ 2698151497Sru if ((device_indent != -1) && 2699151497Sru (pageoffset+device_indent != in+pageoff)) { 2700151497Sru 2701151497Sru int space = current_paragraph->retrieve_para_space() || seen_space; 2702114402Sru current_paragraph->done_para(); 2703114402Sru 2704151497Sru device_indent = in; 2705114402Sru pageoffset = pageoff; 2706114402Sru if (linelen <= max_linelength) 2707114402Sru linelength = linelen; 2708114402Sru 2709151497Sru current_paragraph->do_para(&html, "", device_indent, 2710151497Sru pageoffset, max_linelength, space); 2711114402Sru } 2712114402Sru} 2713114402Sru 2714114402Sru/* 2715114402Sru * do_verticalspacing - handle the .vs command from troff. 2716114402Sru */ 2717114402Sru 2718114402Sruvoid html_printer::do_verticalspacing (char *arg) 2719114402Sru{ 2720114402Sru vertical_spacing = atoi(arg); 2721114402Sru} 2722114402Sru 2723114402Sru/* 2724114402Sru * do_pointsize - handle the .ps command from troff. 2725114402Sru */ 2726114402Sru 2727114402Sruvoid html_printer::do_pointsize (char *arg) 2728114402Sru{ 2729151497Sru /* 2730151497Sru * firstly check to see whether this point size is really associated with a .tl tag 2731151497Sru */ 2732151497Sru 2733151497Sru if (! page_contents->glyphs.is_empty()) { 2734151497Sru text_glob *g = page_contents->glyphs.get_data(); 2735151497Sru text_glob *t = page_contents->glyphs.get_data(); 2736151497Sru 2737151497Sru while (t->is_a_tag() && (! page_contents->glyphs.is_equal_to_head())) { 2738151497Sru if (t->is_tl()) { 2739151497Sru /* 2740151497Sru * found title therefore ignore this .ps tag 2741151497Sru */ 2742151497Sru while (t != g) { 2743151497Sru page_contents->glyphs.move_left(); 2744151497Sru t = page_contents->glyphs.get_data(); 2745151497Sru } 2746151497Sru return; 2747151497Sru } 2748151497Sru page_contents->glyphs.move_right(); 2749151497Sru t = page_contents->glyphs.get_data(); 2750151497Sru } 2751151497Sru /* 2752151497Sru * move back to original position 2753151497Sru */ 2754151497Sru while (t != g) { 2755151497Sru page_contents->glyphs.move_left(); 2756151497Sru t = page_contents->glyphs.get_data(); 2757151497Sru } 2758151497Sru /* 2759151497Sru * collect legal pointsize 2760151497Sru */ 2761151497Sru pointsize = atoi(arg); 2762151497Sru } 2763114402Sru} 2764114402Sru 2765114402Sru/* 2766114402Sru * do_fill - records whether troff has requested that text be filled. 2767114402Sru */ 2768114402Sru 2769151497Sruvoid html_printer::do_fill (char *arg) 2770114402Sru{ 2771151497Sru int on = atoi(arg); 2772151497Sru 2773151497Sru output_hpos = get_troff_indent()+pageoffset; 2774114402Sru supress_sub_sup = TRUE; 2775114402Sru 2776114402Sru if (fill_on != on) { 2777114402Sru if (on) 2778151497Sru current_paragraph->do_para("", seen_space); 2779114402Sru fill_on = on; 2780114402Sru } 2781114402Sru} 2782114402Sru 2783114402Sru/* 2784114402Sru * do_eol - handle the end of line 2785114402Sru */ 2786114402Sru 2787114402Sruvoid html_printer::do_eol (void) 2788114402Sru{ 2789114402Sru if (! fill_on) { 2790114402Sru if (current_paragraph->ever_emitted_text()) { 2791114402Sru current_paragraph->do_newline(); 2792114402Sru current_paragraph->do_break(); 2793114402Sru } 2794114402Sru } 2795151497Sru output_hpos = get_troff_indent()+pageoffset; 2796114402Sru} 2797114402Sru 2798114402Sru/* 2799151497Sru * do_check_center - checks to see whether we have seen a `.ce' tag 2800151497Sru * during the previous line. 2801151497Sru */ 2802151497Sru 2803151497Sruvoid html_printer::do_check_center(void) 2804151497Sru{ 2805151497Sru if (seen_center) { 2806151497Sru seen_center = FALSE; 2807151497Sru if (next_center > 0) { 2808151497Sru if (end_center == 0) { 2809151497Sru int space = current_paragraph->retrieve_para_space() || seen_space; 2810151497Sru current_paragraph->done_para(); 2811151497Sru supress_sub_sup = TRUE; 2812151497Sru current_paragraph->do_para("align=center", space); 2813151497Sru } else 2814151497Sru if (strcmp("align=center", 2815151497Sru current_paragraph->get_alignment()) != 0) { 2816151497Sru /* 2817151497Sru * different alignment, so shutdown paragraph and open 2818151497Sru * a new one. 2819151497Sru */ 2820151497Sru int space = current_paragraph->retrieve_para_space() || seen_space; 2821151497Sru current_paragraph->done_para(); 2822151497Sru supress_sub_sup = TRUE; 2823151497Sru current_paragraph->do_para("align=center", space); 2824151497Sru } else 2825151497Sru /* 2826151497Sru * same alignment, if we have emitted text then issue a break. 2827151497Sru */ 2828151497Sru if (current_paragraph->emitted_text()) 2829151497Sru current_paragraph->do_break(); 2830151497Sru } else 2831151497Sru /* 2832151497Sru * next_center == 0 2833151497Sru */ 2834151497Sru if (end_center > 0) { 2835151497Sru seen_space = seen_space || current_paragraph->retrieve_para_space(); 2836151497Sru current_paragraph->done_para(); 2837151497Sru supress_sub_sup = TRUE; 2838151497Sru current_paragraph->do_para("", seen_space); 2839151497Sru } 2840151497Sru end_center = next_center; 2841151497Sru } 2842151497Sru} 2843151497Sru 2844151497Sru/* 2845114402Sru * do_eol_ce - handle end of line specifically for a .ce 2846114402Sru */ 2847114402Sru 2848114402Sruvoid html_printer::do_eol_ce (void) 2849114402Sru{ 2850114402Sru if (end_center > 0) { 2851114402Sru if (end_center > 1) 2852114402Sru if (current_paragraph->emitted_text()) 2853114402Sru current_paragraph->do_break(); 2854114402Sru 2855114402Sru end_center--; 2856114402Sru if (end_center == 0) { 2857114402Sru current_paragraph->done_para(); 2858114402Sru supress_sub_sup = TRUE; 2859114402Sru } 2860114402Sru } 2861114402Sru} 2862114402Sru 2863114402Sru/* 2864114402Sru * do_flush - flushes all output and tags. 2865114402Sru */ 2866114402Sru 2867114402Sruvoid html_printer::do_flush (void) 2868114402Sru{ 2869114402Sru current_paragraph->done_para(); 2870114402Sru} 2871114402Sru 2872114402Sru/* 2873114402Sru * do_links - moves onto a new temporary file and sets auto_links to FALSE. 2874114402Sru */ 2875114402Sru 2876114402Sruvoid html_printer::do_links (void) 2877114402Sru{ 2878151497Sru html.end_line(); // flush line 2879114402Sru auto_links = FALSE; /* from now on only emit under user request */ 2880114402Sru file_list.add_new_file(xtmpfile()); 2881151497Sru file_list.set_links_required(); 2882114402Sru html.set_file(file_list.get_file()); 2883114402Sru} 2884114402Sru 2885114402Sru/* 2886151497Sru * insert_split_file - 2887151497Sru */ 2888151497Sru 2889151497Sruvoid html_printer::insert_split_file (void) 2890151497Sru{ 2891151497Sru if (multiple_files) { 2892151497Sru current_paragraph->done_para(); // flush paragraph 2893151497Sru html.end_line(); // flush line 2894151497Sru html.set_file(file_list.get_file()); // flush current file 2895151497Sru file_list.add_new_file(xtmpfile()); 2896151497Sru string split_file = job_name; 2897151497Sru 2898151497Sru split_file += string("-"); 2899151497Sru split_file += as_string(header.no_of_level_one_headings); 2900151497Sru split_file += string(".html"); 2901151497Sru split_file += '\0'; 2902151497Sru 2903151497Sru file_list.set_file_name(split_file); 2904151497Sru html.set_file(file_list.get_file()); 2905151497Sru } 2906151497Sru} 2907151497Sru 2908151497Sru/* 2909151497Sru * do_job_name - assigns the job_name to name. 2910151497Sru */ 2911151497Sru 2912151497Sruvoid html_printer::do_job_name (char *name) 2913151497Sru{ 2914151497Sru if (! multiple_files) { 2915151497Sru multiple_files = TRUE; 2916151497Sru while (name != NULL && (*name != (char)0) && (*name == ' ')) 2917151497Sru name++; 2918151497Sru job_name = name; 2919151497Sru } 2920151497Sru} 2921151497Sru 2922151497Sru/* 2923151497Sru * do_head - adds a string to head_info which is to be included into 2924151497Sru * the <head> </head> section of the html document. 2925151497Sru */ 2926151497Sru 2927151497Sruvoid html_printer::do_head (char *name) 2928151497Sru{ 2929151497Sru head_info += string(name); 2930151497Sru head_info += '\n'; 2931151497Sru} 2932151497Sru 2933151497Sru/* 2934114402Sru * do_break - handles the ".br" request and also 2935151497Sru * undoes an outstanding ".ti" command 2936151497Sru * and calls indent if the indentation 2937151497Sru * related registers have changed. 2938114402Sru */ 2939114402Sru 2940114402Sruvoid html_printer::do_break (void) 2941114402Sru{ 2942151497Sru int seen_temp_indent = FALSE; 2943151497Sru 2944114402Sru current_paragraph->do_break(); 2945114402Sru if (end_tempindent > 0) { 2946114402Sru end_tempindent--; 2947151497Sru if (end_tempindent > 0) 2948151497Sru seen_temp_indent = TRUE; 2949114402Sru } 2950151497Sru if (seen_indent || seen_pageoffset || seen_linelength || seen_temp_indent) { 2951151497Sru if (seen_indent && (! seen_temp_indent)) 2952151497Sru troff_indent = next_indent; 2953151497Sru if (! seen_pageoffset) 2954151497Sru next_pageoffset = pageoffset; 2955151497Sru if (! seen_linelength) 2956151497Sru next_linelength = linelength; 2957151497Sru do_indent(get_troff_indent(), next_pageoffset, next_linelength); 2958151497Sru } 2959151497Sru seen_indent = seen_temp_indent; 2960151497Sru seen_linelength = FALSE; 2961151497Sru seen_pageoffset = FALSE; 2962151497Sru do_check_center(); 2963151497Sru output_hpos = get_troff_indent()+pageoffset; 2964114402Sru supress_sub_sup = TRUE; 2965114402Sru} 2966114402Sru 2967151497Sruvoid html_printer::do_space (char *arg) 2968151497Sru{ 2969151497Sru int n = atoi(arg); 2970151497Sru 2971151497Sru seen_space = atoi(arg); 2972151497Sru as.check_sp(seen_space); 2973151497Sru#if 0 2974151497Sru if (n>0 && table) 2975151497Sru table->set_space(TRUE); 2976151497Sru#endif 2977151497Sru 2978151497Sru while (n>0) { 2979151497Sru current_paragraph->do_space(); 2980151497Sru n--; 2981151497Sru } 2982151497Sru supress_sub_sup = TRUE; 2983151497Sru} 2984151497Sru 2985114402Sru/* 2986114402Sru * do_tab_ts - start a table, which will have already been defined. 2987114402Sru */ 2988114402Sru 2989114402Sruvoid html_printer::do_tab_ts (text_glob *g) 2990114402Sru{ 2991114402Sru html_table *t = g->get_table(); 2992114402Sru 2993114402Sru if (t != NULL) { 2994151497Sru current_column = 0; 2995114402Sru current_paragraph->done_pre(); 2996114402Sru current_paragraph->done_para(); 2997151497Sru current_paragraph->remove_para_space(); 2998114402Sru 2999151497Sru#if defined(DEBUG_TABLES) 3000114402Sru html.simple_comment("TABS"); 3001151497Sru#endif 3002114402Sru 3003114402Sru t->set_linelength(max_linelength); 3004114402Sru t->add_indent(pageoffset); 3005151497Sru#if 0 3006151497Sru t->emit_table_header(seen_space); 3007151497Sru#else 3008114402Sru t->emit_table_header(FALSE); 3009151497Sru row_space = current_paragraph->retrieve_para_space() || seen_space; 3010151497Sru seen_space = FALSE; 3011151497Sru#endif 3012114402Sru } 3013114402Sru 3014114402Sru table = t; 3015114402Sru} 3016114402Sru 3017114402Sru/* 3018114402Sru * do_tab_te - finish a table. 3019114402Sru */ 3020114402Sru 3021114402Sruvoid html_printer::do_tab_te (void) 3022114402Sru{ 3023114402Sru if (table) { 3024114402Sru current_paragraph->done_para(); 3025151497Sru current_paragraph->remove_para_space(); 3026114402Sru table->emit_finish_table(); 3027114402Sru } 3028114402Sru 3029114402Sru table = NULL; 3030151497Sru restore_troff_indent(); 3031114402Sru} 3032114402Sru 3033114402Sru/* 3034151497Sru * do_tab - handle the "devtag:tab" tag 3035114402Sru */ 3036114402Sru 3037114402Sruvoid html_printer::do_tab (char *s) 3038114402Sru{ 3039114402Sru if (table) { 3040114402Sru while (isspace(*s)) 3041114402Sru s++; 3042114402Sru s++; 3043151497Sru int col = table->find_column(atoi(s) + pageoffset + get_troff_indent()); 3044114402Sru if (col > 0) { 3045114402Sru current_paragraph->done_para(); 3046114402Sru table->emit_col(col); 3047114402Sru } 3048114402Sru } 3049114402Sru} 3050114402Sru 3051114402Sru/* 3052151497Sru * do_tab0 - handle the "devtag:tab0" tag 3053114402Sru */ 3054114402Sru 3055114402Sruvoid html_printer::do_tab0 (void) 3056114402Sru{ 3057114402Sru if (table) { 3058151497Sru int col = table->find_column(pageoffset+get_troff_indent()); 3059114402Sru if (col > 0) { 3060114402Sru current_paragraph->done_para(); 3061114402Sru table->emit_col(col); 3062114402Sru } 3063114402Sru } 3064114402Sru} 3065114402Sru 3066114402Sru/* 3067114402Sru * do_col - start column, s. 3068114402Sru */ 3069114402Sru 3070114402Sruvoid html_printer::do_col (char *s) 3071114402Sru{ 3072114402Sru if (table) { 3073151497Sru if (atoi(s) < current_column) 3074151497Sru row_space = seen_space; 3075151497Sru 3076151497Sru current_column = atoi(s); 3077114402Sru current_paragraph->done_para(); 3078151497Sru table->emit_col(current_column); 3079151497Sru current_paragraph->do_para("", row_space); 3080114402Sru } 3081114402Sru} 3082114402Sru 3083114402Sru/* 3084151497Sru * troff_tag - processes the troff tag and manipulates the troff 3085151497Sru * state machine. 3086114402Sru */ 3087114402Sru 3088114402Sruvoid html_printer::troff_tag (text_glob *g) 3089114402Sru{ 3090114402Sru /* 3091151497Sru * firstly skip over devtag: 3092114402Sru */ 3093151497Sru char *t=(char *)g->text_string+strlen("devtag:"); 3094114402Sru 3095151497Sru if (strncmp(g->text_string, "html</p>:", strlen("html</p>:")) == 0) { 3096151497Sru do_end_para(g); 3097151497Sru } else if (g->is_eol()) { 3098114402Sru do_eol(); 3099114402Sru } else if (g->is_eol_ce()) { 3100114402Sru do_eol_ce(); 3101114402Sru } else if (strncmp(t, ".sp", 3) == 0) { 3102151497Sru char *a = (char *)t+3; 3103151497Sru do_space(a); 3104114402Sru } else if (strncmp(t, ".br", 3) == 0) { 3105151497Sru seen_break = 1; 3106151497Sru as.check_br(1); 3107114402Sru do_break(); 3108114402Sru } else if (strcmp(t, ".centered-image") == 0) { 3109114402Sru do_centered_image(); 3110114402Sru } else if (strcmp(t, ".right-image") == 0) { 3111114402Sru do_right_image(); 3112114402Sru } else if (strcmp(t, ".left-image") == 0) { 3113114402Sru do_left_image(); 3114114402Sru } else if (strncmp(t, ".auto-image", 11) == 0) { 3115114402Sru char *a = (char *)t+11; 3116114402Sru do_auto_image(g, a); 3117114402Sru } else if (strncmp(t, ".ce", 3) == 0) { 3118114402Sru char *a = (char *)t+3; 3119114402Sru supress_sub_sup = TRUE; 3120114402Sru do_center(a); 3121151497Sru } else if (g->is_tl()) { 3122114402Sru supress_sub_sup = TRUE; 3123114402Sru title.with_h1 = TRUE; 3124114402Sru do_title(); 3125114402Sru } else if (strncmp(t, ".html-tl", 8) == 0) { 3126114402Sru supress_sub_sup = TRUE; 3127114402Sru title.with_h1 = FALSE; 3128114402Sru do_title(); 3129114402Sru } else if (strncmp(t, ".fi", 3) == 0) { 3130151497Sru char *a = (char *)t+3; 3131151497Sru do_fill(a); 3132114402Sru } else if ((strncmp(t, ".SH", 3) == 0) || (strncmp(t, ".NH", 3) == 0)) { 3133114402Sru char *a = (char *)t+3; 3134114402Sru do_heading(a); 3135114402Sru } else if (strncmp(t, ".ll", 3) == 0) { 3136114402Sru char *a = (char *)t+3; 3137114402Sru do_linelength(a); 3138114402Sru } else if (strncmp(t, ".po", 3) == 0) { 3139114402Sru char *a = (char *)t+3; 3140114402Sru do_pageoffset(a); 3141114402Sru } else if (strncmp(t, ".in", 3) == 0) { 3142114402Sru char *a = (char *)t+3; 3143114402Sru do_indentation(a); 3144114402Sru } else if (strncmp(t, ".ti", 3) == 0) { 3145114402Sru char *a = (char *)t+3; 3146114402Sru do_tempindent(a); 3147114402Sru } else if (strncmp(t, ".vs", 3) == 0) { 3148114402Sru char *a = (char *)t+3; 3149114402Sru do_verticalspacing(a); 3150114402Sru } else if (strncmp(t, ".ps", 3) == 0) { 3151114402Sru char *a = (char *)t+3; 3152114402Sru do_pointsize(a); 3153114402Sru } else if (strcmp(t, ".links") == 0) { 3154114402Sru do_links(); 3155151497Sru } else if (strncmp(t, ".job-name", 9) == 0) { 3156151497Sru char *a = (char *)t+9; 3157151497Sru do_job_name(a); 3158151497Sru } else if (strncmp(t, ".head", 5) == 0) { 3159151497Sru char *a = (char *)t+5; 3160151497Sru do_head(a); 3161114402Sru } else if (strcmp(t, ".no-auto-rule") == 0) { 3162114402Sru auto_rule = FALSE; 3163114402Sru } else if (strcmp(t, ".tab-ts") == 0) { 3164114402Sru do_tab_ts(g); 3165114402Sru } else if (strcmp(t, ".tab-te") == 0) { 3166114402Sru do_tab_te(); 3167114402Sru } else if (strncmp(t, ".col ", 5) == 0) { 3168114402Sru char *a = (char *)t+4; 3169114402Sru do_col(a); 3170114402Sru } else if (strncmp(t, "tab ", 4) == 0) { 3171114402Sru char *a = (char *)t+3; 3172114402Sru do_tab(a); 3173114402Sru } else if (strncmp(t, "tab0", 4) == 0) { 3174114402Sru do_tab0(); 3175114402Sru } 3176114402Sru} 3177114402Sru 3178114402Sru/* 3179114402Sru * is_in_middle - returns TRUE if the positions left..right are in the center of the page. 3180114402Sru */ 3181114402Sru 3182114402Sruint html_printer::is_in_middle (int left, int right) 3183114402Sru{ 3184151497Sru return( abs(abs(left-pageoffset) - abs(pageoffset+linelength-right)) 3185151497Sru <= CENTER_TOLERANCE ); 3186114402Sru} 3187114402Sru 3188114402Sru/* 3189114402Sru * flush_globs - runs through the text glob list and emits html. 3190114402Sru */ 3191114402Sru 3192114402Sruvoid html_printer::flush_globs (void) 3193114402Sru{ 3194114402Sru text_glob *g; 3195114402Sru 3196114402Sru if (! page_contents->glyphs.is_empty()) { 3197114402Sru page_contents->glyphs.start_from_head(); 3198114402Sru do { 3199114402Sru g = page_contents->glyphs.get_data(); 3200151497Sru#if 0 3201151497Sru fprintf(stderr, "[%s:%d:%d:%d:%d]", 3202151497Sru g->text_string, g->minv, g->minh, g->maxv, g->maxh) ; 3203151497Sru fflush(stderr); 3204151497Sru#endif 3205114402Sru 3206151497Sru handle_state_assertion(g); 3207151497Sru 3208114402Sru if (strcmp(g->text_string, "XXXXXXX") == 0) 3209114402Sru stop(); 3210114402Sru 3211151497Sru if (g->is_a_tag()) 3212114402Sru troff_tag(g); 3213151497Sru else if (g->is_a_line()) 3214114402Sru emit_line(g); 3215151497Sru else { 3216151497Sru as.check_sp(seen_space); 3217151497Sru as.check_br(seen_break); 3218151497Sru seen_break = 0; 3219151497Sru seen_space = 0; 3220114402Sru emit_html(g); 3221114402Sru } 3222151497Sru 3223151497Sru as.check_fi(fill_on); 3224151497Sru as.check_ce(end_center); 3225114402Sru /* 3226114402Sru * after processing the title (and removing it) the glyph list might be empty 3227114402Sru */ 3228114402Sru if (! page_contents->glyphs.is_empty()) { 3229114402Sru page_contents->glyphs.move_right(); 3230114402Sru } 3231114402Sru } while (! page_contents->glyphs.is_equal_to_head()); 3232114402Sru } 3233114402Sru} 3234114402Sru 3235114402Sru/* 3236114402Sru * calc_nf - calculates the _no_ format flag, given the 3237114402Sru * text glob, g. 3238114402Sru */ 3239114402Sru 3240114402Sruint html_printer::calc_nf (text_glob *g, int nf) 3241114402Sru{ 3242114402Sru if (g != NULL) { 3243151497Sru if (g->is_fi()) { 3244151497Sru as.check_fi(TRUE); 3245114402Sru return FALSE; 3246151497Sru } 3247151497Sru if (g->is_nf()) { 3248151497Sru as.check_fi(FALSE); 3249114402Sru return TRUE; 3250151497Sru } 3251114402Sru } 3252151497Sru as.check_fi(! nf); 3253114402Sru return nf; 3254114402Sru} 3255114402Sru 3256114402Sru/* 3257114402Sru * calc_po_in - calculates the, in, po, registers 3258114402Sru */ 3259114402Sru 3260114402Sruvoid html_printer::calc_po_in (text_glob *g, int nf) 3261114402Sru{ 3262114402Sru if (g->is_in()) 3263151497Sru troff_indent = g->get_arg(); 3264114402Sru else if (g->is_po()) 3265114402Sru pageoffset = g->get_arg(); 3266114402Sru else if (g->is_ti()) { 3267151497Sru temp_indent = g->get_arg(); 3268151497Sru end_tempindent = 2; 3269151497Sru } else if (g->is_br() || (nf && g->is_eol())) { 3270151497Sru if (end_tempindent > 0) 3271151497Sru end_tempindent--; 3272114402Sru } 3273114402Sru} 3274114402Sru 3275114402Sru/* 3276114402Sru * next_horiz_pos - returns the next horiz position. 3277114402Sru * -1 is returned if it doesn't exist. 3278114402Sru */ 3279114402Sru 3280114402Sruint html_printer::next_horiz_pos (text_glob *g, int nf) 3281114402Sru{ 3282151497Sru int next = -1; 3283114402Sru 3284114402Sru if ((g != NULL) && (g->is_br() || (nf && g->is_eol()))) 3285114402Sru if (! page_contents->glyphs.is_empty()) { 3286114402Sru page_contents->glyphs.move_right_get_data(); 3287151497Sru if (g == NULL) { 3288114402Sru page_contents->glyphs.start_from_head(); 3289151497Sru as.reset(); 3290151497Sru } 3291114402Sru else { 3292114402Sru next = g->minh; 3293114402Sru page_contents->glyphs.move_left(); 3294114402Sru } 3295114402Sru } 3296114402Sru return next; 3297114402Sru} 3298114402Sru 3299114402Sru/* 3300114402Sru * insert_tab_ts - inserts a tab-ts before, where. 3301114402Sru */ 3302114402Sru 3303114402Srutext_glob *html_printer::insert_tab_ts (text_glob *where) 3304114402Sru{ 3305114402Sru text_glob *start_of_table; 3306114402Sru text_glob *old_pos = page_contents->glyphs.get_data(); 3307114402Sru 3308114402Sru page_contents->glyphs.move_to(where); 3309114402Sru page_contents->glyphs.move_left(); 3310151497Sru page_contents->insert_tag(string("devtag:.tab-ts")); // tab table start 3311114402Sru page_contents->glyphs.move_right(); 3312114402Sru start_of_table = page_contents->glyphs.get_data(); 3313114402Sru page_contents->glyphs.move_to(old_pos); 3314114402Sru return start_of_table; 3315114402Sru} 3316114402Sru 3317114402Sru/* 3318114402Sru * insert_tab_te - inserts a tab-te before the current position 3319114402Sru * (it skips backwards over .sp/.br) 3320114402Sru */ 3321114402Sru 3322114402Sruvoid html_printer::insert_tab_te (void) 3323114402Sru{ 3324114402Sru text_glob *g = page_contents->glyphs.get_data(); 3325114402Sru page_contents->dump_page(); 3326114402Sru 3327114402Sru while (page_contents->glyphs.get_data()->is_a_tag()) 3328114402Sru page_contents->glyphs.move_left(); 3329114402Sru 3330151497Sru page_contents->insert_tag(string("devtag:.tab-te")); // tab table end 3331114402Sru while (g != page_contents->glyphs.get_data()) 3332114402Sru page_contents->glyphs.move_right(); 3333114402Sru page_contents->dump_page(); 3334114402Sru} 3335114402Sru 3336114402Sru/* 3337114402Sru * insert_tab_0 - inserts a tab0 before, where. 3338114402Sru */ 3339114402Sru 3340114402Sruvoid html_printer::insert_tab_0 (text_glob *where) 3341114402Sru{ 3342114402Sru text_glob *old_pos = page_contents->glyphs.get_data(); 3343114402Sru 3344114402Sru page_contents->glyphs.move_to(where); 3345114402Sru page_contents->glyphs.move_left(); 3346151497Sru page_contents->insert_tag(string("devtag:tab0")); // tab0 start of line 3347114402Sru page_contents->glyphs.move_right(); 3348114402Sru page_contents->glyphs.move_to(old_pos); 3349114402Sru} 3350114402Sru 3351114402Sru/* 3352114402Sru * remove_tabs - removes the tabs tags on this line. 3353114402Sru */ 3354114402Sru 3355114402Sruvoid html_printer::remove_tabs (void) 3356114402Sru{ 3357114402Sru text_glob *orig = page_contents->glyphs.get_data(); 3358114402Sru text_glob *g; 3359114402Sru 3360114402Sru if (! page_contents->glyphs.is_equal_to_tail()) { 3361114402Sru do { 3362114402Sru g = page_contents->glyphs.get_data(); 3363114402Sru if (g->is_tab()) { 3364114402Sru page_contents->glyphs.sub_move_right(); 3365114402Sru if (g == orig) 3366114402Sru orig = page_contents->glyphs.get_data(); 3367114402Sru } else 3368114402Sru page_contents->glyphs.move_right(); 3369114402Sru } while ((! page_contents->glyphs.is_equal_to_head()) && 3370114402Sru (! g->is_eol())); 3371114402Sru 3372114402Sru /* 3373114402Sru * now restore our previous position. 3374114402Sru */ 3375114402Sru while (page_contents->glyphs.get_data() != orig) 3376114402Sru page_contents->glyphs.move_left(); 3377114402Sru } 3378114402Sru} 3379114402Sru 3380114402Sruvoid html_printer::remove_courier_tabs (void) 3381114402Sru{ 3382114402Sru text_glob *g; 3383114402Sru int line_start = TRUE; 3384114402Sru int nf = FALSE; 3385114402Sru 3386114402Sru if (! page_contents->glyphs.is_empty()) { 3387114402Sru page_contents->glyphs.start_from_head(); 3388151497Sru as.reset(); 3389114402Sru line_start = TRUE; 3390114402Sru do { 3391114402Sru g = page_contents->glyphs.get_data(); 3392151497Sru handle_state_assertion(g); 3393114402Sru nf = calc_nf(g, nf); 3394114402Sru 3395114402Sru if (line_start) { 3396114402Sru if (line_start && nf && is_courier_until_eol()) { 3397114402Sru remove_tabs(); 3398114402Sru g = page_contents->glyphs.get_data(); 3399114402Sru } 3400114402Sru } 3401114402Sru 3402151497Sru // line_start = g->is_br() || g->is_nf() || g->is_fi() || (nf && g->is_eol()); 3403151497Sru line_start = g->is_br() || (nf && g->is_eol()); 3404114402Sru page_contents->glyphs.move_right(); 3405114402Sru } while (! page_contents->glyphs.is_equal_to_head()); 3406114402Sru } 3407114402Sru} 3408114402Sru 3409114402Sruvoid html_printer::insert_tab0_foreach_tab (void) 3410114402Sru{ 3411114402Sru text_glob *start_of_line = NULL; 3412114402Sru text_glob *g = NULL; 3413114402Sru int seen_tab = FALSE; 3414114402Sru int seen_col = FALSE; 3415114402Sru int nf = FALSE; 3416114402Sru 3417114402Sru if (! page_contents->glyphs.is_empty()) { 3418114402Sru page_contents->glyphs.start_from_head(); 3419151497Sru as.reset(); 3420114402Sru start_of_line = page_contents->glyphs.get_data(); 3421114402Sru do { 3422114402Sru g = page_contents->glyphs.get_data(); 3423151497Sru handle_state_assertion(g); 3424114402Sru nf = calc_nf(g, nf); 3425114402Sru 3426114402Sru if (g->is_tab()) 3427114402Sru seen_tab = TRUE; 3428114402Sru 3429114402Sru if (g->is_col()) 3430114402Sru seen_col = TRUE; 3431114402Sru 3432114402Sru if (g->is_br() || (nf && g->is_eol())) { 3433114402Sru do { 3434114402Sru page_contents->glyphs.move_right(); 3435114402Sru g = page_contents->glyphs.get_data(); 3436151497Sru handle_state_assertion(g); 3437114402Sru nf = calc_nf(g, nf); 3438114402Sru if (page_contents->glyphs.is_equal_to_head()) { 3439114402Sru if (seen_tab && !seen_col) 3440114402Sru insert_tab_0(start_of_line); 3441114402Sru return; 3442114402Sru } 3443114402Sru } while (g->is_br() || (nf && g->is_eol()) || g->is_ta()); 3444114402Sru // printf("\nstart_of_line is: %s\n", g->text_string); 3445114402Sru if (seen_tab && !seen_col) { 3446114402Sru insert_tab_0(start_of_line); 3447114402Sru page_contents->glyphs.move_to(g); 3448114402Sru } 3449114402Sru 3450114402Sru seen_tab = FALSE; 3451114402Sru seen_col = FALSE; 3452114402Sru start_of_line = g; 3453114402Sru } 3454114402Sru page_contents->glyphs.move_right(); 3455114402Sru } while (! page_contents->glyphs.is_equal_to_head()); 3456114402Sru if (seen_tab && !seen_col) 3457114402Sru insert_tab_0(start_of_line); 3458114402Sru 3459114402Sru } 3460114402Sru} 3461114402Sru 3462114402Sru/* 3463114402Sru * update_min_max - updates the extent of a column, given the left and right 3464114402Sru * extents of a glyph, g. 3465114402Sru */ 3466114402Sru 3467114402Sruvoid html_printer::update_min_max (colType type_of_col, int *minimum, int *maximum, text_glob *g) 3468114402Sru{ 3469114402Sru switch (type_of_col) { 3470114402Sru 3471114402Sru case tab_tag: 3472114402Sru break; 3473114402Sru case tab0_tag: 3474114402Sru *minimum = g->minh; 3475114402Sru break; 3476114402Sru case col_tag: 3477114402Sru *minimum = g->minh; 3478114402Sru *maximum = g->maxh; 3479114402Sru break; 3480114402Sru default: 3481114402Sru break; 3482114402Sru } 3483114402Sru} 3484114402Sru 3485114402Sru/* 3486114402Sru * add_table_end - moves left one glyph, adds a table end tag and adds a 3487114402Sru * debugging string. 3488114402Sru */ 3489114402Sru 3490114402Sruvoid html_printer::add_table_end (const char * 3491114402Sru#if defined(DEBUG_TABLES) 3492114402Sru debug_string 3493114402Sru#endif 3494114402Sru) 3495114402Sru{ 3496114402Sru page_contents->glyphs.move_left(); 3497114402Sru insert_tab_te(); 3498114402Sru#if defined(DEBUG_TABLES) 3499114402Sru page_contents->insert_tag(string(debug_string)); 3500114402Sru#endif 3501114402Sru} 3502114402Sru 3503114402Sru/* 3504151497Sru * lookahead_for_tables - checks for .col tags and inserts table 3505151497Sru * start/end tags 3506114402Sru */ 3507114402Sru 3508114402Sruvoid html_printer::lookahead_for_tables (void) 3509114402Sru{ 3510114402Sru text_glob *g; 3511114402Sru text_glob *start_of_line = NULL; 3512114402Sru text_glob *start_of_table = NULL; 3513114402Sru text_glob *last = NULL; 3514114402Sru colType type_of_col = none; 3515114402Sru int left = 0; 3516114402Sru int found_col = FALSE; 3517114402Sru int seen_text = FALSE; 3518114402Sru int ncol = 0; 3519151497Sru int colmin = 0; // pacify compiler 3520151497Sru int colmax = 0; // pacify compiler 3521151497Sru html_table *tbl = new html_table(&html, -1); 3522114402Sru const char *tab_defs = NULL; 3523114402Sru char align = 'L'; 3524114402Sru int nf = FALSE; 3525114402Sru int old_pageoffset = pageoffset; 3526114402Sru 3527114402Sru remove_courier_tabs(); 3528114402Sru page_contents->dump_page(); 3529114402Sru insert_tab0_foreach_tab(); 3530114402Sru page_contents->dump_page(); 3531114402Sru if (! page_contents->glyphs.is_empty()) { 3532114402Sru page_contents->glyphs.start_from_head(); 3533151497Sru as.reset(); 3534114402Sru g = page_contents->glyphs.get_data(); 3535151497Sru if (g->is_br()) { 3536151497Sru g = page_contents->glyphs.move_right_get_data(); 3537151497Sru handle_state_assertion(g); 3538151497Sru if (page_contents->glyphs.is_equal_to_head()) { 3539151497Sru if (tbl != NULL) { 3540151497Sru delete tbl; 3541151497Sru tbl = NULL; 3542151497Sru } 3543151497Sru return; 3544151497Sru } 3545151497Sru 3546151497Sru start_of_line = g; 3547151497Sru seen_text = FALSE; 3548151497Sru ncol = 0; 3549151497Sru left = next_horiz_pos(g, nf); 3550151497Sru if (found_col) 3551151497Sru last = g; 3552151497Sru found_col = FALSE; 3553151497Sru } 3554151497Sru 3555114402Sru do { 3556114402Sru#if defined(DEBUG_TABLES) 3557114402Sru fprintf(stderr, " [") ; 3558114402Sru fprintf(stderr, g->text_string) ; 3559114402Sru fprintf(stderr, "] ") ; 3560114402Sru fflush(stderr); 3561114402Sru if (strcmp(g->text_string, "XXXXXXX") == 0) 3562114402Sru stop(); 3563114402Sru#endif 3564114402Sru 3565114402Sru nf = calc_nf(g, nf); 3566114402Sru calc_po_in(g, nf); 3567114402Sru if (g->is_col()) { 3568114402Sru if (type_of_col == tab_tag && start_of_table != NULL) { 3569114402Sru page_contents->glyphs.move_left(); 3570114402Sru insert_tab_te(); 3571151497Sru start_of_table->remember_table(tbl); 3572151497Sru tbl = new html_table(&html, -1); 3573114402Sru page_contents->insert_tag(string("*** TAB -> COL ***")); 3574114402Sru if (tab_defs != NULL) 3575151497Sru tbl->tab_stops->init(tab_defs); 3576114402Sru start_of_table = NULL; 3577114402Sru last = NULL; 3578114402Sru } 3579114402Sru type_of_col = col_tag; 3580114402Sru found_col = TRUE; 3581114402Sru ncol = g->get_arg(); 3582114402Sru align = 'L'; 3583114402Sru colmin = 0; 3584114402Sru colmax = 0; 3585114402Sru } else if (g->is_tab()) { 3586114402Sru type_of_col = tab_tag; 3587114402Sru colmin = g->get_tab_args(&align); 3588114402Sru align = 'L'; // for now as 'C' and 'R' are broken 3589151497Sru ncol = tbl->find_tab_column(colmin); 3590151497Sru colmin += pageoffset + get_troff_indent(); 3591151497Sru colmax = tbl->get_tab_pos(ncol+1); 3592114402Sru if (colmax > 0) 3593151497Sru colmax += pageoffset + get_troff_indent(); 3594114402Sru } else if (g->is_tab0()) { 3595114402Sru if (type_of_col == col_tag && start_of_table != NULL) { 3596114402Sru page_contents->glyphs.move_left(); 3597114402Sru insert_tab_te(); 3598151497Sru start_of_table->remember_table(tbl); 3599151497Sru tbl = new html_table(&html, -1); 3600114402Sru page_contents->insert_tag(string("*** COL -> TAB ***")); 3601114402Sru start_of_table = NULL; 3602114402Sru last = NULL; 3603114402Sru } 3604114402Sru if (tab_defs != NULL) 3605151497Sru tbl->tab_stops->init(tab_defs); 3606114402Sru 3607114402Sru type_of_col = tab0_tag; 3608114402Sru ncol = 1; 3609114402Sru colmin = 0; 3610151497Sru colmax = tbl->get_tab_pos(2) + pageoffset + get_troff_indent(); 3611114402Sru } else if (! g->is_a_tag()) 3612114402Sru update_min_max(type_of_col, &colmin, &colmax, g); 3613114402Sru 3614114402Sru if ((! g->is_a_tag()) || g->is_tab()) 3615114402Sru seen_text = TRUE; 3616114402Sru 3617114402Sru if ((g->is_col() || g->is_tab() || g->is_tab0()) 3618114402Sru && (start_of_line != NULL) && (start_of_table == NULL)) { 3619114402Sru start_of_table = insert_tab_ts(start_of_line); 3620114402Sru start_of_line = NULL; 3621114402Sru seen_text = FALSE; 3622114402Sru } else if (g->is_ce() && (start_of_table != NULL)) { 3623114402Sru add_table_end("*** CE ***"); 3624151497Sru start_of_table->remember_table(tbl); 3625151497Sru tbl = new html_table(&html, -1); 3626114402Sru start_of_table = NULL; 3627114402Sru last = NULL; 3628114402Sru } else if (g->is_ta()) { 3629114402Sru tab_defs = g->text_string; 3630151497Sru 3631151497Sru if (type_of_col == col_tag) 3632151497Sru tbl->tab_stops->check_init(tab_defs); 3633151497Sru 3634151497Sru if (!tbl->tab_stops->compatible(tab_defs)) { 3635114402Sru if (start_of_table != NULL) { 3636114402Sru add_table_end("*** TABS ***"); 3637151497Sru start_of_table->remember_table(tbl); 3638151497Sru tbl = new html_table(&html, -1); 3639114402Sru start_of_table = NULL; 3640114402Sru type_of_col = none; 3641114402Sru last = NULL; 3642114402Sru } 3643151497Sru tbl->tab_stops->init(tab_defs); 3644114402Sru } 3645114402Sru } 3646114402Sru 3647114402Sru if (((! g->is_a_tag()) || g->is_tab()) && (start_of_table != NULL)) { 3648114402Sru // we are in a table and have a glyph 3649151497Sru if ((ncol == 0) || (! tbl->add_column(ncol, colmin, colmax, align))) { 3650114402Sru if (ncol == 0) 3651114402Sru add_table_end("*** NCOL == 0 ***"); 3652114402Sru else 3653114402Sru add_table_end("*** CROSSED COLS ***"); 3654114402Sru 3655151497Sru start_of_table->remember_table(tbl); 3656151497Sru tbl = new html_table(&html, -1); 3657114402Sru start_of_table = NULL; 3658114402Sru type_of_col = none; 3659114402Sru last = NULL; 3660114402Sru } 3661114402Sru } 3662114402Sru 3663114402Sru /* 3664114402Sru * move onto next glob, check whether we are starting a new line 3665114402Sru */ 3666114402Sru g = page_contents->glyphs.move_right_get_data(); 3667151497Sru handle_state_assertion(g); 3668114402Sru 3669114402Sru if (g == NULL) { 3670114402Sru if (found_col) { 3671114402Sru page_contents->glyphs.start_from_head(); 3672151497Sru as.reset(); 3673114402Sru last = g; 3674114402Sru found_col = FALSE; 3675114402Sru } 3676114402Sru } else if (g->is_br() || (nf && g->is_eol())) { 3677114402Sru do { 3678114402Sru g = page_contents->glyphs.move_right_get_data(); 3679151497Sru handle_state_assertion(g); 3680114402Sru nf = calc_nf(g, nf); 3681114402Sru } while ((g != NULL) && (g->is_br() || (nf && g->is_eol()))); 3682114402Sru start_of_line = g; 3683114402Sru seen_text = FALSE; 3684114402Sru ncol = 0; 3685114402Sru left = next_horiz_pos(g, nf); 3686114402Sru if (found_col) 3687114402Sru last = g; 3688114402Sru found_col = FALSE; 3689114402Sru } 3690114402Sru } while ((g != NULL) && (! page_contents->glyphs.is_equal_to_head())); 3691114402Sru 3692114402Sru#if defined(DEBUG_TABLES) 3693114402Sru fprintf(stderr, "finished scanning for tables\n"); 3694114402Sru#endif 3695114402Sru 3696114402Sru page_contents->glyphs.start_from_head(); 3697114402Sru if (start_of_table != NULL) { 3698114402Sru if (last != NULL) 3699114402Sru while (last != page_contents->glyphs.get_data()) 3700114402Sru page_contents->glyphs.move_left(); 3701114402Sru 3702114402Sru insert_tab_te(); 3703151497Sru start_of_table->remember_table(tbl); 3704151497Sru tbl = NULL; 3705114402Sru page_contents->insert_tag(string("*** LAST ***")); 3706114402Sru } 3707114402Sru } 3708151497Sru if (tbl != NULL) { 3709151497Sru delete tbl; 3710151497Sru tbl = NULL; 3711151497Sru } 3712114402Sru 3713114402Sru // and reset the registers 3714114402Sru pageoffset = old_pageoffset; 3715151497Sru troff_indent = 0; 3716151497Sru temp_indent = 0; 3717114402Sru end_tempindent = 0; 3718114402Sru} 3719114402Sru 3720114402Sruvoid html_printer::flush_page (void) 3721114402Sru{ 3722114402Sru supress_sub_sup = TRUE; 3723114402Sru flush_sbuf(); 3724114402Sru page_contents->dump_page(); 3725114402Sru lookahead_for_tables(); 3726114402Sru page_contents->dump_page(); 3727114402Sru 3728114402Sru flush_globs(); 3729114402Sru current_paragraph->done_para(); 3730114402Sru 3731114402Sru // move onto a new page 3732114402Sru delete page_contents; 3733114402Sru#if defined(DEBUG_TABLES) 3734114402Sru fprintf(stderr, "\n\n*** flushed page ***\n\n"); 3735114402Sru 3736114402Sru html.simple_comment("new page called"); 3737114402Sru#endif 3738114402Sru page_contents = new page; 3739114402Sru} 3740114402Sru 3741114402Sru/* 3742114402Sru * determine_space - works out whether we need to write a space. 3743114402Sru * If last glyph is ajoining then no space emitted. 3744114402Sru */ 3745114402Sru 3746114402Sruvoid html_printer::determine_space (text_glob *g) 3747114402Sru{ 3748114402Sru if (current_paragraph->is_in_pre()) { 3749114402Sru /* 3750114402Sru * .nf has been specified 3751114402Sru */ 3752114402Sru while (output_hpos < g->minh) { 3753114402Sru output_hpos += space_width; 3754114402Sru current_paragraph->emit_space(); 3755114402Sru } 3756114402Sru } else { 3757114402Sru if ((output_vpos != g->minv) || (output_hpos < g->minh)) { 3758114402Sru current_paragraph->emit_space(); 3759114402Sru } 3760114402Sru } 3761114402Sru} 3762114402Sru 3763114402Sru/* 3764151497Sru * is_line_start - returns TRUE if we are at the start of a line. 3765151497Sru */ 3766151497Sru 3767151497Sruint html_printer::is_line_start (int nf) 3768151497Sru{ 3769151497Sru int line_start = FALSE; 3770151497Sru int result = TRUE; 3771151497Sru text_glob *orig = page_contents->glyphs.get_data(); 3772151497Sru text_glob *g; 3773151497Sru 3774151497Sru if (! page_contents->glyphs.is_equal_to_head()) { 3775151497Sru do { 3776151497Sru page_contents->glyphs.move_left(); 3777151497Sru g = page_contents->glyphs.get_data(); 3778151497Sru result = g->is_a_tag(); 3779151497Sru if (g->is_fi()) 3780151497Sru nf = FALSE; 3781151497Sru else if (g->is_nf()) 3782151497Sru nf = TRUE; 3783151497Sru line_start = g->is_col() || g->is_br() || (nf && g->is_eol()); 3784151497Sru } while ((!line_start) && (result)); 3785151497Sru /* 3786151497Sru * now restore our previous position. 3787151497Sru */ 3788151497Sru while (page_contents->glyphs.get_data() != orig) 3789151497Sru page_contents->glyphs.move_right(); 3790151497Sru } 3791151497Sru return result; 3792151497Sru} 3793151497Sru 3794151497Sru/* 3795114402Sru * is_font_courier - returns TRUE if the font, f, is courier. 3796114402Sru */ 3797114402Sru 3798114402Sruint html_printer::is_font_courier (font *f) 3799114402Sru{ 3800114402Sru if (f != 0) { 3801114402Sru const char *fontname = f->get_name(); 3802114402Sru 3803114402Sru return( (fontname != 0) && (fontname[0] == 'C') ); 3804114402Sru } 3805151497Sru return FALSE; 3806114402Sru} 3807114402Sru 3808114402Sru/* 3809114402Sru * end_font - shuts down the font corresponding to fontname. 3810114402Sru */ 3811114402Sru 3812114402Sruvoid html_printer::end_font (const char *fontname) 3813114402Sru{ 3814114402Sru if (strcmp(fontname, "B") == 0) { 3815114402Sru current_paragraph->done_bold(); 3816114402Sru } else if (strcmp(fontname, "I") == 0) { 3817114402Sru current_paragraph->done_italic(); 3818114402Sru } else if (strcmp(fontname, "BI") == 0) { 3819114402Sru current_paragraph->done_bold(); 3820114402Sru current_paragraph->done_italic(); 3821114402Sru } else if (strcmp(fontname, "CR") == 0) { 3822114402Sru current_paragraph->done_tt(); 3823114402Sru } else if (strcmp(fontname, "CI") == 0) { 3824114402Sru current_paragraph->done_italic(); 3825114402Sru current_paragraph->done_tt(); 3826114402Sru } else if (strcmp(fontname, "CB") == 0) { 3827114402Sru current_paragraph->done_bold(); 3828114402Sru current_paragraph->done_tt(); 3829114402Sru } else if (strcmp(fontname, "CBI") == 0) { 3830114402Sru current_paragraph->done_bold(); 3831114402Sru current_paragraph->done_italic(); 3832114402Sru current_paragraph->done_tt(); 3833114402Sru } 3834114402Sru} 3835114402Sru 3836114402Sru/* 3837114402Sru * start_font - starts the font corresponding to name. 3838114402Sru */ 3839114402Sru 3840114402Sruvoid html_printer::start_font (const char *fontname) 3841114402Sru{ 3842114402Sru if (strcmp(fontname, "R") == 0) { 3843114402Sru current_paragraph->done_bold(); 3844114402Sru current_paragraph->done_italic(); 3845114402Sru current_paragraph->done_tt(); 3846114402Sru } else if (strcmp(fontname, "B") == 0) { 3847114402Sru current_paragraph->do_bold(); 3848114402Sru } else if (strcmp(fontname, "I") == 0) { 3849114402Sru current_paragraph->do_italic(); 3850114402Sru } else if (strcmp(fontname, "BI") == 0) { 3851114402Sru current_paragraph->do_bold(); 3852114402Sru current_paragraph->do_italic(); 3853114402Sru } else if (strcmp(fontname, "CR") == 0) { 3854151497Sru if ((! fill_on) && (is_courier_until_eol()) && 3855151497Sru is_line_start(! fill_on)) { 3856114402Sru current_paragraph->do_pre(); 3857114402Sru } 3858114402Sru current_paragraph->do_tt(); 3859114402Sru } else if (strcmp(fontname, "CI") == 0) { 3860151497Sru if ((! fill_on) && (is_courier_until_eol()) && 3861151497Sru is_line_start(! fill_on)) { 3862114402Sru current_paragraph->do_pre(); 3863114402Sru } 3864114402Sru current_paragraph->do_tt(); 3865114402Sru current_paragraph->do_italic(); 3866114402Sru } else if (strcmp(fontname, "CB") == 0) { 3867151497Sru if ((! fill_on) && (is_courier_until_eol()) && 3868151497Sru is_line_start(! fill_on)) { 3869114402Sru current_paragraph->do_pre(); 3870114402Sru } 3871114402Sru current_paragraph->do_tt(); 3872114402Sru current_paragraph->do_bold(); 3873114402Sru } else if (strcmp(fontname, "CBI") == 0) { 3874151497Sru if ((! fill_on) && (is_courier_until_eol()) && 3875151497Sru is_line_start(! fill_on)) { 3876114402Sru current_paragraph->do_pre(); 3877114402Sru } 3878114402Sru current_paragraph->do_tt(); 3879114402Sru current_paragraph->do_italic(); 3880114402Sru current_paragraph->do_bold(); 3881114402Sru } 3882114402Sru} 3883114402Sru 3884114402Sru/* 3885114402Sru * start_size - from is old font size, to is the new font size. 3886114402Sru * The html increase <big> and <small> decrease alters the 3887114402Sru * font size by 20%. We try and map these onto glyph sizes. 3888114402Sru */ 3889114402Sru 3890114402Sruvoid html_printer::start_size (int from, int to) 3891114402Sru{ 3892114402Sru if (from < to) { 3893114402Sru while (from < to) { 3894114402Sru current_paragraph->do_big(); 3895114402Sru from += SIZE_INCREMENT; 3896114402Sru } 3897114402Sru } else if (from > to) { 3898114402Sru while (from > to) { 3899114402Sru current_paragraph->do_small(); 3900114402Sru from -= SIZE_INCREMENT; 3901114402Sru } 3902114402Sru } 3903114402Sru} 3904114402Sru 3905114402Sru/* 3906114402Sru * do_font - checks to see whether we need to alter the html font. 3907114402Sru */ 3908114402Sru 3909114402Sruvoid html_printer::do_font (text_glob *g) 3910114402Sru{ 3911114402Sru /* 3912114402Sru * check if the output_style.point_size has not been set yet 3913114402Sru * this allow users to place .ps at the top of their troff files 3914114402Sru * and grohtml can then treat the .ps value as the base font size (3) 3915114402Sru */ 3916114402Sru if (output_style.point_size == -1) { 3917114402Sru output_style.point_size = pointsize; 3918114402Sru } 3919114402Sru 3920114402Sru if (g->text_style.f != output_style.f) { 3921114402Sru if (output_style.f != 0) { 3922114402Sru end_font(output_style.f->get_name()); 3923114402Sru } 3924114402Sru output_style.f = g->text_style.f; 3925114402Sru if (output_style.f != 0) { 3926114402Sru start_font(output_style.f->get_name()); 3927114402Sru } 3928114402Sru } 3929114402Sru if (output_style.point_size != g->text_style.point_size) { 3930114402Sru do_sup_or_sub(g); 3931114402Sru if ((output_style.point_size > 0) && 3932114402Sru (g->text_style.point_size > 0)) { 3933114402Sru start_size(output_style.point_size, g->text_style.point_size); 3934114402Sru } 3935114402Sru if (g->text_style.point_size > 0) { 3936114402Sru output_style.point_size = g->text_style.point_size; 3937114402Sru } 3938114402Sru } 3939114402Sru if (output_style.col != g->text_style.col) { 3940114402Sru current_paragraph->done_color(); 3941114402Sru output_style.col = g->text_style.col; 3942114402Sru current_paragraph->do_color(&output_style.col); 3943114402Sru } 3944114402Sru} 3945114402Sru 3946114402Sru/* 3947114402Sru * start_subscript - returns TRUE if, g, looks like a subscript start. 3948114402Sru */ 3949114402Sru 3950114402Sruint html_printer::start_subscript (text_glob *g) 3951114402Sru{ 3952114402Sru int r = font::res; 3953114402Sru int height = output_style.point_size*r/72; 3954114402Sru 3955114402Sru return( (output_style.point_size != 0) && 3956114402Sru (output_vpos < g->minv) && 3957114402Sru (output_vpos-height > g->maxv) && 3958114402Sru (output_style.point_size > g->text_style.point_size) ); 3959114402Sru} 3960114402Sru 3961114402Sru/* 3962114402Sru * start_superscript - returns TRUE if, g, looks like a superscript start. 3963114402Sru */ 3964114402Sru 3965114402Sruint html_printer::start_superscript (text_glob *g) 3966114402Sru{ 3967114402Sru int r = font::res; 3968114402Sru int height = output_style.point_size*r/72; 3969114402Sru 3970114402Sru return( (output_style.point_size != 0) && 3971114402Sru (output_vpos > g->minv) && 3972114402Sru (output_vpos-height < g->maxv) && 3973114402Sru (output_style.point_size > g->text_style.point_size) ); 3974114402Sru} 3975114402Sru 3976114402Sru/* 3977114402Sru * end_subscript - returns TRUE if, g, looks like the end of a subscript. 3978114402Sru */ 3979114402Sru 3980114402Sruint html_printer::end_subscript (text_glob *g) 3981114402Sru{ 3982114402Sru int r = font::res; 3983114402Sru int height = output_style.point_size*r/72; 3984114402Sru 3985114402Sru return( (output_style.point_size != 0) && 3986114402Sru (g->minv < output_vpos) && 3987114402Sru (output_vpos-height > g->maxv) && 3988114402Sru (output_style.point_size < g->text_style.point_size) ); 3989114402Sru} 3990114402Sru 3991114402Sru/* 3992114402Sru * end_superscript - returns TRUE if, g, looks like the end of a superscript. 3993114402Sru */ 3994114402Sru 3995114402Sruint html_printer::end_superscript (text_glob *g) 3996114402Sru{ 3997114402Sru int r = font::res; 3998114402Sru int height = output_style.point_size*r/72; 3999114402Sru 4000114402Sru return( (output_style.point_size != 0) && 4001114402Sru (g->minv > output_vpos) && 4002114402Sru (output_vpos-height < g->maxv) && 4003114402Sru (output_style.point_size < g->text_style.point_size) ); 4004114402Sru} 4005114402Sru 4006114402Sru/* 4007114402Sru * do_sup_or_sub - checks to see whether the next glyph is a subscript/superscript 4008114402Sru * start/end and it calls the services of html-text to issue the 4009114402Sru * appropriate tags. 4010114402Sru */ 4011114402Sru 4012114402Sruvoid html_printer::do_sup_or_sub (text_glob *g) 4013114402Sru{ 4014114402Sru if (! supress_sub_sup) { 4015114402Sru if (start_subscript(g)) { 4016114402Sru current_paragraph->do_sub(); 4017114402Sru } else if (start_superscript(g)) { 4018114402Sru current_paragraph->do_sup(); 4019114402Sru } else if (end_subscript(g)) { 4020114402Sru current_paragraph->done_sub(); 4021114402Sru } else if (end_superscript(g)) { 4022114402Sru current_paragraph->done_sup(); 4023114402Sru } 4024114402Sru } 4025114402Sru} 4026114402Sru 4027114402Sru/* 4028151497Sru * do_end_para - writes out the html text after shutting down the 4029151497Sru * current paragraph. 4030151497Sru */ 4031151497Sru 4032151497Sruvoid html_printer::do_end_para (text_glob *g) 4033151497Sru{ 4034151497Sru do_font(g); 4035151497Sru current_paragraph->done_para(); 4036151497Sru current_paragraph->remove_para_space(); 4037151497Sru html.put_string(g->text_string+9); 4038151497Sru output_vpos = g->minv; 4039151497Sru output_hpos = g->maxh; 4040151497Sru output_vpos_max = g->maxv; 4041151497Sru supress_sub_sup = FALSE; 4042151497Sru} 4043151497Sru 4044151497Sru/* 4045114402Sru * emit_html - write out the html text 4046114402Sru */ 4047114402Sru 4048114402Sruvoid html_printer::emit_html (text_glob *g) 4049114402Sru{ 4050114402Sru do_font(g); 4051114402Sru determine_space(g); 4052114402Sru current_paragraph->do_emittext(g->text_string, g->text_length); 4053114402Sru output_vpos = g->minv; 4054114402Sru output_hpos = g->maxh; 4055114402Sru output_vpos_max = g->maxv; 4056114402Sru supress_sub_sup = FALSE; 4057114402Sru} 4058114402Sru 4059114402Sru/* 4060114402Sru * flush_sbuf - flushes the current sbuf into the list of glyphs. 4061114402Sru */ 4062114402Sru 4063114402Sruvoid html_printer::flush_sbuf() 4064114402Sru{ 4065114402Sru if (sbuf.length() > 0) { 4066114402Sru int r=font::res; // resolution of the device 4067114402Sru set_style(sbuf_style); 4068151497Sru 4069114402Sru if (overstrike_detected && (! is_bold(sbuf_style.f))) { 4070114402Sru font *bold_font = make_bold(sbuf_style.f); 4071114402Sru if (bold_font != NULL) 4072114402Sru sbuf_style.f = bold_font; 4073114402Sru } 4074114402Sru 4075114402Sru page_contents->add(&sbuf_style, sbuf, 4076114402Sru line_number, 4077114402Sru sbuf_vpos-sbuf_style.point_size*r/72, sbuf_start_hpos, 4078114402Sru sbuf_vpos , sbuf_end_hpos); 4079114402Sru 4080114402Sru output_hpos = sbuf_end_hpos; 4081114402Sru output_vpos = sbuf_vpos; 4082114402Sru last_sbuf_length = 0; 4083114402Sru sbuf_prev_hpos = sbuf_end_hpos; 4084114402Sru overstrike_detected = FALSE; 4085114402Sru sbuf.clear(); 4086114402Sru } 4087114402Sru} 4088114402Sru 4089114402Sruvoid html_printer::set_line_thickness(const environment *env) 4090114402Sru{ 4091114402Sru line_thickness = env->size; 4092114402Sru} 4093114402Sru 4094114402Sruvoid html_printer::draw(int code, int *p, int np, const environment *env) 4095114402Sru{ 4096114402Sru switch (code) { 4097114402Sru 4098114402Sru case 'l': 4099114402Sru# if 0 4100114402Sru if (np == 2) { 4101114402Sru page_contents->add_line(&sbuf_style, 4102114402Sru line_number, 4103114402Sru env->hpos, env->vpos, env->hpos+p[0], env->vpos+p[1], line_thickness); 4104114402Sru } else { 4105114402Sru error("2 arguments required for line"); 4106114402Sru } 4107114402Sru# endif 4108114402Sru break; 4109114402Sru case 't': 4110114402Sru { 4111114402Sru if (np == 0) { 4112114402Sru line_thickness = -1; 4113114402Sru } else { 4114114402Sru // troff gratuitously adds an extra 0 4115114402Sru if (np != 1 && np != 2) { 4116114402Sru error("0 or 1 argument required for thickness"); 4117114402Sru break; 4118114402Sru } 4119114402Sru line_thickness = p[0]; 4120114402Sru } 4121114402Sru break; 4122114402Sru } 4123114402Sru 4124114402Sru case 'P': 4125114402Sru break; 4126114402Sru case 'p': 4127114402Sru break; 4128114402Sru case 'E': 4129114402Sru break; 4130114402Sru case 'e': 4131114402Sru break; 4132114402Sru case 'C': 4133114402Sru break; 4134114402Sru case 'c': 4135114402Sru break; 4136114402Sru case 'a': 4137114402Sru break; 4138114402Sru case '~': 4139114402Sru break; 4140114402Sru case 'f': 4141114402Sru break; 4142114402Sru case 'F': 4143114402Sru // fill with color env->fill 4144114402Sru if (background != NULL) 4145114402Sru delete background; 4146114402Sru background = new color; 4147114402Sru *background = *env->fill; 4148114402Sru break; 4149114402Sru 4150114402Sru default: 4151114402Sru error("unrecognised drawing command `%1'", char(code)); 4152114402Sru break; 4153114402Sru } 4154114402Sru} 4155114402Sru 4156114402Sruhtml_printer::html_printer() 4157114402Sru: html(0, MAX_LINE_LENGTH), 4158114402Sru no_of_printed_pages(0), 4159114402Sru last_sbuf_length(0), 4160114402Sru overstrike_detected(FALSE), 4161114402Sru output_hpos(-1), 4162114402Sru output_vpos(-1), 4163114402Sru output_vpos_max(-1), 4164114402Sru line_thickness(-1), 4165114402Sru inside_font_style(0), 4166114402Sru page_number(0), 4167114402Sru header_indent(-1), 4168114402Sru supress_sub_sup(TRUE), 4169114402Sru cutoff_heading(100), 4170114402Sru indent(NULL), 4171114402Sru table(NULL), 4172114402Sru end_center(0), 4173114402Sru end_tempindent(0), 4174114402Sru next_tag(INLINE), 4175114402Sru fill_on(TRUE), 4176114402Sru max_linelength(-1), 4177114402Sru linelength(0), 4178114402Sru pageoffset(0), 4179151497Sru troff_indent(0), 4180151497Sru device_indent(0), 4181151497Sru temp_indent(0), 4182151497Sru pointsize(base_point_size), 4183114402Sru line_number(0), 4184151497Sru background(default_background), 4185151497Sru seen_indent(FALSE), 4186151497Sru next_indent(0), 4187151497Sru seen_pageoffset(FALSE), 4188151497Sru next_pageoffset(0), 4189151497Sru seen_linelength(FALSE), 4190151497Sru next_linelength(0), 4191151497Sru seen_center(FALSE), 4192151497Sru next_center(0), 4193151497Sru seen_space(0), 4194151497Sru seen_break(0), 4195151497Sru current_column(0), 4196151497Sru row_space(FALSE) 4197114402Sru{ 4198114402Sru file_list.add_new_file(xtmpfile()); 4199114402Sru html.set_file(file_list.get_file()); 4200114402Sru if (font::hor != 24) 4201114402Sru fatal("horizontal resolution must be 24"); 4202114402Sru if (font::vert != 40) 4203114402Sru fatal("vertical resolution must be 40"); 4204114402Sru#if 0 4205114402Sru // should be sorted html.. 4206114402Sru if (font::res % (font::sizescale*72) != 0) 4207114402Sru fatal("res must be a multiple of 72*sizescale"); 4208114402Sru#endif 4209114402Sru int r = font::res; 4210114402Sru int point = 0; 4211114402Sru while (r % 10 == 0) { 4212114402Sru r /= 10; 4213114402Sru point++; 4214114402Sru } 4215114402Sru res = r; 4216114402Sru html.set_fixed_point(point); 4217114402Sru space_char_index = font::name_to_index("space"); 4218114402Sru space_width = font::hor; 4219114402Sru paper_length = font::paperlength; 4220114402Sru linelength = font::res*13/2; 4221114402Sru if (paper_length == 0) 4222114402Sru paper_length = 11*font::res; 4223114402Sru 4224114402Sru page_contents = new page(); 4225114402Sru} 4226114402Sru 4227114402Sru/* 4228114402Sru * add_to_sbuf - adds character code or name to the sbuf. 4229114402Sru */ 4230114402Sru 4231151497Sruvoid html_printer::add_to_sbuf (int idx, const string &s) 4232114402Sru{ 4233114402Sru if (sbuf_style.f == NULL) 4234114402Sru return; 4235114402Sru 4236114402Sru char *html_glyph = NULL; 4237151497Sru unsigned int code = sbuf_style.f->get_code(idx); 4238114402Sru 4239114402Sru if (s.empty()) { 4240151497Sru if (sbuf_style.f->contains(idx)) 4241151497Sru html_glyph = (char *)sbuf_style.f->get_special_device_encoding(idx); 4242114402Sru else 4243114402Sru html_glyph = NULL; 4244114402Sru 4245114402Sru if ((html_glyph == NULL) && (code >= UNICODE_DESC_START)) 4246114402Sru html_glyph = to_unicode(code); 4247114402Sru } else 4248114402Sru html_glyph = get_html_translation(sbuf_style.f, s); 4249114402Sru 4250114402Sru last_sbuf_length = sbuf.length(); 4251114402Sru if (html_glyph == NULL) 4252114402Sru sbuf += ((char)code); 4253114402Sru else 4254114402Sru sbuf += html_glyph; 4255114402Sru} 4256114402Sru 4257151497Sruint html_printer::sbuf_continuation (int idx, const char *name, 4258114402Sru const environment *env, int w) 4259114402Sru{ 4260114402Sru /* 4261114402Sru * lets see whether the glyph is closer to the end of sbuf 4262114402Sru */ 4263114402Sru if ((sbuf_end_hpos == env->hpos) 4264114402Sru || ((sbuf_prev_hpos < sbuf_end_hpos) 4265114402Sru && (env->hpos < sbuf_end_hpos) 4266114402Sru && ((sbuf_end_hpos-env->hpos < env->hpos-sbuf_prev_hpos)))) { 4267151497Sru add_to_sbuf(idx, name); 4268114402Sru sbuf_prev_hpos = sbuf_end_hpos; 4269114402Sru sbuf_end_hpos += w + sbuf_kern; 4270114402Sru return TRUE; 4271114402Sru } else { 4272114402Sru if ((env->hpos >= sbuf_end_hpos) && 4273114402Sru ((sbuf_kern == 0) || (sbuf_end_hpos - sbuf_kern != env->hpos))) { 4274114402Sru /* 4275114402Sru * lets see whether a space is needed or not 4276114402Sru */ 4277114402Sru 4278114402Sru if (env->hpos-sbuf_end_hpos < space_width) { 4279151497Sru add_to_sbuf(idx, name); 4280114402Sru sbuf_prev_hpos = sbuf_end_hpos; 4281114402Sru sbuf_end_hpos = env->hpos + w; 4282114402Sru return TRUE; 4283114402Sru } 4284114402Sru } 4285114402Sru } 4286114402Sru return FALSE ; 4287114402Sru} 4288114402Sru 4289114402Sru/* 4290114402Sru * get_html_translation - given the position of the character and its name 4291114402Sru * return the device encoding for such character. 4292114402Sru */ 4293114402Sru 4294114402Sruchar *get_html_translation (font *f, const string &name) 4295114402Sru{ 4296151497Sru int idx; 4297114402Sru 4298114402Sru if ((f == 0) || name.empty()) 4299114402Sru return NULL; 4300114402Sru else { 4301151497Sru idx = f->name_to_index((char *)(name + '\0').contents()); 4302151497Sru if (idx == 0) { 4303114402Sru error("character `%s' not found", (name + '\0').contents()); 4304114402Sru return NULL; 4305114402Sru } else 4306151497Sru if (f->contains(idx)) 4307151497Sru return (char *)f->get_special_device_encoding(idx); 4308114402Sru else 4309114402Sru return NULL; 4310114402Sru } 4311114402Sru} 4312114402Sru 4313114402Sru/* 4314114402Sru * overstrike - returns TRUE if the glyph (i, name) is going to overstrike 4315114402Sru * a previous glyph in sbuf. 4316114402Sru * If TRUE the font is changed to bold and the previous sbuf 4317114402Sru * is flushed. 4318114402Sru */ 4319114402Sru 4320151497Sruint html_printer::overstrike(int idx, const char *name, const environment *env, int w) 4321114402Sru{ 4322114402Sru if ((env->hpos < sbuf_end_hpos) 4323114402Sru || ((sbuf_kern != 0) && (sbuf_end_hpos - sbuf_kern < env->hpos))) { 4324114402Sru /* 4325114402Sru * at this point we have detected an overlap 4326114402Sru */ 4327114402Sru if (overstrike_detected) { 4328114402Sru /* already detected, remove previous glyph and use this glyph */ 4329114402Sru sbuf.set_length(last_sbuf_length); 4330151497Sru add_to_sbuf(idx, name); 4331114402Sru sbuf_end_hpos = env->hpos + w; 4332114402Sru return TRUE; 4333114402Sru } else { 4334114402Sru /* first time we have detected an overstrike in the sbuf */ 4335114402Sru sbuf.set_length(last_sbuf_length); /* remove previous glyph */ 4336114402Sru if (! is_bold(sbuf_style.f)) 4337114402Sru flush_sbuf(); 4338114402Sru overstrike_detected = TRUE; 4339151497Sru add_to_sbuf(idx, name); 4340114402Sru sbuf_end_hpos = env->hpos + w; 4341114402Sru return TRUE; 4342114402Sru } 4343114402Sru } 4344114402Sru return FALSE ; 4345114402Sru} 4346114402Sru 4347114402Sru/* 4348151497Sru * set_char - adds a character into the sbuf if it is a continuation 4349151497Sru * with the previous word otherwise flush the current sbuf 4350151497Sru * and add character anew. 4351114402Sru */ 4352114402Sru 4353151497Sruvoid html_printer::set_char(int i, font *f, const environment *env, 4354151497Sru int w, const char *name) 4355114402Sru{ 4356114402Sru style sty(f, env->size, env->height, env->slant, env->fontno, *env->col); 4357114402Sru if (sty.slant != 0) { 4358114402Sru if (sty.slant > 80 || sty.slant < -80) { 4359114402Sru error("silly slant `%1' degrees", sty.slant); 4360114402Sru sty.slant = 0; 4361114402Sru } 4362114402Sru } 4363114402Sru if (((! sbuf.empty()) && (sty == sbuf_style) && (sbuf_vpos == env->vpos)) 4364114402Sru && (sbuf_continuation(i, name, env, w) || overstrike(i, name, env, w))) 4365114402Sru return; 4366114402Sru 4367114402Sru flush_sbuf(); 4368151497Sru if (sbuf_style.f == NULL) 4369151497Sru sbuf_style = sty; 4370114402Sru add_to_sbuf(i, name); 4371114402Sru sbuf_end_hpos = env->hpos + w; 4372114402Sru sbuf_start_hpos = env->hpos; 4373114402Sru sbuf_prev_hpos = env->hpos; 4374114402Sru sbuf_vpos = env->vpos; 4375114402Sru sbuf_style = sty; 4376114402Sru sbuf_kern = 0; 4377114402Sru} 4378114402Sru 4379114402Sru/* 4380114402Sru * set_numbered_char - handle numbered characters. 4381114402Sru * Negative values are interpreted as unbreakable spaces; 4382114402Sru * the value (taken positive) gives the width. 4383114402Sru */ 4384114402Sru 4385114402Sruvoid html_printer::set_numbered_char(int num, const environment *env, 4386114402Sru int *widthp) 4387114402Sru{ 4388114402Sru int nbsp_width = 0; 4389114402Sru if (num < 0) { 4390114402Sru nbsp_width = -num; 4391114402Sru num = 160; // 4392114402Sru } 4393114402Sru int i = font::number_to_index(num); 4394114402Sru int fn = env->fontno; 4395114402Sru if (fn < 0 || fn >= nfonts) { 4396114402Sru error("bad font position `%1'", fn); 4397114402Sru return; 4398114402Sru } 4399114402Sru font *f = font_table[fn]; 4400114402Sru if (f == 0) { 4401114402Sru error("no font mounted at `%1'", fn); 4402114402Sru return; 4403114402Sru } 4404114402Sru if (!f->contains(i)) { 4405114402Sru error("font `%1' does not contain numbered character %2", 4406114402Sru f->get_name(), 4407114402Sru num); 4408114402Sru return; 4409114402Sru } 4410114402Sru int w; 4411114402Sru if (nbsp_width) 4412114402Sru w = nbsp_width; 4413114402Sru else 4414114402Sru w = f->get_width(i, env->size); 4415151497Sru w = round_width(w); 4416114402Sru if (widthp) 4417114402Sru *widthp = w; 4418114402Sru set_char(i, f, env, w, 0); 4419114402Sru} 4420114402Sru 4421151497Sruint html_printer::set_char_and_width(const char *nm, const environment *env, 4422151497Sru int *widthp, font **f) 4423151497Sru{ 4424151497Sru int i = font::name_to_index(nm); 4425151497Sru int fn = env->fontno; 4426151497Sru if (fn < 0 || fn >= nfonts) { 4427151497Sru error("bad font position `%1'", fn); 4428151497Sru return -1; 4429151497Sru } 4430151497Sru *f = font_table[fn]; 4431151497Sru if (*f == 0) { 4432151497Sru error("no font mounted at `%1'", fn); 4433151497Sru return -1; 4434151497Sru } 4435151497Sru if (!(*f)->contains(i)) { 4436151497Sru if (nm[0] != '\0' && nm[1] == '\0') 4437151497Sru error("font `%1' does not contain ascii character `%2'", 4438151497Sru (*f)->get_name(), 4439151497Sru nm[0]); 4440151497Sru else 4441151497Sru error("font `%1' does not contain special character `%2'", 4442151497Sru (*f)->get_name(), 4443151497Sru nm); 4444151497Sru return -1; 4445151497Sru } 4446151497Sru int w = (*f)->get_width(i, env->size); 4447151497Sru w = round_width(w); 4448151497Sru if (widthp) 4449151497Sru *widthp = w; 4450151497Sru return i; 4451151497Sru} 4452151497Sru 4453114402Sru/* 4454114402Sru * write_title - writes the title to this document 4455114402Sru */ 4456114402Sru 4457114402Sruvoid html_printer::write_title (int in_head) 4458114402Sru{ 4459114402Sru if (title.has_been_found) { 4460114402Sru if (in_head) { 4461114402Sru html.put_string("<title>"); 4462114402Sru html.put_string(title.text); 4463114402Sru html.put_string("</title>").nl().nl(); 4464114402Sru } else { 4465114402Sru title.has_been_written = TRUE; 4466114402Sru if (title.with_h1) { 4467114402Sru html.put_string("<h1 align=center>"); 4468114402Sru html.put_string(title.text); 4469114402Sru html.put_string("</h1>").nl().nl(); 4470114402Sru } 4471114402Sru } 4472114402Sru } else if (in_head) { 4473114402Sru // place empty title tags to help conform to `tidy' 4474114402Sru html.put_string("<title></title>").nl(); 4475114402Sru } 4476114402Sru} 4477114402Sru 4478114402Sru/* 4479114402Sru * write_rule - emits a html rule tag, if the auto_rule boolean is true. 4480114402Sru */ 4481114402Sru 4482114402Srustatic void write_rule (void) 4483114402Sru{ 4484114402Sru if (auto_rule) 4485114402Sru fputs("<hr>\n", stdout); 4486114402Sru} 4487114402Sru 4488114402Sruvoid html_printer::begin_page(int n) 4489114402Sru{ 4490114402Sru page_number = n; 4491114402Sru#if defined(DEBUGGING) 4492114402Sru html.begin_comment("Page: ").put_string(i_to_a(page_number)).end_comment();; 4493114402Sru#endif 4494114402Sru no_of_printed_pages++; 4495114402Sru 4496114402Sru output_style.f = 0; 4497114402Sru output_style.point_size= -1; 4498114402Sru output_space_code = 32; 4499114402Sru output_draw_point_size = -1; 4500114402Sru output_line_thickness = -1; 4501114402Sru output_hpos = -1; 4502114402Sru output_vpos = -1; 4503114402Sru output_vpos_max = -1; 4504114402Sru current_paragraph = new html_text(&html); 4505151497Sru do_indent(get_troff_indent(), pageoffset, linelength); 4506151497Sru current_paragraph->do_para("", FALSE); 4507114402Sru} 4508114402Sru 4509114402Sruvoid html_printer::end_page(int) 4510114402Sru{ 4511114402Sru flush_sbuf(); 4512114402Sru flush_page(); 4513114402Sru} 4514114402Sru 4515114402Srufont *html_printer::make_font(const char *nm) 4516114402Sru{ 4517114402Sru return html_font::load_html_font(nm); 4518114402Sru} 4519114402Sru 4520114402Sruvoid html_printer::do_body (void) 4521114402Sru{ 4522114402Sru if (background == NULL) 4523114402Sru fputs("<body>\n\n", stdout); 4524114402Sru else { 4525114402Sru unsigned int r, g, b; 4526114402Sru char buf[6+1]; 4527114402Sru 4528114402Sru background->get_rgb(&r, &g, &b); 4529114402Sru // we have to scale 0..0xFFFF to 0..0xFF 4530114402Sru sprintf(buf, "%.2X%.2X%.2X", r/0x101, g/0x101, b/0x101); 4531114402Sru 4532114402Sru fputs("<body bgcolor=\"#", stdout); 4533114402Sru fputs(buf, stdout); 4534114402Sru fputs("\">\n\n", stdout); 4535114402Sru } 4536114402Sru} 4537114402Sru 4538151497Sru/* 4539151497Sru * emit_link - generates: <a href="to">name</a> 4540151497Sru */ 4541151497Sru 4542151497Sruvoid html_printer::emit_link (const string &to, const char *name) 4543151497Sru{ 4544151497Sru fputs("<a href=\"", stdout); 4545151497Sru fputs(to.contents(), stdout); 4546151497Sru fputs("\">", stdout); 4547151497Sru fputs(name, stdout); 4548151497Sru fputs("</a>", stdout); 4549151497Sru} 4550151497Sru 4551151497Sru/* 4552151497Sru * write_navigation - writes out the links which navigate between 4553151497Sru * file fragments. 4554151497Sru */ 4555151497Sru 4556151497Sruvoid html_printer::write_navigation (const string &top, const string &prev, 4557151497Sru const string &next, const string ¤t) 4558151497Sru{ 4559151497Sru int need_bar = FALSE; 4560151497Sru 4561151497Sru if (multiple_files) { 4562151497Sru write_rule(); 4563151497Sru fputs("[ ", stdout); 4564151497Sru if ((strcmp(prev.contents(), "") != 0) && prev != top && prev != current) { 4565151497Sru emit_link(prev, "prev"); 4566151497Sru need_bar = TRUE; 4567151497Sru } 4568151497Sru if ((strcmp(next.contents(), "") != 0) && next != top && next != current) { 4569151497Sru if (need_bar) 4570151497Sru fputs(" | ", stdout); 4571151497Sru emit_link(next, "next"); 4572151497Sru need_bar = TRUE; 4573151497Sru } 4574151497Sru if (top != "<standard input>" && (strcmp(top.contents(), "") != 0) && top != current) { 4575151497Sru if (need_bar) 4576151497Sru fputs(" | ", stdout); 4577151497Sru emit_link(top, "top"); 4578151497Sru } 4579151497Sru fputs(" ]\n", stdout); 4580151497Sru write_rule(); 4581151497Sru } 4582151497Sru} 4583151497Sru 4584151497Sru/* 4585151497Sru * do_file_components - scan the file list copying each temporary 4586151497Sru * file in turn. This is used twofold: 4587151497Sru * 4588151497Sru * firstly to emit section heading links, 4589151497Sru * between file fragments if required and 4590151497Sru * secondly to generate jobname file fragments 4591151497Sru * if required. 4592151497Sru */ 4593151497Sru 4594151497Sruvoid html_printer::do_file_components (void) 4595151497Sru{ 4596151497Sru int fragment_no = 1; 4597151497Sru string top; 4598151497Sru string prev; 4599151497Sru string next; 4600151497Sru string current; 4601151497Sru 4602151497Sru file_list.start_of_list(); 4603151497Sru top = string(job_name); 4604151497Sru top += string(".html"); 4605151497Sru top += '\0'; 4606151497Sru next = file_list.next_file_name(); 4607151497Sru next += '\0'; 4608151497Sru current = next; 4609151497Sru while (file_list.get_file() != 0) { 4610151497Sru if (fseek(file_list.get_file(), 0L, 0) < 0) 4611151497Sru fatal("fseek on temporary file failed"); 4612151497Sru html.copy_file(file_list.get_file()); 4613151497Sru fclose(file_list.get_file()); 4614151497Sru 4615151497Sru file_list.move_next(); 4616151497Sru if (file_list.is_new_output_file()) { 4617151497Sru if (fragment_no > 1) 4618151497Sru write_navigation(top, prev, next, current); 4619151497Sru prev = current; 4620151497Sru current = next; 4621151497Sru next = file_list.next_file_name(); 4622151497Sru next += '\0'; 4623151497Sru string split_file = file_list.file_name(); 4624151497Sru split_file += '\0'; 4625151497Sru fflush(stdout); 4626151497Sru freopen(split_file.contents(), "w", stdout); 4627151497Sru fragment_no++; 4628151497Sru writeHeadMetaStyle(); 4629151497Sru write_navigation(top, prev, next, current); 4630151497Sru } 4631151497Sru if (file_list.are_links_required()) 4632151497Sru header.write_headings(stdout, TRUE); 4633151497Sru } 4634151497Sru if (fragment_no > 1) 4635151497Sru write_navigation(top, prev, next, current); 4636151497Sru else 4637151497Sru write_rule(); 4638151497Sru} 4639151497Sru 4640151497Sru/* 4641151497Sru * writeHeadMetaStyle - emits the <head> <meta> and <style> tags and 4642151497Sru * related information. 4643151497Sru */ 4644151497Sru 4645151497Sruvoid html_printer::writeHeadMetaStyle (void) 4646151497Sru{ 4647151497Sru fputs("<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n", stdout); 4648151497Sru fputs("\"http://www.w3.org/TR/html4/loose.dtd\">\n", stdout); 4649151497Sru 4650151497Sru fputs("<html>\n", stdout); 4651151497Sru fputs("<head>\n", stdout); 4652151497Sru fputs("<meta name=\"generator\" " 4653151497Sru "content=\"groff -Thtml, see www.gnu.org\">\n", stdout); 4654151497Sru fputs("<meta http-equiv=\"Content-Type\" " 4655151497Sru "content=\"text/html; charset=US-ASCII\">\n", stdout); 4656151497Sru fputs("<meta name=\"Content-Style\" content=\"text/css\">\n", stdout); 4657151497Sru 4658151497Sru fputs("<style type=\"text/css\">\n", stdout); 4659151497Sru fputs(" p { margin-top: 0; margin-bottom: 0; }\n", stdout); 4660151497Sru fputs(" pre { margin-top: 0; margin-bottom: 0; }\n", stdout); 4661151497Sru fputs(" table { margin-top: 0; margin-bottom: 0; }\n", stdout); 4662151497Sru fputs("</style>\n", stdout); 4663151497Sru} 4664151497Sru 4665114402Sruhtml_printer::~html_printer() 4666114402Sru{ 4667114402Sru#ifdef LONG_FOR_TIME_T 4668114402Sru long t; 4669114402Sru#else 4670114402Sru time_t t; 4671114402Sru#endif 4672114402Sru 4673114402Sru current_paragraph->flush_text(); 4674114402Sru html.end_line(); 4675114402Sru html.set_file(stdout); 4676114402Sru html.begin_comment("Creator : ") 4677114402Sru .put_string("groff ") 4678114402Sru .put_string("version ") 4679114402Sru .put_string(Version_string) 4680114402Sru .end_comment(); 4681114402Sru 4682114402Sru t = time(0); 4683114402Sru html.begin_comment("CreationDate: ") 4684114402Sru .put_string(ctime(&t), strlen(ctime(&t))-1) 4685114402Sru .end_comment(); 4686114402Sru 4687151497Sru writeHeadMetaStyle(); 4688114402Sru 4689114402Sru write_title(TRUE); 4690151497Sru head_info += '\0'; 4691151497Sru fputs(head_info.contents(), stdout); 4692114402Sru fputs("</head>\n", stdout); 4693114402Sru do_body(); 4694114402Sru 4695114402Sru write_title(FALSE); 4696114402Sru header.write_headings(stdout, FALSE); 4697114402Sru write_rule(); 4698114402Sru#if defined(DEBUGGING) 4699114402Sru html.begin_comment("Total number of pages: ").put_string(i_to_a(no_of_printed_pages)).end_comment(); 4700114402Sru#endif 4701114402Sru html.end_line(); 4702114402Sru html.end_line(); 4703151497Sru 4704151497Sru if (multiple_files) { 4705151497Sru fputs("</body>\n", stdout); 4706151497Sru fputs("</html>\n", stdout); 4707151497Sru do_file_components(); 4708151497Sru } else { 4709151497Sru do_file_components(); 4710151497Sru fputs("</body>\n", stdout); 4711151497Sru fputs("</html>\n", stdout); 4712114402Sru } 4713114402Sru} 4714114402Sru 4715114402Sru/* 4716151497Sru * get_str - returns a dupicate of string, s. The duplicate 4717151497Sru * string is terminated at the next ',' or ']'. 4718114402Sru */ 4719114402Sru 4720151497Srustatic char *get_str (const char *s, char **n) 4721151497Sru{ 4722151497Sru int i=0; 4723151497Sru char *v; 4724151497Sru 4725151497Sru while ((s[i] != (char)0) && (s[i] != ',') && (s[i] != ']')) 4726151497Sru i++; 4727151497Sru if (i>0) { 4728151497Sru v = new char[i+1]; 4729151497Sru memcpy(v, s, i+1); 4730151497Sru v[i] = (char)0; 4731151497Sru if (s[i] == ',') 4732151497Sru (*n) = (char *)&s[i+1]; 4733151497Sru else 4734151497Sru (*n) = (char *)&s[i]; 4735151497Sru return v; 4736151497Sru } 4737151497Sru if (s[i] == ',') 4738151497Sru (*n) = (char *)&s[1]; 4739151497Sru else 4740151497Sru (*n) = (char *)s; 4741151497Sru return NULL; 4742151497Sru} 4743151497Sru 4744151497Sru/* 4745151497Sru * make_val - creates a string from if s is NULL. 4746151497Sru */ 4747151497Sru 4748151497Sruchar *make_val (char *s, int v, char *id, char *f, char *l) 4749151497Sru{ 4750151497Sru if (s == NULL) { 4751151497Sru char buf[30]; 4752151497Sru 4753151497Sru sprintf(buf, "%d", v); 4754151497Sru return strsave(buf); 4755151497Sru } 4756151497Sru else { 4757151497Sru /* 4758151497Sru * check that value, s, is the same as, v. 4759151497Sru */ 4760151497Sru char *t = s; 4761151497Sru 4762151497Sru while (*t == '=') 4763151497Sru t++; 4764151497Sru if (atoi(t) != v) { 4765151497Sru if (f == NULL) 4766151497Sru f = (char *)"stdin"; 4767151497Sru if (l == NULL) 4768151497Sru l = (char *)"<none>"; 4769151497Sru fprintf(stderr, "%s:%s: grohtml assertion failed at id%s expecting %d and was given %s\n", 4770151497Sru f, l, id, v, s); 4771151497Sru } 4772151497Sru return s; 4773151497Sru } 4774151497Sru} 4775151497Sru 4776151497Sru/* 4777151497Sru * handle_assertion - handles the assertions created via .www:ASSERT 4778151497Sru * in www.tmac. See www.tmac for examples. 4779151497Sru * This method should be called as we are 4780151497Sru * parsing the ditroff input. It checks the x, y 4781151497Sru * position assertions. It does _not_ check the 4782151497Sru * troff state assertions as these are unknown at this 4783151497Sru * point. 4784151497Sru */ 4785151497Sru 4786151497Sruvoid html_printer::handle_assertion (int minv, int minh, int maxv, int maxh, const char *s) 4787151497Sru{ 4788151497Sru char *n; 4789151497Sru char *cmd = get_str(s, &n); 4790151497Sru char *id = get_str(n, &n); 4791151497Sru char *val = get_str(n, &n); 4792151497Sru char *file= get_str(n, &n); 4793151497Sru char *line= get_str(n, &n); 4794151497Sru 4795151497Sru if (strcmp(cmd, "assertion:[x") == 0) 4796151497Sru as.addx(cmd, id, make_val(val, minh, id, file, line), file, line); 4797151497Sru else if (strcmp(cmd, "assertion:[y") == 0) 4798151497Sru as.addy(cmd, id, make_val(val, minv, id, file, line), file, line); 4799151497Sru else 4800151497Sru if (strncmp(cmd, "assertion:[", strlen("assertion:[")) == 0) 4801151497Sru page_contents->add_tag(&sbuf_style, string(s), 4802151497Sru line_number, minv, minh, maxv, maxh); 4803151497Sru} 4804151497Sru 4805151497Sru/* 4806151497Sru * build_state_assertion - builds the troff state assertions. 4807151497Sru */ 4808151497Sru 4809151497Sruvoid html_printer::handle_state_assertion (text_glob *g) 4810151497Sru{ 4811151497Sru if (g != NULL && g->is_a_tag() && 4812151497Sru (strncmp(g->text_string, "assertion:[", 11) == 0)) { 4813151497Sru char *n = (char *)&g->text_string[11]; 4814151497Sru char *cmd = get_str(n, &n); 4815151497Sru char *val = get_str(n, &n); 4816151497Sru (void)get_str(n, &n); // unused 4817151497Sru char *file= get_str(n, &n); 4818151497Sru char *line= get_str(n, &n); 4819151497Sru 4820151497Sru as.build(cmd, val, file, line); 4821151497Sru } 4822151497Sru} 4823151497Sru 4824151497Sru/* 4825151497Sru * special - handle all x X requests from troff. For post-html they 4826151497Sru * allow users to pass raw html commands, turn auto linked 4827151497Sru * headings off/on etc. 4828151497Sru */ 4829151497Sru 4830114402Sruvoid html_printer::special(char *s, const environment *env, char type) 4831114402Sru{ 4832114402Sru if (type != 'p') 4833114402Sru return; 4834114402Sru if (s != 0) { 4835114402Sru flush_sbuf(); 4836114402Sru if (env->fontno >= 0) { 4837114402Sru style sty(get_font_from_index(env->fontno), env->size, env->height, 4838114402Sru env->slant, env->fontno, *env->col); 4839114402Sru sbuf_style = sty; 4840114402Sru } 4841114402Sru 4842114402Sru if (strncmp(s, "html:", 5) == 0) { 4843114402Sru int r=font::res; /* resolution of the device */ 4844114402Sru font *f=sbuf_style.f; 4845114402Sru 4846114402Sru if (f == NULL) { 4847114402Sru int found=FALSE; 4848114402Sru 4849114402Sru f = font::load_font("TR", &found); 4850114402Sru } 4851114402Sru 4852114402Sru /* 4853114402Sru * need to pass rest of string through to html output during flush 4854114402Sru */ 4855114402Sru page_contents->add_and_encode(&sbuf_style, string(&s[5]), 4856114402Sru line_number, 4857114402Sru env->vpos-env->size*r/72, env->hpos, 4858151497Sru env->vpos , env->hpos, 4859151497Sru FALSE); 4860114402Sru 4861114402Sru /* 4862151497Sru * assume that the html command has no width, if it does then 4863151497Sru * hopefully troff will have fudged this in a macro by 4864151497Sru * requesting that the formatting move right by the appropriate 4865151497Sru * amount. 4866114402Sru */ 4867151497Sru } else if (strncmp(s, "html</p>:", 9) == 0) { 4868151497Sru int r=font::res; /* resolution of the device */ 4869151497Sru font *f=sbuf_style.f; 4870151497Sru 4871151497Sru if (f == NULL) { 4872151497Sru int found=FALSE; 4873151497Sru 4874151497Sru f = font::load_font("TR", &found); 4875151497Sru } 4876151497Sru 4877151497Sru /* 4878151497Sru * need to pass all of string through to html output during flush 4879151497Sru */ 4880151497Sru page_contents->add_and_encode(&sbuf_style, string(s), 4881151497Sru line_number, 4882151497Sru env->vpos-env->size*r/72, env->hpos, 4883151497Sru env->vpos , env->hpos, 4884151497Sru TRUE); 4885151497Sru 4886151497Sru /* 4887151497Sru * assume that the html command has no width, if it does then 4888151497Sru * hopefully troff will have fudged this in a macro by 4889151497Sru * requesting that the formatting move right by the appropriate 4890151497Sru * amount. 4891151497Sru */ 4892114402Sru } else if (strncmp(s, "index:", 6) == 0) { 4893114402Sru cutoff_heading = atoi(&s[6]); 4894151497Sru } else if (strncmp(s, "assertion:[", 11) == 0) { 4895114402Sru int r=font::res; /* resolution of the device */ 4896114402Sru 4897151497Sru handle_assertion(env->vpos-env->size*r/72, env->hpos, 4898151497Sru env->vpos, env->hpos, s); 4899151497Sru } 4900151497Sru } 4901151497Sru} 4902151497Sru 4903151497Sru/* 4904151497Sru * devtag - handles device troff tags sent from the `troff'. 4905151497Sru * These include the troff state machine tags: 4906151497Sru * .br, .sp, .in, .tl, .ll etc 4907151497Sru * 4908151497Sru * (see man 5 grohtml_tags). 4909151497Sru */ 4910151497Sru 4911151497Sruvoid html_printer::devtag (char *s, const environment *env, char type) 4912151497Sru{ 4913151497Sru if (type != 'p') 4914151497Sru return; 4915151497Sru 4916151497Sru if (s != 0) { 4917151497Sru flush_sbuf(); 4918151497Sru if (env->fontno >= 0) { 4919151497Sru style sty(get_font_from_index(env->fontno), env->size, env->height, 4920151497Sru env->slant, env->fontno, *env->col); 4921151497Sru sbuf_style = sty; 4922151497Sru } 4923151497Sru 4924151497Sru if (strncmp(s, "devtag:", strlen("devtag:")) == 0) { 4925151497Sru int r=font::res; /* resolution of the device */ 4926151497Sru 4927114402Sru page_contents->add_tag(&sbuf_style, string(s), 4928114402Sru line_number, 4929114402Sru env->vpos-env->size*r/72, env->hpos, 4930114402Sru env->vpos , env->hpos); 4931114402Sru } 4932114402Sru } 4933114402Sru} 4934114402Sru 4935151497Sru 4936151497Sru/* 4937151497Sru * taken from number.cpp in src/roff/troff, [hunits::hunits(units x)] 4938151497Sru */ 4939151497Sru 4940151497Sruint html_printer::round_width(int x) 4941151497Sru{ 4942151497Sru int r = font::hor; 4943151497Sru int n; 4944151497Sru 4945151497Sru // don't depend on the rounding direction for division of negative integers 4946151497Sru if (r == 1) 4947151497Sru n = x; 4948151497Sru else 4949151497Sru n = (x < 0 4950151497Sru ? -((-x + r/2 - 1)/r) 4951151497Sru : (x + r/2 - 1)/r); 4952151497Sru return n * r; 4953151497Sru} 4954151497Sru 4955114402Sruint main(int argc, char **argv) 4956114402Sru{ 4957114402Sru program_name = argv[0]; 4958114402Sru static char stderr_buf[BUFSIZ]; 4959114402Sru setbuf(stderr, stderr_buf); 4960114402Sru int c; 4961114402Sru static const struct option long_options[] = { 4962114402Sru { "help", no_argument, 0, CHAR_MAX + 1 }, 4963114402Sru { "version", no_argument, 0, 'v' }, 4964114402Sru { NULL, 0, 0, 0 } 4965114402Sru }; 4966151497Sru while ((c = getopt_long(argc, argv, "a:bdD:F:g:hi:I:j:lno:prs:S:v", 4967151497Sru long_options, NULL)) 4968114402Sru != EOF) 4969114402Sru switch(c) { 4970114402Sru case 'a': 4971114402Sru /* text antialiasing bits - handled by pre-html */ 4972114402Sru break; 4973114402Sru case 'b': 4974114402Sru // set background color to white 4975114402Sru default_background = new color; 4976114402Sru default_background->set_gray(color::MAX_COLOR_VAL); 4977114402Sru break; 4978151497Sru case 'd': 4979151497Sru /* handled by pre-html */ 4980151497Sru break; 4981151497Sru case 'D': 4982151497Sru /* handled by pre-html */ 4983151497Sru break; 4984114402Sru case 'F': 4985114402Sru font::command_line_font_dir(optarg); 4986114402Sru break; 4987151497Sru case 'g': 4988151497Sru /* graphic antialiasing bits - handled by pre-html */ 4989114402Sru break; 4990114402Sru case 'h': 4991114402Sru /* do not use the Hn headings of html, but manufacture our own */ 4992114402Sru manufacture_headings = TRUE; 4993114402Sru break; 4994114402Sru case 'i': 4995114402Sru /* handled by pre-html */ 4996114402Sru break; 4997114402Sru case 'I': 4998114402Sru /* handled by pre-html */ 4999114402Sru break; 5000151497Sru case 'j': 5001151497Sru multiple_files = TRUE; 5002151497Sru job_name = optarg; 5003114402Sru break; 5004151497Sru case 'l': 5005151497Sru auto_links = FALSE; 5006151497Sru break; 5007114402Sru case 'n': 5008114402Sru simple_anchors = TRUE; 5009114402Sru break; 5010151497Sru case 'o': 5011151497Sru /* handled by pre-html */ 5012151497Sru break; 5013151497Sru case 'p': 5014151497Sru /* handled by pre-html */ 5015151497Sru break; 5016151497Sru case 'r': 5017151497Sru auto_rule = FALSE; 5018151497Sru break; 5019151497Sru case 's': 5020151497Sru base_point_size = atoi(optarg); 5021151497Sru break; 5022151497Sru case 'S': 5023151497Sru split_level = atoi(optarg) + 1; 5024151497Sru break; 5025151497Sru case 'v': 5026151497Sru printf("GNU post-grohtml (groff) version %s\n", Version_string); 5027151497Sru exit(0); 5028151497Sru break; 5029114402Sru case CHAR_MAX + 1: // --help 5030114402Sru usage(stdout); 5031114402Sru exit(0); 5032114402Sru break; 5033114402Sru case '?': 5034114402Sru usage(stderr); 5035114402Sru exit(1); 5036114402Sru break; 5037114402Sru default: 5038114402Sru assert(0); 5039114402Sru } 5040114402Sru if (optind >= argc) { 5041114402Sru do_file("-"); 5042114402Sru } else { 5043114402Sru for (int i = optind; i < argc; i++) 5044114402Sru do_file(argv[i]); 5045114402Sru } 5046114402Sru return 0; 5047114402Sru} 5048114402Sru 5049114402Srustatic void usage(FILE *stream) 5050114402Sru{ 5051114402Sru fprintf(stream, "usage: %s [-vblnh] [-D dir] [-I image_stem] [-F dir] [files ...]\n", 5052114402Sru program_name); 5053114402Sru} 5054