1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004 3114402Sru Free Software Foundation, Inc. 4114402Sru Written by James Clark (jjc@jclark.com) 5114402Sru 6114402SruThis file is part of groff. 7114402Sru 8114402Srugroff is free software; you can redistribute it and/or modify it under 9114402Sruthe terms of the GNU General Public License as published by the Free 10114402SruSoftware Foundation; either version 2, or (at your option) any later 11114402Sruversion. 12114402Sru 13114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16114402Srufor more details. 17114402Sru 18114402SruYou should have received a copy of the GNU General Public License along 19114402Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21114402Sru 22114402Sru/* 23114402Sru * PostScript documentation: 24114402Sru * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf 25114402Sru * http://partners.adobe.com/asn/developer/pdfs/tn/5001.DSC_Spec.pdf 26114402Sru */ 27114402Sru 28114402Sru#include "driver.h" 29114402Sru#include "stringclass.h" 30114402Sru#include "cset.h" 31114402Sru#include "nonposix.h" 32114402Sru#include "paper.h" 33114402Sru 34114402Sru#include "ps.h" 35114402Sru#include <time.h> 36114402Sru 37114402Sru#ifdef NEED_DECLARATION_PUTENV 38114402Sruextern "C" { 39114402Sru int putenv(const char *); 40114402Sru} 41114402Sru#endif /* NEED_DECLARATION_PUTENV */ 42114402Sru 43114402Sruextern "C" const char *Version_string; 44114402Sru 45151497Sru// search path defaults to the current directory 46151497Srusearch_path include_search_path(0, 0, 0, 1); 47151497Sru 48114402Srustatic int landscape_flag = 0; 49114402Srustatic int manual_feed_flag = 0; 50114402Srustatic int ncopies = 1; 51114402Srustatic int linewidth = -1; 52114402Sru// Non-zero means generate PostScript code that guesses the paper 53114402Sru// length using the imageable area. 54114402Srustatic int guess_flag = 0; 55114402Srustatic double user_paper_length = 0; 56114402Srustatic double user_paper_width = 0; 57114402Sru 58114402Sru// Non-zero if -b was specified on the command line. 59114402Srustatic int bflag = 0; 60114402Sruunsigned broken_flags = 0; 61114402Sru 62114402Sru// Non-zero means we need the CMYK extension for PostScript Level 1 63114402Srustatic int cmyk_flag = 0; 64114402Sru 65114402Sru#define DEFAULT_LINEWIDTH 40 /* in ems/1000 */ 66114402Sru#define MAX_LINE_LENGTH 72 67114402Sru#define FILL_MAX 1000 68114402Sru 69114402Sruconst char *const dict_name = "grops"; 70114402Sruconst char *const defs_dict_name = "DEFS"; 71114402Sruconst int DEFS_DICT_SPARE = 50; 72114402Sru 73114402Srudouble degrees(double r) 74114402Sru{ 75114402Sru return r*180.0/PI; 76114402Sru} 77114402Sru 78114402Srudouble radians(double d) 79114402Sru{ 80114402Sru return d*PI/180.0; 81114402Sru} 82114402Sru 83114402Sru// This is used for testing whether a character should be output in the 84114402Sru// PostScript file using \nnn, so we really want the character to be 85114402Sru// less than 0200. 86114402Sru 87114402Sruinline int is_ascii(char c) 88114402Sru{ 89114402Sru return (unsigned char)c < 0200; 90114402Sru} 91114402Sru 92114402Srups_output::ps_output(FILE *f, int n) 93114402Sru: fp(f), col(0), max_line_length(n), need_space(0), fixed_point(0) 94114402Sru{ 95114402Sru} 96114402Sru 97114402Srups_output &ps_output::set_file(FILE *f) 98114402Sru{ 99114402Sru fp = f; 100114402Sru col = 0; 101114402Sru return *this; 102114402Sru} 103114402Sru 104114402Srups_output &ps_output::copy_file(FILE *infp) 105114402Sru{ 106114402Sru int c; 107114402Sru while ((c = getc(infp)) != EOF) 108114402Sru putc(c, fp); 109114402Sru return *this; 110114402Sru} 111114402Sru 112114402Srups_output &ps_output::end_line() 113114402Sru{ 114114402Sru if (col != 0) { 115114402Sru putc('\n', fp); 116114402Sru col = 0; 117114402Sru need_space = 0; 118114402Sru } 119114402Sru return *this; 120114402Sru} 121114402Sru 122114402Srups_output &ps_output::special(const char *s) 123114402Sru{ 124114402Sru if (s == 0 || *s == '\0') 125114402Sru return *this; 126114402Sru if (col != 0) { 127114402Sru putc('\n', fp); 128114402Sru col = 0; 129114402Sru } 130114402Sru fputs(s, fp); 131114402Sru if (strchr(s, '\0')[-1] != '\n') 132114402Sru putc('\n', fp); 133114402Sru need_space = 0; 134114402Sru return *this; 135114402Sru} 136114402Sru 137114402Srups_output &ps_output::simple_comment(const char *s) 138114402Sru{ 139114402Sru if (col != 0) 140114402Sru putc('\n', fp); 141114402Sru putc('%', fp); 142114402Sru putc('%', fp); 143114402Sru fputs(s, fp); 144114402Sru putc('\n', fp); 145114402Sru col = 0; 146114402Sru need_space = 0; 147114402Sru return *this; 148114402Sru} 149114402Sru 150114402Srups_output &ps_output::begin_comment(const char *s) 151114402Sru{ 152114402Sru if (col != 0) 153114402Sru putc('\n', fp); 154114402Sru putc('%', fp); 155114402Sru putc('%', fp); 156114402Sru fputs(s, fp); 157114402Sru col = 2 + strlen(s); 158114402Sru return *this; 159114402Sru} 160114402Sru 161114402Srups_output &ps_output::end_comment() 162114402Sru{ 163114402Sru if (col != 0) { 164114402Sru putc('\n', fp); 165114402Sru col = 0; 166114402Sru } 167114402Sru need_space = 0; 168114402Sru return *this; 169114402Sru} 170114402Sru 171114402Srups_output &ps_output::comment_arg(const char *s) 172114402Sru{ 173114402Sru int len = strlen(s); 174114402Sru if (col + len + 1 > max_line_length) { 175114402Sru putc('\n', fp); 176114402Sru fputs("%%+", fp); 177114402Sru col = 3; 178114402Sru } 179114402Sru putc(' ', fp); 180114402Sru fputs(s, fp); 181114402Sru col += len + 1; 182114402Sru return *this; 183114402Sru} 184114402Sru 185114402Srups_output &ps_output::set_fixed_point(int n) 186114402Sru{ 187114402Sru assert(n >= 0 && n <= 10); 188114402Sru fixed_point = n; 189114402Sru return *this; 190114402Sru} 191114402Sru 192114402Srups_output &ps_output::put_delimiter(char c) 193114402Sru{ 194114402Sru if (col + 1 > max_line_length) { 195114402Sru putc('\n', fp); 196114402Sru col = 0; 197114402Sru } 198114402Sru putc(c, fp); 199114402Sru col++; 200114402Sru need_space = 0; 201114402Sru return *this; 202114402Sru} 203114402Sru 204114402Srups_output &ps_output::put_string(const char *s, int n) 205114402Sru{ 206114402Sru int len = 0; 207114402Sru int i; 208114402Sru for (i = 0; i < n; i++) { 209114402Sru char c = s[i]; 210114402Sru if (is_ascii(c) && csprint(c)) { 211114402Sru if (c == '(' || c == ')' || c == '\\') 212114402Sru len += 2; 213114402Sru else 214114402Sru len += 1; 215114402Sru } 216114402Sru else 217114402Sru len += 4; 218114402Sru } 219114402Sru if (len > n*2) { 220114402Sru if (col + n*2 + 2 > max_line_length && n*2 + 2 <= max_line_length) { 221114402Sru putc('\n', fp); 222114402Sru col = 0; 223114402Sru } 224114402Sru if (col + 1 > max_line_length) { 225114402Sru putc('\n', fp); 226114402Sru col = 0; 227114402Sru } 228114402Sru putc('<', fp); 229114402Sru col++; 230114402Sru for (i = 0; i < n; i++) { 231114402Sru if (col + 2 > max_line_length) { 232114402Sru putc('\n', fp); 233114402Sru col = 0; 234114402Sru } 235114402Sru fprintf(fp, "%02x", s[i] & 0377); 236114402Sru col += 2; 237114402Sru } 238114402Sru putc('>', fp); 239114402Sru col++; 240114402Sru } 241114402Sru else { 242114402Sru if (col + len + 2 > max_line_length && len + 2 <= max_line_length) { 243114402Sru putc('\n', fp); 244114402Sru col = 0; 245114402Sru } 246114402Sru if (col + 2 > max_line_length) { 247114402Sru putc('\n', fp); 248114402Sru col = 0; 249114402Sru } 250114402Sru putc('(', fp); 251114402Sru col++; 252114402Sru for (i = 0; i < n; i++) { 253114402Sru char c = s[i]; 254114402Sru if (is_ascii(c) && csprint(c)) { 255114402Sru if (c == '(' || c == ')' || c == '\\') 256114402Sru len = 2; 257114402Sru else 258114402Sru len = 1; 259114402Sru } 260114402Sru else 261114402Sru len = 4; 262114402Sru if (col + len + 1 > max_line_length) { 263114402Sru putc('\\', fp); 264114402Sru putc('\n', fp); 265114402Sru col = 0; 266114402Sru } 267114402Sru switch (len) { 268114402Sru case 1: 269114402Sru putc(c, fp); 270114402Sru break; 271114402Sru case 2: 272114402Sru putc('\\', fp); 273114402Sru putc(c, fp); 274114402Sru break; 275114402Sru case 4: 276114402Sru fprintf(fp, "\\%03o", c & 0377); 277114402Sru break; 278114402Sru default: 279114402Sru assert(0); 280114402Sru } 281114402Sru col += len; 282114402Sru } 283114402Sru putc(')', fp); 284114402Sru col++; 285114402Sru } 286114402Sru need_space = 0; 287114402Sru return *this; 288114402Sru} 289114402Sru 290114402Srups_output &ps_output::put_number(int n) 291114402Sru{ 292114402Sru char buf[1 + INT_DIGITS + 1]; 293114402Sru sprintf(buf, "%d", n); 294114402Sru int len = strlen(buf); 295114402Sru if (col > 0 && col + len + need_space > max_line_length) { 296114402Sru putc('\n', fp); 297114402Sru col = 0; 298114402Sru need_space = 0; 299114402Sru } 300114402Sru if (need_space) { 301114402Sru putc(' ', fp); 302114402Sru col++; 303114402Sru } 304114402Sru fputs(buf, fp); 305114402Sru col += len; 306114402Sru need_space = 1; 307114402Sru return *this; 308114402Sru} 309114402Sru 310114402Srups_output &ps_output::put_fix_number(int i) 311114402Sru{ 312114402Sru const char *p = if_to_a(i, fixed_point); 313114402Sru int len = strlen(p); 314114402Sru if (col > 0 && col + len + need_space > max_line_length) { 315114402Sru putc('\n', fp); 316114402Sru col = 0; 317114402Sru need_space = 0; 318114402Sru } 319114402Sru if (need_space) { 320114402Sru putc(' ', fp); 321114402Sru col++; 322114402Sru } 323114402Sru fputs(p, fp); 324114402Sru col += len; 325114402Sru need_space = 1; 326114402Sru return *this; 327114402Sru} 328114402Sru 329114402Srups_output &ps_output::put_float(double d) 330114402Sru{ 331114402Sru char buf[128]; 332151497Sru sprintf(buf, "%.4f", d); 333151497Sru int last = strlen(buf) - 1; 334151497Sru while (buf[last] == '0') 335151497Sru last--; 336151497Sru if (buf[last] == '.') 337151497Sru last--; 338151497Sru buf[++last] = '\0'; 339151497Sru if (col > 0 && col + last + need_space > max_line_length) { 340114402Sru putc('\n', fp); 341114402Sru col = 0; 342114402Sru need_space = 0; 343114402Sru } 344114402Sru if (need_space) { 345114402Sru putc(' ', fp); 346114402Sru col++; 347114402Sru } 348114402Sru fputs(buf, fp); 349151497Sru col += last; 350114402Sru need_space = 1; 351114402Sru return *this; 352114402Sru} 353114402Sru 354114402Srups_output &ps_output::put_symbol(const char *s) 355114402Sru{ 356114402Sru int len = strlen(s); 357114402Sru if (col > 0 && col + len + need_space > max_line_length) { 358114402Sru putc('\n', fp); 359114402Sru col = 0; 360114402Sru need_space = 0; 361114402Sru } 362114402Sru if (need_space) { 363114402Sru putc(' ', fp); 364114402Sru col++; 365114402Sru } 366114402Sru fputs(s, fp); 367114402Sru col += len; 368114402Sru need_space = 1; 369114402Sru return *this; 370114402Sru} 371114402Sru 372114402Srups_output &ps_output::put_color(unsigned int c) 373114402Sru{ 374114402Sru char buf[128]; 375114402Sru sprintf(buf, "%.3g", double(c) / color::MAX_COLOR_VAL); 376114402Sru int len = strlen(buf); 377114402Sru if (col > 0 && col + len + need_space > max_line_length) { 378114402Sru putc('\n', fp); 379114402Sru col = 0; 380114402Sru need_space = 0; 381114402Sru } 382114402Sru if (need_space) { 383114402Sru putc(' ', fp); 384114402Sru col++; 385114402Sru } 386114402Sru fputs(buf, fp); 387114402Sru col += len; 388114402Sru need_space = 1; 389114402Sru return *this; 390114402Sru} 391114402Sru 392114402Srups_output &ps_output::put_literal_symbol(const char *s) 393114402Sru{ 394114402Sru int len = strlen(s); 395114402Sru if (col > 0 && col + len + 1 > max_line_length) { 396114402Sru putc('\n', fp); 397114402Sru col = 0; 398114402Sru } 399114402Sru putc('/', fp); 400114402Sru fputs(s, fp); 401114402Sru col += len + 1; 402114402Sru need_space = 1; 403114402Sru return *this; 404114402Sru} 405114402Sru 406114402Sruclass ps_font : public font { 407114402Sru ps_font(const char *); 408114402Srupublic: 409114402Sru int encoding_index; 410114402Sru char *encoding; 411114402Sru char *reencoded_name; 412114402Sru ~ps_font(); 413114402Sru void handle_unknown_font_command(const char *command, const char *arg, 414114402Sru const char *filename, int lineno); 415114402Sru static ps_font *load_ps_font(const char *); 416114402Sru}; 417114402Sru 418114402Srups_font *ps_font::load_ps_font(const char *s) 419114402Sru{ 420114402Sru ps_font *f = new ps_font(s); 421114402Sru if (!f->load()) { 422114402Sru delete f; 423114402Sru return 0; 424114402Sru } 425114402Sru return f; 426114402Sru} 427114402Sru 428114402Srups_font::ps_font(const char *nm) 429114402Sru: font(nm), encoding_index(-1), encoding(0), reencoded_name(0) 430114402Sru{ 431114402Sru} 432114402Sru 433114402Srups_font::~ps_font() 434114402Sru{ 435114402Sru a_delete encoding; 436114402Sru a_delete reencoded_name; 437114402Sru} 438114402Sru 439114402Sruvoid ps_font::handle_unknown_font_command(const char *command, const char *arg, 440114402Sru const char *filename, int lineno) 441114402Sru{ 442114402Sru if (strcmp(command, "encoding") == 0) { 443114402Sru if (arg == 0) 444114402Sru error_with_file_and_line(filename, lineno, 445114402Sru "`encoding' command requires an argument"); 446114402Sru else 447114402Sru encoding = strsave(arg); 448114402Sru } 449114402Sru} 450114402Sru 451114402Srustatic void handle_unknown_desc_command(const char *command, const char *arg, 452114402Sru const char *filename, int lineno) 453114402Sru{ 454114402Sru if (strcmp(command, "broken") == 0) { 455114402Sru if (arg == 0) 456114402Sru error_with_file_and_line(filename, lineno, 457114402Sru "`broken' command requires an argument"); 458114402Sru else if (!bflag) 459114402Sru broken_flags = atoi(arg); 460114402Sru } 461114402Sru} 462114402Sru 463114402Srustruct subencoding { 464114402Sru font *p; 465114402Sru unsigned int num; 466114402Sru int idx; 467114402Sru char *subfont; 468114402Sru const char *glyphs[256]; 469114402Sru subencoding *next; 470114402Sru 471114402Sru subencoding(font *, unsigned int, int, subencoding *); 472114402Sru ~subencoding(); 473114402Sru}; 474114402Sru 475114402Srusubencoding::subencoding(font *f, unsigned int n, int ix, subencoding *s) 476114402Sru: p(f), num(n), idx(ix), subfont(0), next(s) 477114402Sru{ 478114402Sru for (int i = 0; i < 256; i++) 479114402Sru glyphs[i] = 0; 480114402Sru} 481114402Sru 482114402Srusubencoding::~subencoding() 483114402Sru{ 484114402Sru a_delete subfont; 485114402Sru} 486114402Sru 487114402Srustruct style { 488114402Sru font *f; 489114402Sru subencoding *sub; 490114402Sru int point_size; 491114402Sru int height; 492114402Sru int slant; 493114402Sru style(); 494114402Sru style(font *, subencoding *, int, int, int); 495114402Sru int operator==(const style &) const; 496114402Sru int operator!=(const style &) const; 497114402Sru}; 498114402Sru 499114402Srustyle::style() : f(0) 500114402Sru{ 501114402Sru} 502114402Sru 503114402Srustyle::style(font *p, subencoding *s, int sz, int h, int sl) 504114402Sru: f(p), sub(s), point_size(sz), height(h), slant(sl) 505114402Sru{ 506114402Sru} 507114402Sru 508114402Sruint style::operator==(const style &s) const 509114402Sru{ 510114402Sru return (f == s.f 511114402Sru && sub == s.sub 512114402Sru && point_size == s.point_size 513114402Sru && height == s.height 514114402Sru && slant == s.slant); 515114402Sru} 516114402Sru 517114402Sruint style::operator!=(const style &s) const 518114402Sru{ 519114402Sru return !(*this == s); 520114402Sru} 521114402Sru 522114402Sruclass ps_printer : public printer { 523114402Sru FILE *tempfp; 524114402Sru ps_output out; 525114402Sru int res; 526114402Sru int space_char_index; 527114402Sru int pages_output; 528114402Sru int paper_length; 529114402Sru int equalise_spaces; 530114402Sru enum { SBUF_SIZE = 256 }; 531114402Sru char sbuf[SBUF_SIZE]; 532114402Sru int sbuf_len; 533114402Sru int sbuf_start_hpos; 534114402Sru int sbuf_vpos; 535114402Sru int sbuf_end_hpos; 536114402Sru int sbuf_space_width; 537114402Sru int sbuf_space_count; 538114402Sru int sbuf_space_diff_count; 539114402Sru int sbuf_space_code; 540114402Sru int sbuf_kern; 541114402Sru style sbuf_style; 542114402Sru color sbuf_color; // the current PS color 543114402Sru style output_style; 544114402Sru subencoding *subencodings; 545114402Sru int output_hpos; 546114402Sru int output_vpos; 547114402Sru int output_draw_point_size; 548114402Sru int line_thickness; 549114402Sru int output_line_thickness; 550114402Sru unsigned char output_space_code; 551114402Sru enum { MAX_DEFINED_STYLES = 50 }; 552114402Sru style defined_styles[MAX_DEFINED_STYLES]; 553114402Sru int ndefined_styles; 554114402Sru int next_encoding_index; 555114402Sru int next_subencoding_index; 556114402Sru string defs; 557114402Sru int ndefs; 558114402Sru resource_manager rm; 559114402Sru int invis_count; 560114402Sru 561114402Sru void flush_sbuf(); 562114402Sru void set_style(const style &); 563114402Sru void set_space_code(unsigned char c); 564114402Sru int set_encoding_index(ps_font *); 565114402Sru subencoding *set_subencoding(font *, int, unsigned char *); 566114402Sru char *get_subfont(subencoding *, const char *); 567114402Sru void do_exec(char *, const environment *); 568114402Sru void do_import(char *, const environment *); 569114402Sru void do_def(char *, const environment *); 570114402Sru void do_mdef(char *, const environment *); 571114402Sru void do_file(char *, const environment *); 572114402Sru void do_invis(char *, const environment *); 573114402Sru void do_endinvis(char *, const environment *); 574114402Sru void set_line_thickness_and_color(const environment *); 575114402Sru void fill_path(const environment *); 576114402Sru void encode_fonts(); 577114402Sru void encode_subfont(subencoding *); 578114402Sru void define_encoding(const char *, int); 579114402Sru void reencode_font(ps_font *); 580114402Sru void set_color(color *c, int fill = 0); 581114402Sru 582114402Sru const char *media_name(); 583114402Sru int media_width(); 584114402Sru int media_height(); 585114402Sru void media_set(); 586114402Sru 587114402Srupublic: 588114402Sru ps_printer(double); 589114402Sru ~ps_printer(); 590114402Sru void set_char(int i, font *f, const environment *env, int w, 591114402Sru const char *name); 592114402Sru void draw(int code, int *p, int np, const environment *env); 593114402Sru void begin_page(int); 594114402Sru void end_page(int); 595114402Sru void special(char *arg, const environment *env, char type); 596114402Sru font *make_font(const char *); 597114402Sru void end_of_line(); 598114402Sru}; 599114402Sru 600114402Sru// `pl' is in inches 601114402Srups_printer::ps_printer(double pl) 602114402Sru: out(0, MAX_LINE_LENGTH), 603114402Sru pages_output(0), 604114402Sru sbuf_len(0), 605114402Sru subencodings(0), 606114402Sru output_hpos(-1), 607114402Sru output_vpos(-1), 608114402Sru line_thickness(-1), 609114402Sru ndefined_styles(0), 610114402Sru next_encoding_index(0), 611114402Sru next_subencoding_index(0), 612114402Sru ndefs(0), 613114402Sru invis_count(0) 614114402Sru{ 615114402Sru tempfp = xtmpfile(); 616114402Sru out.set_file(tempfp); 617114402Sru if (linewidth < 0) 618114402Sru linewidth = DEFAULT_LINEWIDTH; 619114402Sru if (font::hor != 1) 620114402Sru fatal("horizontal resolution must be 1"); 621114402Sru if (font::vert != 1) 622114402Sru fatal("vertical resolution must be 1"); 623114402Sru if (font::res % (font::sizescale*72) != 0) 624114402Sru fatal("res must be a multiple of 72*sizescale"); 625114402Sru int r = font::res; 626114402Sru int point = 0; 627114402Sru while (r % 10 == 0) { 628114402Sru r /= 10; 629114402Sru point++; 630114402Sru } 631114402Sru res = r; 632114402Sru out.set_fixed_point(point); 633114402Sru space_char_index = font::name_to_index("space"); 634114402Sru if (pl == 0) 635114402Sru paper_length = font::paperlength; 636114402Sru else 637114402Sru paper_length = int(pl * font::res + 0.5); 638114402Sru if (paper_length == 0) 639114402Sru paper_length = 11 * font::res; 640114402Sru equalise_spaces = font::res >= 72000; 641114402Sru} 642114402Sru 643114402Sruint ps_printer::set_encoding_index(ps_font *f) 644114402Sru{ 645114402Sru if (f->encoding_index >= 0) 646114402Sru return f->encoding_index; 647114402Sru for (font_pointer_list *p = font_list; p; p = p->next) 648114402Sru if (p->p != f) { 649114402Sru char *encoding = ((ps_font *)p->p)->encoding; 650114402Sru int encoding_index = ((ps_font *)p->p)->encoding_index; 651114402Sru if (encoding != 0 && encoding_index >= 0 652114402Sru && strcmp(f->encoding, encoding) == 0) { 653114402Sru return f->encoding_index = encoding_index; 654114402Sru } 655114402Sru } 656114402Sru return f->encoding_index = next_encoding_index++; 657114402Sru} 658114402Sru 659114402Srusubencoding *ps_printer::set_subencoding(font *f, int i, unsigned char *codep) 660114402Sru{ 661114402Sru unsigned int idx = f->get_code(i); 662114402Sru *codep = idx % 256; 663114402Sru unsigned int num = idx >> 8; 664114402Sru if (num == 0) 665114402Sru return 0; 666114402Sru subencoding *p = 0; 667114402Sru for (p = subencodings; p; p = p->next) 668114402Sru if (p->p == f && p->num == num) 669114402Sru break; 670114402Sru if (p == 0) 671114402Sru p = subencodings = new subencoding(f, num, next_subencoding_index++, 672114402Sru subencodings); 673114402Sru p->glyphs[*codep] = f->get_special_device_encoding(i); 674114402Sru return p; 675114402Sru} 676114402Sru 677114402Sruchar *ps_printer::get_subfont(subencoding *sub, const char *stem) 678114402Sru{ 679114402Sru assert(sub != 0); 680114402Sru if (!sub->subfont) { 681114402Sru char *tem = new char[strlen(stem) + 2 + INT_DIGITS + 1]; 682114402Sru sprintf(tem, "%s@@%d", stem, next_subencoding_index); 683114402Sru sub->subfont = tem; 684114402Sru } 685114402Sru return sub->subfont; 686114402Sru} 687114402Sru 688114402Sruvoid ps_printer::set_char(int i, font *f, const environment *env, int w, 689114402Sru const char *) 690114402Sru{ 691114402Sru if (i == space_char_index || invis_count > 0) 692114402Sru return; 693114402Sru unsigned char code; 694114402Sru subencoding *sub = set_subencoding(f, i, &code); 695114402Sru style sty(f, sub, env->size, env->height, env->slant); 696114402Sru if (sty.slant != 0) { 697114402Sru if (sty.slant > 80 || sty.slant < -80) { 698114402Sru error("silly slant `%1' degrees", sty.slant); 699114402Sru sty.slant = 0; 700114402Sru } 701114402Sru } 702114402Sru if (sbuf_len > 0) { 703114402Sru if (sbuf_len < SBUF_SIZE 704114402Sru && sty == sbuf_style 705114402Sru && sbuf_vpos == env->vpos 706114402Sru && sbuf_color == *env->col) { 707114402Sru if (sbuf_end_hpos == env->hpos) { 708114402Sru sbuf[sbuf_len++] = code; 709114402Sru sbuf_end_hpos += w + sbuf_kern; 710114402Sru return; 711114402Sru } 712114402Sru if (sbuf_len == 1 && sbuf_kern == 0) { 713114402Sru sbuf_kern = env->hpos - sbuf_end_hpos; 714114402Sru sbuf_end_hpos = env->hpos + sbuf_kern + w; 715114402Sru sbuf[sbuf_len++] = code; 716114402Sru return; 717114402Sru } 718114402Sru /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off 719114402Sru starting a new string. */ 720114402Sru if (sbuf_len < SBUF_SIZE - 1 && env->hpos >= sbuf_end_hpos 721114402Sru && (sbuf_kern == 0 || sbuf_end_hpos - sbuf_kern != env->hpos)) { 722114402Sru if (sbuf_space_code < 0) { 723114402Sru if (f->contains(space_char_index)) { 724114402Sru sbuf_space_code = f->get_code(space_char_index); 725114402Sru sbuf_space_width = env->hpos - sbuf_end_hpos; 726114402Sru sbuf_end_hpos = env->hpos + w + sbuf_kern; 727114402Sru sbuf[sbuf_len++] = sbuf_space_code; 728114402Sru sbuf[sbuf_len++] = code; 729114402Sru sbuf_space_count++; 730114402Sru return; 731114402Sru } 732114402Sru } 733114402Sru else { 734114402Sru int diff = env->hpos - sbuf_end_hpos - sbuf_space_width; 735114402Sru if (diff == 0 || (equalise_spaces && (diff == 1 || diff == -1))) { 736114402Sru sbuf_end_hpos = env->hpos + w + sbuf_kern; 737114402Sru sbuf[sbuf_len++] = sbuf_space_code; 738114402Sru sbuf[sbuf_len++] = code; 739114402Sru sbuf_space_count++; 740114402Sru if (diff == 1) 741114402Sru sbuf_space_diff_count++; 742114402Sru else if (diff == -1) 743114402Sru sbuf_space_diff_count--; 744114402Sru return; 745114402Sru } 746114402Sru } 747114402Sru } 748114402Sru } 749114402Sru flush_sbuf(); 750114402Sru } 751114402Sru sbuf_len = 1; 752114402Sru sbuf[0] = code; 753114402Sru sbuf_end_hpos = env->hpos + w; 754114402Sru sbuf_start_hpos = env->hpos; 755114402Sru sbuf_vpos = env->vpos; 756114402Sru sbuf_style = sty; 757114402Sru sbuf_space_code = -1; 758114402Sru sbuf_space_width = 0; 759114402Sru sbuf_space_count = sbuf_space_diff_count = 0; 760114402Sru sbuf_kern = 0; 761114402Sru if (sbuf_color != *env->col) 762114402Sru set_color(env->col); 763114402Sru} 764114402Sru 765114402Srustatic char *make_encoding_name(int encoding_index) 766114402Sru{ 767114402Sru static char buf[3 + INT_DIGITS + 1]; 768114402Sru sprintf(buf, "ENC%d", encoding_index); 769114402Sru return buf; 770114402Sru} 771114402Sru 772114402Srustatic char *make_subencoding_name(int subencoding_index) 773114402Sru{ 774114402Sru static char buf[6 + INT_DIGITS + 1]; 775114402Sru sprintf(buf, "SUBENC%d", subencoding_index); 776114402Sru return buf; 777114402Sru} 778114402Sru 779114402Sruconst char *const WS = " \t\n\r"; 780114402Sru 781114402Sruvoid ps_printer::define_encoding(const char *encoding, int encoding_index) 782114402Sru{ 783114402Sru char *vec[256]; 784114402Sru int i; 785114402Sru for (i = 0; i < 256; i++) 786114402Sru vec[i] = 0; 787114402Sru char *path; 788114402Sru FILE *fp = font::open_file(encoding, &path); 789114402Sru if (fp == 0) 790114402Sru fatal("can't open encoding file `%1'", encoding); 791114402Sru int lineno = 1; 792114402Sru const int BUFFER_SIZE = 512; 793114402Sru char buf[BUFFER_SIZE]; 794114402Sru while (fgets(buf, BUFFER_SIZE, fp) != 0) { 795114402Sru char *p = buf; 796114402Sru while (csspace(*p)) 797114402Sru p++; 798114402Sru if (*p != '#' && *p != '\0' && (p = strtok(buf, WS)) != 0) { 799114402Sru char *q = strtok(0, WS); 800151497Sru int n = 0; // pacify compiler 801114402Sru if (q == 0 || sscanf(q, "%d", &n) != 1 || n < 0 || n >= 256) 802114402Sru fatal_with_file_and_line(path, lineno, "bad second field"); 803114402Sru vec[n] = new char[strlen(p) + 1]; 804114402Sru strcpy(vec[n], p); 805114402Sru } 806114402Sru lineno++; 807114402Sru } 808114402Sru a_delete path; 809114402Sru out.put_literal_symbol(make_encoding_name(encoding_index)) 810114402Sru .put_delimiter('['); 811114402Sru for (i = 0; i < 256; i++) { 812114402Sru if (vec[i] == 0) 813114402Sru out.put_literal_symbol(".notdef"); 814114402Sru else { 815114402Sru out.put_literal_symbol(vec[i]); 816114402Sru a_delete vec[i]; 817114402Sru } 818114402Sru } 819114402Sru out.put_delimiter(']') 820114402Sru .put_symbol("def"); 821114402Sru fclose(fp); 822114402Sru} 823114402Sru 824114402Sruvoid ps_printer::reencode_font(ps_font *f) 825114402Sru{ 826114402Sru out.put_literal_symbol(f->reencoded_name) 827114402Sru .put_symbol(make_encoding_name(f->encoding_index)) 828114402Sru .put_literal_symbol(f->get_internal_name()) 829114402Sru .put_symbol("RE"); 830114402Sru} 831114402Sru 832114402Sruvoid ps_printer::encode_fonts() 833114402Sru{ 834114402Sru if (next_encoding_index == 0) 835114402Sru return; 836114402Sru char *done_encoding = new char[next_encoding_index]; 837114402Sru for (int i = 0; i < next_encoding_index; i++) 838114402Sru done_encoding[i] = 0; 839114402Sru for (font_pointer_list *f = font_list; f; f = f->next) { 840114402Sru int encoding_index = ((ps_font *)f->p)->encoding_index; 841114402Sru if (encoding_index >= 0) { 842114402Sru assert(encoding_index < next_encoding_index); 843114402Sru if (!done_encoding[encoding_index]) { 844114402Sru done_encoding[encoding_index] = 1; 845114402Sru define_encoding(((ps_font *)f->p)->encoding, encoding_index); 846114402Sru } 847114402Sru reencode_font((ps_font *)f->p); 848114402Sru } 849114402Sru } 850114402Sru a_delete done_encoding; 851114402Sru} 852114402Sru 853114402Sruvoid ps_printer::encode_subfont(subencoding *sub) 854114402Sru{ 855114402Sru assert(sub->glyphs != 0); 856114402Sru out.put_literal_symbol(make_subencoding_name(sub->idx)) 857114402Sru .put_delimiter('['); 858114402Sru for (int i = 0; i < 256; i++) 859114402Sru { 860114402Sru if (sub->glyphs[i]) 861114402Sru out.put_literal_symbol(sub->glyphs[i]); 862114402Sru else 863114402Sru out.put_literal_symbol(".notdef"); 864114402Sru } 865114402Sru out.put_delimiter(']') 866114402Sru .put_symbol("def"); 867114402Sru} 868114402Sru 869114402Sruvoid ps_printer::set_style(const style &sty) 870114402Sru{ 871114402Sru char buf[1 + INT_DIGITS + 1]; 872114402Sru for (int i = 0; i < ndefined_styles; i++) 873114402Sru if (sty == defined_styles[i]) { 874114402Sru sprintf(buf, "F%d", i); 875114402Sru out.put_symbol(buf); 876114402Sru return; 877114402Sru } 878114402Sru if (ndefined_styles >= MAX_DEFINED_STYLES) 879114402Sru ndefined_styles = 0; 880114402Sru sprintf(buf, "F%d", ndefined_styles); 881114402Sru out.put_literal_symbol(buf); 882114402Sru const char *psname = sty.f->get_internal_name(); 883114402Sru if (psname == 0) 884114402Sru fatal("no internalname specified for font `%1'", sty.f->get_name()); 885114402Sru char *encoding = ((ps_font *)sty.f)->encoding; 886114402Sru if (sty.sub == 0) { 887114402Sru if (encoding != 0) { 888114402Sru char *s = ((ps_font *)sty.f)->reencoded_name; 889114402Sru if (s == 0) { 890114402Sru int ei = set_encoding_index((ps_font *)sty.f); 891114402Sru char *tem = new char[strlen(psname) + 1 + INT_DIGITS + 1]; 892114402Sru sprintf(tem, "%s@%d", psname, ei); 893114402Sru psname = tem; 894114402Sru ((ps_font *)sty.f)->reencoded_name = tem; 895114402Sru } 896114402Sru else 897114402Sru psname = s; 898114402Sru } 899114402Sru } 900114402Sru else 901114402Sru psname = get_subfont(sty.sub, psname); 902114402Sru out.put_fix_number((font::res/(72*font::sizescale))*sty.point_size); 903114402Sru if (sty.height != 0 || sty.slant != 0) { 904114402Sru int h = sty.height == 0 ? sty.point_size : sty.height; 905114402Sru h *= font::res/(72*font::sizescale); 906114402Sru int c = int(h*tan(radians(sty.slant)) + .5); 907114402Sru out.put_fix_number(c) 908114402Sru .put_fix_number(h) 909114402Sru .put_literal_symbol(psname) 910114402Sru .put_symbol("MF"); 911114402Sru } 912114402Sru else { 913114402Sru out.put_literal_symbol(psname) 914114402Sru .put_symbol("SF"); 915114402Sru } 916114402Sru defined_styles[ndefined_styles++] = sty; 917114402Sru} 918114402Sru 919114402Sruvoid ps_printer::set_color(color *col, int fill) 920114402Sru{ 921114402Sru sbuf_color = *col; 922114402Sru unsigned int components[4]; 923114402Sru char s[3]; 924114402Sru color_scheme cs = col->get_components(components); 925114402Sru s[0] = fill ? 'F' : 'C'; 926114402Sru s[2] = 0; 927114402Sru switch (cs) { 928114402Sru case DEFAULT: // black 929114402Sru out.put_symbol("0"); 930114402Sru s[1] = 'g'; 931114402Sru break; 932114402Sru case RGB: 933114402Sru out.put_color(Red) 934114402Sru .put_color(Green) 935114402Sru .put_color(Blue); 936114402Sru s[1] = 'r'; 937114402Sru break; 938114402Sru case CMY: 939114402Sru col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); 940114402Sru // fall through 941114402Sru case CMYK: 942114402Sru out.put_color(Cyan) 943114402Sru .put_color(Magenta) 944114402Sru .put_color(Yellow) 945114402Sru .put_color(Black); 946114402Sru s[1] = 'k'; 947114402Sru cmyk_flag = 1; 948114402Sru break; 949114402Sru case GRAY: 950114402Sru out.put_color(Gray); 951114402Sru s[1] = 'g'; 952114402Sru break; 953114402Sru } 954114402Sru out.put_symbol(s); 955114402Sru} 956114402Sru 957114402Sruvoid ps_printer::set_space_code(unsigned char c) 958114402Sru{ 959114402Sru out.put_literal_symbol("SC") 960114402Sru .put_number(c) 961114402Sru .put_symbol("def"); 962114402Sru} 963114402Sru 964114402Sruvoid ps_printer::end_of_line() 965114402Sru{ 966114402Sru flush_sbuf(); 967114402Sru // this ensures that we do an absolute motion to the beginning of a line 968114402Sru output_vpos = output_hpos = -1; 969114402Sru} 970114402Sru 971114402Sruvoid ps_printer::flush_sbuf() 972114402Sru{ 973114402Sru enum { 974114402Sru NONE, 975114402Sru RELATIVE_H, 976114402Sru RELATIVE_V, 977114402Sru RELATIVE_HV, 978114402Sru ABSOLUTE 979114402Sru } motion = NONE; 980114402Sru int space_flag = 0; 981114402Sru if (sbuf_len == 0) 982114402Sru return; 983114402Sru if (output_style != sbuf_style) { 984114402Sru set_style(sbuf_style); 985114402Sru output_style = sbuf_style; 986114402Sru } 987114402Sru int extra_space = 0; 988114402Sru if (output_hpos < 0 || output_vpos < 0) 989114402Sru motion = ABSOLUTE; 990114402Sru else { 991114402Sru if (output_hpos != sbuf_start_hpos) 992114402Sru motion = RELATIVE_H; 993114402Sru if (output_vpos != sbuf_vpos) { 994114402Sru if (motion != NONE) 995114402Sru motion = RELATIVE_HV; 996114402Sru else 997114402Sru motion = RELATIVE_V; 998114402Sru } 999114402Sru } 1000114402Sru if (sbuf_space_code >= 0) { 1001114402Sru int w = sbuf_style.f->get_width(space_char_index, sbuf_style.point_size); 1002114402Sru if (w + sbuf_kern != sbuf_space_width) { 1003114402Sru if (sbuf_space_code != output_space_code) { 1004114402Sru set_space_code(sbuf_space_code); 1005114402Sru output_space_code = sbuf_space_code; 1006114402Sru } 1007114402Sru space_flag = 1; 1008114402Sru extra_space = sbuf_space_width - w - sbuf_kern; 1009114402Sru if (sbuf_space_diff_count > sbuf_space_count/2) 1010114402Sru extra_space++; 1011114402Sru else if (sbuf_space_diff_count < -(sbuf_space_count/2)) 1012114402Sru extra_space--; 1013114402Sru } 1014114402Sru } 1015114402Sru if (space_flag) 1016114402Sru out.put_fix_number(extra_space); 1017114402Sru if (sbuf_kern != 0) 1018114402Sru out.put_fix_number(sbuf_kern); 1019114402Sru out.put_string(sbuf, sbuf_len); 1020114402Sru char command_array[] = {'A', 'B', 'C', 'D', 1021114402Sru 'E', 'F', 'G', 'H', 1022114402Sru 'I', 'J', 'K', 'L', 1023114402Sru 'M', 'N', 'O', 'P', 1024114402Sru 'Q', 'R', 'S', 'T'}; 1025114402Sru char sym[2]; 1026114402Sru sym[0] = command_array[motion*4 + space_flag + 2*(sbuf_kern != 0)]; 1027114402Sru sym[1] = '\0'; 1028114402Sru switch (motion) { 1029114402Sru case NONE: 1030114402Sru break; 1031114402Sru case ABSOLUTE: 1032114402Sru out.put_fix_number(sbuf_start_hpos) 1033114402Sru .put_fix_number(sbuf_vpos); 1034114402Sru break; 1035114402Sru case RELATIVE_H: 1036114402Sru out.put_fix_number(sbuf_start_hpos - output_hpos); 1037114402Sru break; 1038114402Sru case RELATIVE_V: 1039114402Sru out.put_fix_number(sbuf_vpos - output_vpos); 1040114402Sru break; 1041114402Sru case RELATIVE_HV: 1042114402Sru out.put_fix_number(sbuf_start_hpos - output_hpos) 1043114402Sru .put_fix_number(sbuf_vpos - output_vpos); 1044114402Sru break; 1045114402Sru default: 1046114402Sru assert(0); 1047114402Sru } 1048114402Sru out.put_symbol(sym); 1049114402Sru output_hpos = sbuf_end_hpos; 1050114402Sru output_vpos = sbuf_vpos; 1051114402Sru sbuf_len = 0; 1052114402Sru} 1053114402Sru 1054114402Sruvoid ps_printer::set_line_thickness_and_color(const environment *env) 1055114402Sru{ 1056114402Sru if (line_thickness < 0) { 1057114402Sru if (output_draw_point_size != env->size) { 1058114402Sru // we ought to check for overflow here 1059114402Sru int lw = ((font::res/(72*font::sizescale))*linewidth*env->size)/1000; 1060114402Sru out.put_fix_number(lw) 1061114402Sru .put_symbol("LW"); 1062114402Sru output_draw_point_size = env->size; 1063114402Sru output_line_thickness = -1; 1064114402Sru } 1065114402Sru } 1066114402Sru else { 1067114402Sru if (output_line_thickness != line_thickness) { 1068114402Sru out.put_fix_number(line_thickness) 1069114402Sru .put_symbol("LW"); 1070114402Sru output_line_thickness = line_thickness; 1071114402Sru output_draw_point_size = -1; 1072114402Sru } 1073114402Sru } 1074114402Sru if (sbuf_color != *env->col) 1075114402Sru set_color(env->col); 1076114402Sru} 1077114402Sru 1078114402Sruvoid ps_printer::fill_path(const environment *env) 1079114402Sru{ 1080114402Sru if (sbuf_color == *env->fill) 1081114402Sru out.put_symbol("FL"); 1082114402Sru else 1083114402Sru set_color(env->fill, 1); 1084114402Sru} 1085114402Sru 1086114402Sruvoid ps_printer::draw(int code, int *p, int np, const environment *env) 1087114402Sru{ 1088114402Sru if (invis_count > 0) 1089114402Sru return; 1090114402Sru flush_sbuf(); 1091114402Sru int fill_flag = 0; 1092114402Sru switch (code) { 1093114402Sru case 'C': 1094114402Sru fill_flag = 1; 1095114402Sru // fall through 1096114402Sru case 'c': 1097114402Sru // troff adds an extra argument to C 1098114402Sru if (np != 1 && !(code == 'C' && np == 2)) { 1099114402Sru error("1 argument required for circle"); 1100114402Sru break; 1101114402Sru } 1102114402Sru out.put_fix_number(env->hpos + p[0]/2) 1103114402Sru .put_fix_number(env->vpos) 1104114402Sru .put_fix_number(p[0]/2) 1105114402Sru .put_symbol("DC"); 1106114402Sru if (fill_flag) 1107114402Sru fill_path(env); 1108114402Sru else { 1109114402Sru set_line_thickness_and_color(env); 1110114402Sru out.put_symbol("ST"); 1111114402Sru } 1112114402Sru break; 1113114402Sru case 'l': 1114114402Sru if (np != 2) { 1115114402Sru error("2 arguments required for line"); 1116114402Sru break; 1117114402Sru } 1118114402Sru set_line_thickness_and_color(env); 1119114402Sru out.put_fix_number(p[0] + env->hpos) 1120114402Sru .put_fix_number(p[1] + env->vpos) 1121114402Sru .put_fix_number(env->hpos) 1122114402Sru .put_fix_number(env->vpos) 1123114402Sru .put_symbol("DL"); 1124114402Sru break; 1125114402Sru case 'E': 1126114402Sru fill_flag = 1; 1127114402Sru // fall through 1128114402Sru case 'e': 1129114402Sru if (np != 2) { 1130114402Sru error("2 arguments required for ellipse"); 1131114402Sru break; 1132114402Sru } 1133114402Sru out.put_fix_number(p[0]) 1134114402Sru .put_fix_number(p[1]) 1135114402Sru .put_fix_number(env->hpos + p[0]/2) 1136114402Sru .put_fix_number(env->vpos) 1137114402Sru .put_symbol("DE"); 1138114402Sru if (fill_flag) 1139114402Sru fill_path(env); 1140114402Sru else { 1141114402Sru set_line_thickness_and_color(env); 1142114402Sru out.put_symbol("ST"); 1143114402Sru } 1144114402Sru break; 1145114402Sru case 'P': 1146114402Sru fill_flag = 1; 1147114402Sru // fall through 1148114402Sru case 'p': 1149114402Sru { 1150114402Sru if (np & 1) { 1151114402Sru error("even number of arguments required for polygon"); 1152114402Sru break; 1153114402Sru } 1154114402Sru if (np == 0) { 1155114402Sru error("no arguments for polygon"); 1156114402Sru break; 1157114402Sru } 1158114402Sru out.put_fix_number(env->hpos) 1159114402Sru .put_fix_number(env->vpos) 1160114402Sru .put_symbol("MT"); 1161114402Sru for (int i = 0; i < np; i += 2) 1162114402Sru out.put_fix_number(p[i]) 1163114402Sru .put_fix_number(p[i+1]) 1164114402Sru .put_symbol("RL"); 1165114402Sru out.put_symbol("CL"); 1166114402Sru if (fill_flag) 1167114402Sru fill_path(env); 1168114402Sru else { 1169114402Sru set_line_thickness_and_color(env); 1170114402Sru out.put_symbol("ST"); 1171114402Sru } 1172114402Sru break; 1173114402Sru } 1174114402Sru case '~': 1175114402Sru { 1176114402Sru if (np & 1) { 1177114402Sru error("even number of arguments required for spline"); 1178114402Sru break; 1179114402Sru } 1180114402Sru if (np == 0) { 1181114402Sru error("no arguments for spline"); 1182114402Sru break; 1183114402Sru } 1184114402Sru out.put_fix_number(env->hpos) 1185114402Sru .put_fix_number(env->vpos) 1186114402Sru .put_symbol("MT"); 1187114402Sru out.put_fix_number(p[0]/2) 1188114402Sru .put_fix_number(p[1]/2) 1189114402Sru .put_symbol("RL"); 1190114402Sru /* tnum/tden should be between 0 and 1; the closer it is to 1 1191114402Sru the tighter the curve will be to the guiding lines; 2/3 1192114402Sru is the standard value */ 1193114402Sru const int tnum = 2; 1194114402Sru const int tden = 3; 1195114402Sru for (int i = 0; i < np - 2; i += 2) { 1196114402Sru out.put_fix_number((p[i]*tnum)/(2*tden)) 1197114402Sru .put_fix_number((p[i + 1]*tnum)/(2*tden)) 1198114402Sru .put_fix_number(p[i]/2 + (p[i + 2]*(tden - tnum))/(2*tden)) 1199114402Sru .put_fix_number(p[i + 1]/2 + (p[i + 3]*(tden - tnum))/(2*tden)) 1200114402Sru .put_fix_number((p[i] - p[i]/2) + p[i + 2]/2) 1201114402Sru .put_fix_number((p[i + 1] - p[i + 1]/2) + p[i + 3]/2) 1202114402Sru .put_symbol("RC"); 1203114402Sru } 1204114402Sru out.put_fix_number(p[np - 2] - p[np - 2]/2) 1205114402Sru .put_fix_number(p[np - 1] - p[np - 1]/2) 1206114402Sru .put_symbol("RL"); 1207114402Sru set_line_thickness_and_color(env); 1208114402Sru out.put_symbol("ST"); 1209114402Sru } 1210114402Sru break; 1211114402Sru case 'a': 1212114402Sru { 1213114402Sru if (np != 4) { 1214114402Sru error("4 arguments required for arc"); 1215114402Sru break; 1216114402Sru } 1217114402Sru set_line_thickness_and_color(env); 1218114402Sru double c[2]; 1219114402Sru if (adjust_arc_center(p, c)) 1220114402Sru out.put_fix_number(env->hpos + int(c[0])) 1221114402Sru .put_fix_number(env->vpos + int(c[1])) 1222114402Sru .put_fix_number(int(sqrt(c[0]*c[0] + c[1]*c[1]))) 1223114402Sru .put_float(degrees(atan2(-c[1], -c[0]))) 1224114402Sru .put_float(degrees(atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]))) 1225114402Sru .put_symbol("DA"); 1226114402Sru else 1227114402Sru out.put_fix_number(p[0] + p[2] + env->hpos) 1228114402Sru .put_fix_number(p[1] + p[3] + env->vpos) 1229114402Sru .put_fix_number(env->hpos) 1230114402Sru .put_fix_number(env->vpos) 1231114402Sru .put_symbol("DL"); 1232114402Sru } 1233114402Sru break; 1234114402Sru case 't': 1235114402Sru if (np == 0) 1236114402Sru line_thickness = -1; 1237114402Sru else { 1238114402Sru // troff gratuitously adds an extra 0 1239114402Sru if (np != 1 && np != 2) { 1240114402Sru error("0 or 1 argument required for thickness"); 1241114402Sru break; 1242114402Sru } 1243114402Sru line_thickness = p[0]; 1244114402Sru } 1245114402Sru break; 1246114402Sru default: 1247114402Sru error("unrecognised drawing command `%1'", char(code)); 1248114402Sru break; 1249114402Sru } 1250114402Sru output_hpos = output_vpos = -1; 1251114402Sru} 1252114402Sru 1253114402Sruconst char *ps_printer::media_name() 1254114402Sru{ 1255114402Sru return "Default"; 1256114402Sru} 1257114402Sru 1258114402Sruint ps_printer::media_width() 1259114402Sru{ 1260114402Sru /* 1261114402Sru * NOTE: 1262114402Sru * Although paper size is defined as real numbers, it seems to be 1263114402Sru * a common convention to round to the nearest postscript unit. 1264114402Sru * For example, a4 is really 595.276 by 841.89 but we use 595 by 842. 1265114402Sru * 1266114402Sru * This is probably a good compromise, especially since the 1267114402Sru * Postscript definition specifies that media 1268114402Sru * matching should be done within a tolerance of 5 units. 1269114402Sru */ 1270114402Sru return int(user_paper_width ? user_paper_width*72.0 + 0.5 1271114402Sru : font::paperwidth*72.0/font::res + 0.5); 1272114402Sru} 1273114402Sru 1274114402Sruint ps_printer::media_height() 1275114402Sru{ 1276114402Sru return int(user_paper_length ? user_paper_length*72.0 + 0.5 1277114402Sru : paper_length*72.0/font::res + 0.5); 1278114402Sru} 1279114402Sru 1280114402Sruvoid ps_printer::media_set() 1281114402Sru{ 1282114402Sru /* 1283114402Sru * The setpagedevice implies an erasepage and initgraphics, and 1284114402Sru * must thus precede any descriptions for a particular page. 1285114402Sru * 1286114402Sru * NOTE: 1287114402Sru * This does not work with ps2pdf when there are included eps 1288114402Sru * segments that contain PageSize/setpagedevice. 1289114402Sru * This might be a bug in ghostscript -- must be investigated. 1290114402Sru * Using setpagedevice in an .eps is really the wrong concept, anyway. 1291114402Sru * 1292114402Sru * NOTE: 1293114402Sru * For the future, this is really the place to insert other 1294114402Sru * media selection features, like: 1295114402Sru * MediaColor 1296114402Sru * MediaPosition 1297114402Sru * MediaType 1298114402Sru * MediaWeight 1299114402Sru * MediaClass 1300114402Sru * TraySwitch 1301114402Sru * ManualFeed 1302114402Sru * InsertSheet 1303114402Sru * Duplex 1304114402Sru * Collate 1305114402Sru * ProcessColorModel 1306114402Sru * etc. 1307114402Sru */ 1308114402Sru if (!(broken_flags & (USE_PS_ADOBE_2_0|NO_PAPERSIZE))) { 1309114402Sru out.begin_comment("BeginFeature:") 1310114402Sru .comment_arg("*PageSize") 1311114402Sru .comment_arg(media_name()) 1312114402Sru .end_comment(); 1313114402Sru int w = media_width(); 1314114402Sru int h = media_height(); 1315114402Sru if (w > 0 && h > 0) 1316114402Sru // warning to user is done elsewhere 1317114402Sru fprintf(out.get_file(), 1318114402Sru "<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n", 1319114402Sru w, h); 1320114402Sru out.simple_comment("EndFeature"); 1321114402Sru } 1322114402Sru} 1323114402Sru 1324114402Sruvoid ps_printer::begin_page(int n) 1325114402Sru{ 1326114402Sru out.begin_comment("Page:") 1327114402Sru .comment_arg(i_to_a(n)); 1328114402Sru out.comment_arg(i_to_a(++pages_output)) 1329114402Sru .end_comment(); 1330114402Sru output_style.f = 0; 1331114402Sru output_space_code = 32; 1332114402Sru output_draw_point_size = -1; 1333114402Sru output_line_thickness = -1; 1334114402Sru output_hpos = output_vpos = -1; 1335114402Sru ndefined_styles = 0; 1336114402Sru out.simple_comment("BeginPageSetup"); 1337114402Sru 1338114402Sru#if 0 1339114402Sru /* 1340114402Sru * NOTE: 1341114402Sru * may decide to do this once per page 1342114402Sru */ 1343114402Sru media_set(); 1344114402Sru#endif 1345114402Sru 1346114402Sru out.put_symbol("BP") 1347114402Sru .simple_comment("EndPageSetup"); 1348114402Sru if (sbuf_color != default_color) 1349114402Sru set_color(&sbuf_color); 1350114402Sru} 1351114402Sru 1352114402Sruvoid ps_printer::end_page(int) 1353114402Sru{ 1354114402Sru flush_sbuf(); 1355114402Sru set_color(&default_color); 1356114402Sru out.put_symbol("EP"); 1357114402Sru if (invis_count != 0) { 1358114402Sru error("missing `endinvis' command"); 1359114402Sru invis_count = 0; 1360114402Sru } 1361114402Sru} 1362114402Sru 1363114402Srufont *ps_printer::make_font(const char *nm) 1364114402Sru{ 1365114402Sru return ps_font::load_ps_font(nm); 1366114402Sru} 1367114402Sru 1368114402Srups_printer::~ps_printer() 1369114402Sru{ 1370114402Sru out.simple_comment("Trailer") 1371114402Sru .put_symbol("end") 1372114402Sru .simple_comment("EOF"); 1373114402Sru if (fseek(tempfp, 0L, 0) < 0) 1374114402Sru fatal("fseek on temporary file failed"); 1375114402Sru fputs("%!PS-Adobe-", stdout); 1376114402Sru fputs((broken_flags & USE_PS_ADOBE_2_0) ? "2.0" : "3.0", stdout); 1377114402Sru putchar('\n'); 1378114402Sru out.set_file(stdout); 1379114402Sru if (cmyk_flag) 1380114402Sru out.begin_comment("Extensions:") 1381114402Sru .comment_arg("CMYK") 1382114402Sru .end_comment(); 1383114402Sru out.begin_comment("Creator:") 1384114402Sru .comment_arg("groff") 1385114402Sru .comment_arg("version") 1386114402Sru .comment_arg(Version_string) 1387114402Sru .end_comment(); 1388114402Sru { 1389114402Sru fputs("%%CreationDate: ", out.get_file()); 1390114402Sru#ifdef LONG_FOR_TIME_T 1391114402Sru long 1392114402Sru#else 1393114402Sru time_t 1394114402Sru#endif 1395114402Sru t = time(0); 1396114402Sru fputs(ctime(&t), out.get_file()); 1397114402Sru } 1398114402Sru for (font_pointer_list *f = font_list; f; f = f->next) { 1399114402Sru ps_font *psf = (ps_font *)(f->p); 1400114402Sru rm.need_font(psf->get_internal_name()); 1401114402Sru } 1402114402Sru rm.print_header_comments(out); 1403114402Sru out.begin_comment("Pages:") 1404114402Sru .comment_arg(i_to_a(pages_output)) 1405114402Sru .end_comment(); 1406114402Sru out.begin_comment("PageOrder:") 1407114402Sru .comment_arg("Ascend") 1408114402Sru .end_comment(); 1409114402Sru if (!(broken_flags & NO_PAPERSIZE)) { 1410114402Sru int w = media_width(); 1411114402Sru int h = media_height(); 1412114402Sru if (w > 0 && h > 0) 1413114402Sru fprintf(out.get_file(), 1414114402Sru "%%%%DocumentMedia: %s %d %d %d %s %s\n", 1415114402Sru media_name(), // tag name of media 1416114402Sru w, // media width 1417114402Sru h, // media height 1418114402Sru 0, // weight in g/m2 1419114402Sru "()", // paper color, e.g. white 1420114402Sru "()" // preprinted form type 1421114402Sru ); 1422114402Sru else { 1423114402Sru if (h <= 0) 1424114402Sru // see ps_printer::ps_printer 1425114402Sru warning("bad paper height, defaulting to 11i"); 1426114402Sru if (w <= 0) 1427114402Sru warning("bad paper width"); 1428114402Sru } 1429114402Sru } 1430114402Sru out.begin_comment("Orientation:") 1431114402Sru .comment_arg(landscape_flag ? "Landscape" : "Portrait") 1432114402Sru .end_comment(); 1433114402Sru if (ncopies != 1) { 1434114402Sru out.end_line(); 1435114402Sru fprintf(out.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies); 1436114402Sru } 1437114402Sru out.simple_comment("EndComments"); 1438114402Sru if (!(broken_flags & NO_PAPERSIZE)) { 1439114402Sru /* gv works fine without this one, but it really should be there. */ 1440114402Sru out.simple_comment("BeginDefaults"); 1441114402Sru fprintf(out.get_file(), "%%%%PageMedia: %s\n", media_name()); 1442114402Sru out.simple_comment("EndDefaults"); 1443114402Sru } 1444114402Sru out.simple_comment("BeginProlog"); 1445114402Sru rm.output_prolog(out); 1446114402Sru if (!(broken_flags & NO_SETUP_SECTION)) { 1447114402Sru out.simple_comment("EndProlog"); 1448114402Sru out.simple_comment("BeginSetup"); 1449114402Sru } 1450114402Sru#if 1 1451114402Sru /* 1452114402Sru * Define paper (i.e., media) size for entire document here. 1453114402Sru * This allows ps2pdf to correctly determine page size, for instance. 1454114402Sru */ 1455114402Sru media_set(); 1456114402Sru#endif 1457114402Sru rm.document_setup(out); 1458114402Sru out.put_symbol(dict_name) 1459114402Sru .put_symbol("begin"); 1460114402Sru if (ndefs > 0) 1461114402Sru ndefs += DEFS_DICT_SPARE; 1462114402Sru out.put_literal_symbol(defs_dict_name) 1463114402Sru .put_number(ndefs + 1) 1464114402Sru .put_symbol("dict") 1465114402Sru .put_symbol("def"); 1466114402Sru out.put_symbol(defs_dict_name) 1467114402Sru .put_symbol("begin"); 1468114402Sru out.put_literal_symbol("u") 1469114402Sru .put_delimiter('{') 1470114402Sru .put_fix_number(1) 1471114402Sru .put_symbol("mul") 1472114402Sru .put_delimiter('}') 1473114402Sru .put_symbol("bind") 1474114402Sru .put_symbol("def"); 1475114402Sru defs += '\0'; 1476114402Sru out.special(defs.contents()); 1477114402Sru out.put_symbol("end"); 1478114402Sru if (ncopies != 1) 1479114402Sru out.put_literal_symbol("#copies") 1480114402Sru .put_number(ncopies) 1481114402Sru .put_symbol("def"); 1482114402Sru out.put_literal_symbol("RES") 1483114402Sru .put_number(res) 1484114402Sru .put_symbol("def"); 1485114402Sru out.put_literal_symbol("PL"); 1486114402Sru if (guess_flag) 1487114402Sru out.put_symbol("PLG"); 1488114402Sru else 1489114402Sru out.put_fix_number(paper_length); 1490114402Sru out.put_symbol("def"); 1491114402Sru out.put_literal_symbol("LS") 1492114402Sru .put_symbol(landscape_flag ? "true" : "false") 1493114402Sru .put_symbol("def"); 1494114402Sru if (manual_feed_flag) { 1495114402Sru out.begin_comment("BeginFeature:") 1496114402Sru .comment_arg("*ManualFeed") 1497114402Sru .comment_arg("True") 1498114402Sru .end_comment() 1499114402Sru .put_symbol("MANUAL") 1500114402Sru .simple_comment("EndFeature"); 1501114402Sru } 1502114402Sru encode_fonts(); 1503114402Sru while (subencodings) { 1504114402Sru subencoding *tem = subencodings; 1505114402Sru subencodings = subencodings->next; 1506114402Sru encode_subfont(tem); 1507114402Sru out.put_literal_symbol(tem->subfont) 1508114402Sru .put_symbol(make_subencoding_name(tem->idx)) 1509114402Sru .put_literal_symbol(tem->p->get_internal_name()) 1510114402Sru .put_symbol("RE"); 1511114402Sru delete tem; 1512114402Sru } 1513114402Sru out.simple_comment((broken_flags & NO_SETUP_SECTION) 1514114402Sru ? "EndProlog" 1515114402Sru : "EndSetup"); 1516114402Sru out.end_line(); 1517114402Sru out.copy_file(tempfp); 1518114402Sru fclose(tempfp); 1519114402Sru} 1520114402Sru 1521114402Sruvoid ps_printer::special(char *arg, const environment *env, char type) 1522114402Sru{ 1523114402Sru if (type != 'p') 1524114402Sru return; 1525114402Sru typedef void (ps_printer::*SPECIAL_PROCP)(char *, const environment *); 1526114402Sru static struct { 1527114402Sru const char *name; 1528114402Sru SPECIAL_PROCP proc; 1529114402Sru } proc_table[] = { 1530114402Sru { "exec", &ps_printer::do_exec }, 1531114402Sru { "def", &ps_printer::do_def }, 1532114402Sru { "mdef", &ps_printer::do_mdef }, 1533114402Sru { "import", &ps_printer::do_import }, 1534114402Sru { "file", &ps_printer::do_file }, 1535114402Sru { "invis", &ps_printer::do_invis }, 1536114402Sru { "endinvis", &ps_printer::do_endinvis }, 1537114402Sru }; 1538114402Sru char *p; 1539114402Sru for (p = arg; *p == ' ' || *p == '\n'; p++) 1540114402Sru ; 1541114402Sru char *tag = p; 1542114402Sru for (; *p != '\0' && *p != ':' && *p != ' ' && *p != '\n'; p++) 1543114402Sru ; 1544114402Sru if (*p == '\0' || strncmp(tag, "ps", p - tag) != 0) { 1545114402Sru error("X command without `ps:' tag ignored"); 1546114402Sru return; 1547114402Sru } 1548114402Sru p++; 1549114402Sru for (; *p == ' ' || *p == '\n'; p++) 1550114402Sru ; 1551114402Sru char *command = p; 1552114402Sru for (; *p != '\0' && *p != ' ' && *p != '\n'; p++) 1553114402Sru ; 1554114402Sru if (*command == '\0') { 1555114402Sru error("empty X command ignored"); 1556114402Sru return; 1557114402Sru } 1558114402Sru for (unsigned int i = 0; i < sizeof(proc_table)/sizeof(proc_table[0]); i++) 1559114402Sru if (strncmp(command, proc_table[i].name, p - command) == 0) { 1560114402Sru (this->*(proc_table[i].proc))(p, env); 1561114402Sru return; 1562114402Sru } 1563114402Sru error("X command `%1' not recognised", command); 1564114402Sru} 1565114402Sru 1566114402Sru// A conforming PostScript document must not have lines longer 1567114402Sru// than 255 characters (excluding line termination characters). 1568114402Sru 1569114402Srustatic int check_line_lengths(const char *p) 1570114402Sru{ 1571114402Sru for (;;) { 1572114402Sru const char *end = strchr(p, '\n'); 1573114402Sru if (end == 0) 1574114402Sru end = strchr(p, '\0'); 1575114402Sru if (end - p > 255) 1576114402Sru return 0; 1577114402Sru if (*end == '\0') 1578114402Sru break; 1579114402Sru p = end + 1; 1580114402Sru } 1581114402Sru return 1; 1582114402Sru} 1583114402Sru 1584114402Sruvoid ps_printer::do_exec(char *arg, const environment *env) 1585114402Sru{ 1586114402Sru flush_sbuf(); 1587114402Sru while (csspace(*arg)) 1588114402Sru arg++; 1589114402Sru if (*arg == '\0') { 1590114402Sru error("missing argument to X exec command"); 1591114402Sru return; 1592114402Sru } 1593114402Sru if (!check_line_lengths(arg)) { 1594114402Sru error("lines in X exec command must not be more than 255 characters long"); 1595114402Sru return; 1596114402Sru } 1597114402Sru out.put_fix_number(env->hpos) 1598114402Sru .put_fix_number(env->vpos) 1599114402Sru .put_symbol("EBEGIN") 1600114402Sru .special(arg) 1601114402Sru .put_symbol("EEND"); 1602114402Sru output_hpos = output_vpos = -1; 1603114402Sru output_style.f = 0; 1604114402Sru output_draw_point_size = -1; 1605114402Sru output_line_thickness = -1; 1606114402Sru ndefined_styles = 0; 1607114402Sru if (!ndefs) 1608114402Sru ndefs = 1; 1609114402Sru} 1610114402Sru 1611114402Sruvoid ps_printer::do_file(char *arg, const environment *env) 1612114402Sru{ 1613114402Sru flush_sbuf(); 1614114402Sru while (csspace(*arg)) 1615114402Sru arg++; 1616114402Sru if (*arg == '\0') { 1617114402Sru error("missing argument to X file command"); 1618114402Sru return; 1619114402Sru } 1620114402Sru const char *filename = arg; 1621114402Sru do { 1622114402Sru ++arg; 1623114402Sru } while (*arg != '\0' && *arg != ' ' && *arg != '\n'); 1624114402Sru out.put_fix_number(env->hpos) 1625114402Sru .put_fix_number(env->vpos) 1626114402Sru .put_symbol("EBEGIN"); 1627114402Sru rm.import_file(filename, out); 1628114402Sru out.put_symbol("EEND"); 1629114402Sru output_hpos = output_vpos = -1; 1630114402Sru output_style.f = 0; 1631114402Sru output_draw_point_size = -1; 1632114402Sru output_line_thickness = -1; 1633114402Sru ndefined_styles = 0; 1634114402Sru if (!ndefs) 1635114402Sru ndefs = 1; 1636114402Sru} 1637114402Sru 1638114402Sruvoid ps_printer::do_def(char *arg, const environment *) 1639114402Sru{ 1640114402Sru flush_sbuf(); 1641114402Sru while (csspace(*arg)) 1642114402Sru arg++; 1643114402Sru if (!check_line_lengths(arg)) { 1644114402Sru error("lines in X def command must not be more than 255 characters long"); 1645114402Sru return; 1646114402Sru } 1647114402Sru defs += arg; 1648114402Sru if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') 1649114402Sru defs += '\n'; 1650114402Sru ndefs++; 1651114402Sru} 1652114402Sru 1653114402Sru// Like def, but the first argument says how many definitions it contains. 1654114402Sru 1655114402Sruvoid ps_printer::do_mdef(char *arg, const environment *) 1656114402Sru{ 1657114402Sru flush_sbuf(); 1658114402Sru char *p; 1659114402Sru int n = (int)strtol(arg, &p, 10); 1660114402Sru if (n == 0 && p == arg) { 1661114402Sru error("first argument to X mdef must be an integer"); 1662114402Sru return; 1663114402Sru } 1664114402Sru if (n < 0) { 1665114402Sru error("out of range argument `%1' to X mdef command", int(n)); 1666114402Sru return; 1667114402Sru } 1668114402Sru arg = p; 1669114402Sru while (csspace(*arg)) 1670114402Sru arg++; 1671114402Sru if (!check_line_lengths(arg)) { 1672114402Sru error("lines in X mdef command must not be more than 255 characters long"); 1673114402Sru return; 1674114402Sru } 1675114402Sru defs += arg; 1676114402Sru if (*arg != '\0' && strchr(arg, '\0')[-1] != '\n') 1677114402Sru defs += '\n'; 1678114402Sru ndefs += n; 1679114402Sru} 1680114402Sru 1681114402Sruvoid ps_printer::do_import(char *arg, const environment *env) 1682114402Sru{ 1683114402Sru flush_sbuf(); 1684114402Sru while (*arg == ' ' || *arg == '\n') 1685114402Sru arg++; 1686114402Sru char *p; 1687114402Sru for (p = arg; *p != '\0' && *p != ' ' && *p != '\n'; p++) 1688114402Sru ; 1689114402Sru if (*p != '\0') 1690114402Sru *p++ = '\0'; 1691114402Sru int parms[6]; 1692114402Sru int nparms = 0; 1693114402Sru while (nparms < 6) { 1694114402Sru char *end; 1695114402Sru long n = strtol(p, &end, 10); 1696114402Sru if (n == 0 && end == p) 1697114402Sru break; 1698114402Sru parms[nparms++] = int(n); 1699114402Sru p = end; 1700114402Sru } 1701114402Sru if (csalpha(*p) && (p[1] == '\0' || p[1] == ' ' || p[1] == '\n')) { 1702114402Sru error("scaling indicators not allowed in arguments for X import command"); 1703114402Sru return; 1704114402Sru } 1705114402Sru while (*p == ' ' || *p == '\n') 1706114402Sru p++; 1707114402Sru if (nparms < 5) { 1708114402Sru if (*p == '\0') 1709114402Sru error("too few arguments for X import command"); 1710114402Sru else 1711114402Sru error("invalid argument `%1' for X import command", p); 1712114402Sru return; 1713114402Sru } 1714114402Sru if (*p != '\0') { 1715114402Sru error("superfluous argument `%1' for X import command", p); 1716114402Sru return; 1717114402Sru } 1718114402Sru int llx = parms[0]; 1719114402Sru int lly = parms[1]; 1720114402Sru int urx = parms[2]; 1721114402Sru int ury = parms[3]; 1722114402Sru int desired_width = parms[4]; 1723114402Sru int desired_height = parms[5]; 1724114402Sru if (desired_width <= 0) { 1725114402Sru error("bad width argument `%1' for X import command: must be > 0", 1726114402Sru desired_width); 1727114402Sru return; 1728114402Sru } 1729114402Sru if (nparms == 6 && desired_height <= 0) { 1730114402Sru error("bad height argument `%1' for X import command: must be > 0", 1731114402Sru desired_height); 1732114402Sru return; 1733114402Sru } 1734114402Sru if (llx == urx) { 1735114402Sru error("llx and urx arguments for X import command must not be equal"); 1736114402Sru return; 1737114402Sru } 1738114402Sru if (lly == ury) { 1739114402Sru error("lly and ury arguments for X import command must not be equal"); 1740114402Sru return; 1741114402Sru } 1742114402Sru if (nparms == 5) { 1743114402Sru int old_wid = urx - llx; 1744114402Sru int old_ht = ury - lly; 1745114402Sru if (old_wid < 0) 1746114402Sru old_wid = -old_wid; 1747114402Sru if (old_ht < 0) 1748114402Sru old_ht = -old_ht; 1749114402Sru desired_height = int(desired_width*(double(old_ht)/double(old_wid)) + .5); 1750114402Sru } 1751114402Sru if (env->vpos - desired_height < 0) 1752114402Sru warning("top of imported graphic is above the top of the page"); 1753114402Sru out.put_number(llx) 1754114402Sru .put_number(lly) 1755114402Sru .put_fix_number(desired_width) 1756114402Sru .put_number(urx - llx) 1757114402Sru .put_fix_number(-desired_height) 1758114402Sru .put_number(ury - lly) 1759114402Sru .put_fix_number(env->hpos) 1760114402Sru .put_fix_number(env->vpos) 1761114402Sru .put_symbol("PBEGIN"); 1762114402Sru rm.import_file(arg, out); 1763114402Sru // do this here just in case application defines PEND 1764114402Sru out.put_symbol("end") 1765114402Sru .put_symbol("PEND"); 1766114402Sru} 1767114402Sru 1768114402Sruvoid ps_printer::do_invis(char *, const environment *) 1769114402Sru{ 1770114402Sru invis_count++; 1771114402Sru} 1772114402Sru 1773114402Sruvoid ps_printer::do_endinvis(char *, const environment *) 1774114402Sru{ 1775114402Sru if (invis_count == 0) 1776114402Sru error("unbalanced `endinvis' command"); 1777114402Sru else 1778114402Sru --invis_count; 1779114402Sru} 1780114402Sru 1781114402Sruprinter *make_printer() 1782114402Sru{ 1783114402Sru return new ps_printer(user_paper_length); 1784114402Sru} 1785114402Sru 1786114402Srustatic void usage(FILE *stream); 1787114402Sru 1788114402Sruint main(int argc, char **argv) 1789114402Sru{ 1790114402Sru setlocale(LC_NUMERIC, "C"); 1791114402Sru program_name = argv[0]; 1792114402Sru string env; 1793114402Sru static char stderr_buf[BUFSIZ]; 1794114402Sru setbuf(stderr, stderr_buf); 1795114402Sru int c; 1796114402Sru static const struct option long_options[] = { 1797114402Sru { "help", no_argument, 0, CHAR_MAX + 1 }, 1798114402Sru { "version", no_argument, 0, 'v' }, 1799114402Sru { NULL, 0, 0, 0 } 1800114402Sru }; 1801151497Sru while ((c = getopt_long(argc, argv, "b:c:F:gI:lmp:P:vw:", long_options, NULL)) 1802114402Sru != EOF) 1803114402Sru switch(c) { 1804114402Sru case 'b': 1805114402Sru // XXX check this 1806114402Sru broken_flags = atoi(optarg); 1807114402Sru bflag = 1; 1808114402Sru break; 1809114402Sru case 'c': 1810114402Sru if (sscanf(optarg, "%d", &ncopies) != 1 || ncopies <= 0) { 1811114402Sru error("bad number of copies `%s'", optarg); 1812114402Sru ncopies = 1; 1813114402Sru } 1814114402Sru break; 1815114402Sru case 'F': 1816114402Sru font::command_line_font_dir(optarg); 1817114402Sru break; 1818114402Sru case 'g': 1819114402Sru guess_flag = 1; 1820114402Sru break; 1821151497Sru case 'I': 1822151497Sru include_search_path.command_line_dir(optarg); 1823151497Sru break; 1824114402Sru case 'l': 1825114402Sru landscape_flag = 1; 1826114402Sru break; 1827114402Sru case 'm': 1828114402Sru manual_feed_flag = 1; 1829114402Sru break; 1830114402Sru case 'p': 1831114402Sru if (!font::scan_papersize(optarg, 0, 1832114402Sru &user_paper_length, &user_paper_width)) 1833114402Sru error("invalid custom paper size `%1' ignored", optarg); 1834114402Sru break; 1835114402Sru case 'P': 1836114402Sru env = "GROPS_PROLOGUE"; 1837114402Sru env += '='; 1838114402Sru env += optarg; 1839114402Sru env += '\0'; 1840114402Sru if (putenv(strsave(env.contents()))) 1841114402Sru fatal("putenv failed"); 1842114402Sru break; 1843114402Sru case 'v': 1844114402Sru printf("GNU grops (groff) version %s\n", Version_string); 1845114402Sru exit(0); 1846114402Sru break; 1847114402Sru case 'w': 1848114402Sru if (sscanf(optarg, "%d", &linewidth) != 1 || linewidth < 0) { 1849114402Sru error("bad linewidth `%1'", optarg); 1850114402Sru linewidth = -1; 1851114402Sru } 1852114402Sru break; 1853114402Sru case CHAR_MAX + 1: // --help 1854114402Sru usage(stdout); 1855114402Sru exit(0); 1856114402Sru break; 1857114402Sru case '?': 1858114402Sru usage(stderr); 1859114402Sru exit(1); 1860114402Sru break; 1861114402Sru default: 1862114402Sru assert(0); 1863114402Sru } 1864114402Sru font::set_unknown_desc_command_handler(handle_unknown_desc_command); 1865114402Sru SET_BINARY(fileno(stdout)); 1866114402Sru if (optind >= argc) 1867114402Sru do_file("-"); 1868114402Sru else { 1869114402Sru for (int i = optind; i < argc; i++) 1870114402Sru do_file(argv[i]); 1871114402Sru } 1872114402Sru return 0; 1873114402Sru} 1874114402Sru 1875114402Srustatic void usage(FILE *stream) 1876114402Sru{ 1877114402Sru fprintf(stream, 1878151497Sru"usage: %s [-glmv] [-b n] [-c n] [-w n] [-I dir] [-P prologue]\n" 1879151497Sru" [-F dir] [files ...]\n", 1880114402Sru program_name); 1881114402Sru} 1882