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#include "driver.h" 23114402Sru#include "nonposix.h" 24114402Sru#include "paper.h" 25114402Sru 26114402Sruextern "C" const char *Version_string; 27114402Sru 28114402Sru#define DEFAULT_LINEWIDTH 40 29114402Srustatic int linewidth = DEFAULT_LINEWIDTH; 30114402Sru 31114402Srustatic int draw_flag = 1; 32114402Sru 33114402Srustatic int landscape_flag = 0; 34114402Srustatic double user_paper_length = 0; 35114402Srustatic double user_paper_width = 0; 36114402Sru 37114402Sru/* These values were chosen because: 38114402Sru 39114402Sru(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) 40114402Sru 41114402Sruand 57816 is an exact multiple of both 72.27*SIZESCALE and 72. 42114402Sru 43114402SruThe width in the groff font file is the product of MULTIPLIER and the 44114402Sruwidth in the tfm file. */ 45114402Sru 46114402Sru#define RES 57816 47114402Sru#define RES_7227 (RES/7227) 48114402Sru#define UNITWIDTH 131072 49114402Sru#define SIZESCALE 100 50114402Sru#define MULTIPLIER 1 51114402Sru 52114402Sruclass dvi_font : public font { 53114402Sru dvi_font(const char *); 54114402Srupublic: 55114402Sru int checksum; 56114402Sru int design_size; 57114402Sru ~dvi_font(); 58114402Sru void handle_unknown_font_command(const char *command, const char *arg, 59114402Sru const char *filename, int lineno); 60114402Sru static dvi_font *load_dvi_font(const char *); 61114402Sru}; 62114402Sru 63114402Srudvi_font *dvi_font::load_dvi_font(const char *s) 64114402Sru{ 65114402Sru dvi_font *f = new dvi_font(s); 66114402Sru if (!f->load()) { 67114402Sru delete f; 68114402Sru return 0; 69114402Sru } 70114402Sru return f; 71114402Sru} 72114402Sru 73114402Srudvi_font::dvi_font(const char *nm) 74114402Sru: font(nm), checksum(0), design_size(0) 75114402Sru{ 76114402Sru} 77114402Sru 78114402Srudvi_font::~dvi_font() 79114402Sru{ 80114402Sru} 81114402Sru 82114402Sruvoid dvi_font::handle_unknown_font_command(const char *command, 83114402Sru const char *arg, 84114402Sru const char *filename, int lineno) 85114402Sru{ 86114402Sru char *ptr; 87114402Sru if (strcmp(command, "checksum") == 0) { 88114402Sru if (arg == 0) 89114402Sru fatal_with_file_and_line(filename, lineno, 90114402Sru "`checksum' command requires an argument"); 91114402Sru checksum = int(strtol(arg, &ptr, 10)); 92114402Sru if (checksum == 0 && ptr == arg) { 93114402Sru fatal_with_file_and_line(filename, lineno, "bad checksum"); 94114402Sru } 95114402Sru } 96114402Sru else if (strcmp(command, "designsize") == 0) { 97114402Sru if (arg == 0) 98114402Sru fatal_with_file_and_line(filename, lineno, 99114402Sru "`designsize' command requires an argument"); 100114402Sru design_size = int(strtol(arg, &ptr, 10)); 101114402Sru if (design_size == 0 && ptr == arg) { 102114402Sru fatal_with_file_and_line(filename, lineno, "bad design size"); 103114402Sru } 104114402Sru } 105114402Sru} 106114402Sru 107114402Sru#define FONTS_MAX 256 108114402Sru 109114402Srustruct output_font { 110114402Sru dvi_font *f; 111114402Sru int point_size; 112114402Sru output_font() : f(0) { } 113114402Sru}; 114114402Sru 115114402Sruclass dvi_printer : public printer { 116114402Sru FILE *fp; 117114402Sru int max_drift; 118114402Sru int byte_count; 119114402Sru int last_bop; 120114402Sru int page_count; 121114402Sru int cur_h; 122114402Sru int cur_v; 123114402Sru int end_h; 124114402Sru int max_h; 125114402Sru int max_v; 126114402Sru output_font output_font_table[FONTS_MAX]; 127114402Sru font *cur_font; 128114402Sru int cur_point_size; 129114402Sru color cur_color; 130114402Sru int pushed; 131114402Sru int pushed_h; 132114402Sru int pushed_v; 133114402Sru int have_pushed; 134114402Sru void preamble(); 135114402Sru void postamble(); 136114402Sru void define_font(int); 137114402Sru void set_font(int); 138114402Sru void possibly_begin_line(); 139114402Sru void set_color(color *); 140114402Sruprotected: 141114402Sru enum { 142114402Sru id_byte = 2, 143114402Sru set1 = 128, 144114402Sru put1 = 133, 145114402Sru put_rule = 137, 146114402Sru bop = 139, 147114402Sru eop = 140, 148114402Sru push = 141, 149114402Sru pop = 142, 150114402Sru right1 = 143, 151114402Sru down1 = 157, 152114402Sru fnt_num_0 = 171, 153114402Sru fnt1 = 235, 154114402Sru xxx1 = 239, 155114402Sru fnt_def1 = 243, 156114402Sru pre = 247, 157114402Sru post = 248, 158114402Sru post_post = 249, 159114402Sru filler = 223 160114402Sru }; 161114402Sru int line_thickness; 162114402Sru 163114402Sru void out1(int); 164114402Sru void out2(int); 165114402Sru void out3(int); 166114402Sru void out4(int); 167114402Sru void moveto(int, int); 168114402Sru void out_string(const char *); 169114402Sru void out_signed(unsigned char, int); 170114402Sru void out_unsigned(unsigned char, int); 171114402Sru void do_special(const char *); 172114402Srupublic: 173114402Sru dvi_printer(); 174114402Sru ~dvi_printer(); 175114402Sru font *make_font(const char *); 176114402Sru void begin_page(int); 177114402Sru void end_page(int); 178114402Sru void set_char(int, font *, const environment *, int w, const char *name); 179114402Sru void special(char *arg, const environment *env, char type); 180114402Sru void end_of_line(); 181114402Sru void draw(int code, int *p, int np, const environment *env); 182114402Sru}; 183114402Sru 184114402Sru 185114402Sruclass draw_dvi_printer : public dvi_printer { 186114402Sru int output_pen_size; 187114402Sru void set_line_thickness(const environment *); 188114402Sru void fill_next(const environment *); 189114402Srupublic: 190114402Sru draw_dvi_printer(); 191114402Sru ~draw_dvi_printer(); 192114402Sru void draw(int code, int *p, int np, const environment *env); 193114402Sru void end_page(int); 194114402Sru}; 195114402Sru 196114402Srudvi_printer::dvi_printer() 197114402Sru: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0), 198114402Sru cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1) 199114402Sru{ 200114402Sru if (font::res != RES) 201114402Sru fatal("resolution must be %1", RES); 202114402Sru if (font::unitwidth != UNITWIDTH) 203114402Sru fatal("unitwidth must be %1", UNITWIDTH); 204114402Sru if (font::hor != 1) 205114402Sru fatal("hor must be equal to 1"); 206114402Sru if (font::vert != 1) 207114402Sru fatal("vert must be equal to 1"); 208114402Sru if (font::sizescale != SIZESCALE) 209114402Sru fatal("sizescale must be equal to %1", SIZESCALE); 210114402Sru max_drift = font::res/1000; // this is fairly arbitrary 211114402Sru preamble(); 212114402Sru} 213114402Sru 214114402Srudvi_printer::~dvi_printer() 215114402Sru{ 216114402Sru postamble(); 217114402Sru} 218114402Sru 219114402Sru 220114402Srudraw_dvi_printer::draw_dvi_printer() 221114402Sru: output_pen_size(-1) 222114402Sru{ 223114402Sru} 224114402Sru 225114402Srudraw_dvi_printer::~draw_dvi_printer() 226114402Sru{ 227114402Sru} 228114402Sru 229114402Sru 230114402Sruvoid dvi_printer::out1(int n) 231114402Sru{ 232114402Sru byte_count += 1; 233114402Sru putc(n & 0xff, fp); 234114402Sru} 235114402Sru 236114402Sruvoid dvi_printer::out2(int n) 237114402Sru{ 238114402Sru byte_count += 2; 239114402Sru putc((n >> 8) & 0xff, fp); 240114402Sru putc(n & 0xff, fp); 241114402Sru} 242114402Sru 243114402Sruvoid dvi_printer::out3(int n) 244114402Sru{ 245114402Sru byte_count += 3; 246114402Sru putc((n >> 16) & 0xff, fp); 247114402Sru putc((n >> 8) & 0xff, fp); 248114402Sru putc(n & 0xff, fp); 249114402Sru} 250114402Sru 251114402Sruvoid dvi_printer::out4(int n) 252114402Sru{ 253114402Sru byte_count += 4; 254114402Sru putc((n >> 24) & 0xff, fp); 255114402Sru putc((n >> 16) & 0xff, fp); 256114402Sru putc((n >> 8) & 0xff, fp); 257114402Sru putc(n & 0xff, fp); 258114402Sru} 259114402Sru 260114402Sruvoid dvi_printer::out_string(const char *s) 261114402Sru{ 262114402Sru out1(strlen(s)); 263114402Sru while (*s != 0) 264114402Sru out1(*s++); 265114402Sru} 266114402Sru 267114402Sru 268114402Sruvoid dvi_printer::end_of_line() 269114402Sru{ 270114402Sru if (pushed) { 271114402Sru out1(pop); 272114402Sru pushed = 0; 273114402Sru cur_h = pushed_h; 274114402Sru cur_v = pushed_v; 275114402Sru } 276114402Sru} 277114402Sru 278114402Sruvoid dvi_printer::possibly_begin_line() 279114402Sru{ 280114402Sru if (!pushed) { 281114402Sru have_pushed = pushed = 1; 282114402Sru pushed_h = cur_h; 283114402Sru pushed_v = cur_v; 284114402Sru out1(push); 285114402Sru } 286114402Sru} 287114402Sru 288114402Sruint scale(int x, int z) 289114402Sru{ 290114402Sru int sw; 291114402Sru int a, b, c, d; 292114402Sru int alpha, beta; 293114402Sru alpha = 16*z; beta = 16; 294114402Sru while (z >= 040000000L) { 295114402Sru z /= 2; beta /= 2; 296114402Sru } 297114402Sru d = x & 255; 298114402Sru c = (x >> 8) & 255; 299114402Sru b = (x >> 16) & 255; 300114402Sru a = (x >> 24) & 255; 301114402Sru sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; 302114402Sru if (a == 255) 303114402Sru sw -= alpha; 304114402Sru else 305114402Sru assert(a == 0); 306114402Sru return sw; 307114402Sru} 308114402Sru 309114402Sruvoid dvi_printer::set_color(color *col) 310114402Sru{ 311114402Sru cur_color = *col; 312114402Sru char buf[256]; 313114402Sru unsigned int components[4]; 314114402Sru color_scheme cs = col->get_components(components); 315114402Sru switch (cs) { 316114402Sru case DEFAULT: 317114402Sru sprintf(buf, "color gray 0"); 318114402Sru break; 319114402Sru case RGB: 320114402Sru sprintf(buf, "color rgb %.3g %.3g %.3g", 321114402Sru double(Red) / color::MAX_COLOR_VAL, 322114402Sru double(Green) / color::MAX_COLOR_VAL, 323114402Sru double(Blue) / color::MAX_COLOR_VAL); 324114402Sru break; 325114402Sru case CMY: 326114402Sru col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); 327114402Sru // fall through 328114402Sru case CMYK: 329114402Sru sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g", 330114402Sru double(Cyan) / color::MAX_COLOR_VAL, 331114402Sru double(Magenta) / color::MAX_COLOR_VAL, 332114402Sru double(Yellow) / color::MAX_COLOR_VAL, 333114402Sru double(Black) / color::MAX_COLOR_VAL); 334114402Sru break; 335114402Sru case GRAY: 336114402Sru sprintf(buf, "color gray %.3g", 337114402Sru double(Gray) / color::MAX_COLOR_VAL); 338114402Sru break; 339114402Sru } 340114402Sru do_special(buf); 341114402Sru} 342114402Sru 343151497Sruvoid dvi_printer::set_char(int idx, font *f, const environment *env, 344114402Sru int w, const char *) 345114402Sru{ 346114402Sru if (*env->col != cur_color) 347114402Sru set_color(env->col); 348151497Sru int code = f->get_code(idx); 349114402Sru if (env->size != cur_point_size || f != cur_font) { 350114402Sru cur_font = f; 351114402Sru cur_point_size = env->size; 352114402Sru int i; 353114402Sru for (i = 0;; i++) { 354114402Sru if (i >= FONTS_MAX) { 355114402Sru fatal("too many output fonts required"); 356114402Sru } 357114402Sru if (output_font_table[i].f == 0) { 358114402Sru output_font_table[i].f = (dvi_font *)cur_font; 359114402Sru output_font_table[i].point_size = cur_point_size; 360114402Sru define_font(i); 361114402Sru } 362114402Sru if (output_font_table[i].f == cur_font 363114402Sru && output_font_table[i].point_size == cur_point_size) 364114402Sru break; 365114402Sru } 366114402Sru set_font(i); 367114402Sru } 368114402Sru int distance = env->hpos - cur_h; 369114402Sru if (env->hpos != end_h && distance != 0) { 370114402Sru out_signed(right1, distance); 371114402Sru cur_h = env->hpos; 372114402Sru } 373114402Sru else if (distance > max_drift) { 374114402Sru out_signed(right1, distance - max_drift); 375114402Sru cur_h = env->hpos - max_drift; 376114402Sru } 377114402Sru else if (distance < -max_drift) { 378114402Sru out_signed(right1, distance + max_drift); 379114402Sru cur_h = env->hpos + max_drift; 380114402Sru } 381114402Sru if (env->vpos != cur_v) { 382114402Sru out_signed(down1, env->vpos - cur_v); 383114402Sru cur_v = env->vpos; 384114402Sru } 385114402Sru possibly_begin_line(); 386114402Sru end_h = env->hpos + w; 387151497Sru cur_h += scale(f->get_width(idx, UNITWIDTH)/MULTIPLIER, 388114402Sru cur_point_size*RES_7227); 389114402Sru if (cur_h > max_h) 390114402Sru max_h = cur_h; 391114402Sru if (cur_v > max_v) 392114402Sru max_v = cur_v; 393114402Sru if (code >= 0 && code <= 127) 394114402Sru out1(code); 395114402Sru else 396114402Sru out_unsigned(set1, code); 397114402Sru} 398114402Sru 399114402Sruvoid dvi_printer::define_font(int i) 400114402Sru{ 401114402Sru out_unsigned(fnt_def1, i); 402114402Sru dvi_font *f = output_font_table[i].f; 403114402Sru out4(f->checksum); 404114402Sru out4(output_font_table[i].point_size*RES_7227); 405114402Sru out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); 406114402Sru const char *nm = f->get_internal_name(); 407114402Sru out1(0); 408114402Sru out_string(nm); 409114402Sru} 410114402Sru 411114402Sruvoid dvi_printer::set_font(int i) 412114402Sru{ 413114402Sru if (i >= 0 && i <= 63) 414114402Sru out1(fnt_num_0 + i); 415114402Sru else 416114402Sru out_unsigned(fnt1, i); 417114402Sru} 418114402Sru 419114402Sruvoid dvi_printer::out_signed(unsigned char base, int param) 420114402Sru{ 421114402Sru if (-128 <= param && param < 128) { 422114402Sru out1(base); 423114402Sru out1(param); 424114402Sru } 425114402Sru else if (-32768 <= param && param < 32768) { 426114402Sru out1(base+1); 427114402Sru out2(param); 428114402Sru } 429114402Sru else if (-(1 << 23) <= param && param < (1 << 23)) { 430114402Sru out1(base+2); 431114402Sru out3(param); 432114402Sru } 433114402Sru else { 434114402Sru out1(base+3); 435114402Sru out4(param); 436114402Sru } 437114402Sru} 438114402Sru 439114402Sruvoid dvi_printer::out_unsigned(unsigned char base, int param) 440114402Sru{ 441114402Sru if (param >= 0) { 442114402Sru if (param < 256) { 443114402Sru out1(base); 444114402Sru out1(param); 445114402Sru } 446114402Sru else if (param < 65536) { 447114402Sru out1(base+1); 448114402Sru out2(param); 449114402Sru } 450114402Sru else if (param < (1 << 24)) { 451114402Sru out1(base+2); 452114402Sru out3(param); 453114402Sru } 454114402Sru else { 455114402Sru out1(base+3); 456114402Sru out4(param); 457114402Sru } 458114402Sru } 459114402Sru else { 460114402Sru out1(base+3); 461114402Sru out4(param); 462114402Sru } 463114402Sru} 464114402Sru 465114402Sruvoid dvi_printer::preamble() 466114402Sru{ 467114402Sru out1(pre); 468114402Sru out1(id_byte); 469114402Sru out4(254000); 470114402Sru out4(font::res); 471114402Sru out4(1000); 472114402Sru out1(0); 473114402Sru} 474114402Sru 475114402Sruvoid dvi_printer::postamble() 476114402Sru{ 477114402Sru int tem = byte_count; 478114402Sru out1(post); 479114402Sru out4(last_bop); 480114402Sru out4(254000); 481114402Sru out4(font::res); 482114402Sru out4(1000); 483114402Sru out4(max_v); 484114402Sru out4(max_h); 485114402Sru out2(have_pushed); // stack depth 486114402Sru out2(page_count); 487114402Sru int i; 488114402Sru for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) 489114402Sru define_font(i); 490114402Sru out1(post_post); 491114402Sru out4(tem); 492114402Sru out1(id_byte); 493114402Sru for (i = 0; i < 4 || byte_count % 4 != 0; i++) 494114402Sru out1(filler); 495114402Sru} 496114402Sru 497114402Sruvoid dvi_printer::begin_page(int i) 498114402Sru{ 499114402Sru page_count++; 500114402Sru int tem = byte_count; 501114402Sru out1(bop); 502114402Sru out4(i); 503114402Sru for (int j = 1; j < 10; j++) 504114402Sru out4(0); 505114402Sru out4(last_bop); 506114402Sru last_bop = tem; 507114402Sru // By convention position (0,0) in a dvi file is placed at (1in, 1in). 508114402Sru cur_h = font::res; 509114402Sru cur_v = font::res; 510114402Sru end_h = 0; 511114402Sru if (page_count == 1) { 512114402Sru char buf[256]; 513114402Sru // at least dvips uses this 514114402Sru double length = user_paper_length ? user_paper_length : 515114402Sru double(font::paperlength) / font::res; 516114402Sru double width = user_paper_width ? user_paper_width : 517114402Sru double(font::paperwidth) / font::res; 518114402Sru if (width > 0 && length > 0) { 519114402Sru sprintf(buf, "papersize=%.3fin,%.3fin", 520114402Sru landscape_flag ? length : width, 521114402Sru landscape_flag ? width : length); 522114402Sru do_special(buf); 523114402Sru } 524114402Sru } 525114402Sru if (cur_color != default_color) 526114402Sru set_color(&cur_color); 527114402Sru} 528114402Sru 529114402Sruvoid dvi_printer::end_page(int) 530114402Sru{ 531114402Sru set_color(&default_color); 532114402Sru if (pushed) 533114402Sru end_of_line(); 534114402Sru out1(eop); 535114402Sru cur_font = 0; 536114402Sru} 537114402Sru 538114402Sruvoid draw_dvi_printer::end_page(int len) 539114402Sru{ 540114402Sru dvi_printer::end_page(len); 541114402Sru output_pen_size = -1; 542114402Sru} 543114402Sru 544114402Sruvoid dvi_printer::do_special(const char *s) 545114402Sru{ 546114402Sru int len = strlen(s); 547114402Sru if (len == 0) 548114402Sru return; 549114402Sru possibly_begin_line(); 550114402Sru out_unsigned(xxx1, len); 551114402Sru while (*s) 552114402Sru out1(*s++); 553114402Sru} 554114402Sru 555114402Sruvoid dvi_printer::special(char *arg, const environment *env, char type) 556114402Sru{ 557114402Sru if (type != 'p') 558114402Sru return; 559114402Sru moveto(env->hpos, env->vpos); 560114402Sru do_special(arg); 561114402Sru} 562114402Sru 563114402Sruvoid dvi_printer::moveto(int h, int v) 564114402Sru{ 565114402Sru if (h != cur_h) { 566114402Sru out_signed(right1, h - cur_h); 567114402Sru cur_h = h; 568114402Sru if (cur_h > max_h) 569114402Sru max_h = cur_h; 570114402Sru } 571114402Sru if (v != cur_v) { 572114402Sru out_signed(down1, v - cur_v); 573114402Sru cur_v = v; 574114402Sru if (cur_v > max_v) 575114402Sru max_v = cur_v; 576114402Sru } 577114402Sru end_h = 0; 578114402Sru} 579114402Sru 580114402Sruvoid dvi_printer::draw(int code, int *p, int np, const environment *env) 581114402Sru{ 582114402Sru if (code == 'l') { 583114402Sru int x = 0, y = 0; 584114402Sru int height = 0, width = 0; 585114402Sru int thickness; 586114402Sru if (line_thickness < 0) 587114402Sru thickness = env->size*RES_7227*linewidth/1000; 588114402Sru else if (line_thickness > 0) 589114402Sru thickness = line_thickness; 590114402Sru else 591114402Sru thickness = 1; 592114402Sru if (np != 2) { 593114402Sru error("2 arguments required for line"); 594114402Sru } 595114402Sru else if (p[0] == 0) { 596114402Sru // vertical rule 597114402Sru if (p[1] > 0) { 598114402Sru x = env->hpos - thickness/2; 599114402Sru y = env->vpos + p[1] + thickness/2; 600114402Sru height = p[1] + thickness; 601114402Sru width = thickness; 602114402Sru } 603114402Sru else if (p[1] < 0) { 604114402Sru x = env->hpos - thickness/2; 605114402Sru y = env->vpos + thickness/2; 606114402Sru height = thickness - p[1]; 607114402Sru width = thickness; 608114402Sru } 609114402Sru } 610114402Sru else if (p[1] == 0) { 611114402Sru if (p[0] > 0) { 612114402Sru x = env->hpos - thickness/2; 613114402Sru y = env->vpos + thickness/2; 614114402Sru height = thickness; 615114402Sru width = p[0] + thickness; 616114402Sru } 617114402Sru else if (p[0] < 0) { 618114402Sru x = env->hpos - p[0] - thickness/2; 619114402Sru y = env->vpos + thickness/2; 620114402Sru height = thickness; 621114402Sru width = thickness - p[0]; 622114402Sru } 623114402Sru } 624114402Sru if (height != 0) { 625114402Sru moveto(x, y); 626114402Sru out1(put_rule); 627114402Sru out4(height); 628114402Sru out4(width); 629114402Sru } 630114402Sru } 631114402Sru else if (code == 't') { 632114402Sru if (np == 0) { 633114402Sru line_thickness = -1; 634114402Sru } 635114402Sru else { 636114402Sru // troff gratuitously adds an extra 0 637114402Sru if (np != 1 && np != 2) 638114402Sru error("0 or 1 argument required for thickness"); 639114402Sru else 640114402Sru line_thickness = p[0]; 641114402Sru } 642114402Sru } 643114402Sru else if (code == 'R') { 644114402Sru if (np != 2) 645114402Sru error("2 arguments required for rule"); 646114402Sru else if (p[0] != 0 || p[1] != 0) { 647114402Sru int dh = p[0]; 648114402Sru int dv = p[1]; 649114402Sru int oh = env->hpos; 650114402Sru int ov = env->vpos; 651114402Sru if (dv > 0) { 652114402Sru ov += dv; 653114402Sru dv = -dv; 654114402Sru } 655114402Sru if (dh < 0) { 656114402Sru oh += dh; 657114402Sru dh = -dh; 658114402Sru } 659114402Sru moveto(oh, ov); 660114402Sru out1(put_rule); 661114402Sru out4(-dv); 662114402Sru out4(dh); 663114402Sru } 664114402Sru } 665114402Sru} 666114402Sru 667114402Sru// XXX Will this overflow? 668114402Sru 669114402Sruinline int milliinches(int n) 670114402Sru{ 671114402Sru return (n*1000 + font::res/2)/font::res; 672114402Sru} 673114402Sru 674114402Sruvoid draw_dvi_printer::set_line_thickness(const environment *env) 675114402Sru{ 676114402Sru int desired_pen_size 677114402Sru = milliinches(line_thickness < 0 678114402Sru // Will this overflow? 679114402Sru ? env->size*RES_7227*linewidth/1000 680114402Sru : line_thickness); 681114402Sru if (desired_pen_size != output_pen_size) { 682114402Sru char buf[256]; 683114402Sru sprintf(buf, "pn %d", desired_pen_size); 684114402Sru do_special(buf); 685114402Sru output_pen_size = desired_pen_size; 686114402Sru } 687114402Sru} 688114402Sru 689114402Sruvoid draw_dvi_printer::fill_next(const environment *env) 690114402Sru{ 691114402Sru unsigned int g; 692114402Sru if (env->fill->is_default()) 693114402Sru g = 0; 694114402Sru else { 695114402Sru // currently, only BW support 696114402Sru env->fill->get_gray(&g); 697114402Sru } 698114402Sru char buf[256]; 699114402Sru sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL); 700114402Sru do_special(buf); 701114402Sru} 702114402Sru 703114402Sruvoid draw_dvi_printer::draw(int code, int *p, int np, const environment *env) 704114402Sru{ 705114402Sru char buf[1024]; 706114402Sru int fill_flag = 0; 707114402Sru switch (code) { 708114402Sru case 'C': 709114402Sru fill_flag = 1; 710114402Sru // fall through 711114402Sru case 'c': 712151497Sru { 713151497Sru // troff adds an extra argument to C 714151497Sru if (np != 1 && !(code == 'C' && np == 2)) { 715151497Sru error("1 argument required for circle"); 716151497Sru break; 717151497Sru } 718151497Sru moveto(env->hpos+p[0]/2, env->vpos); 719151497Sru if (fill_flag) 720151497Sru fill_next(env); 721151497Sru else 722151497Sru set_line_thickness(env); 723151497Sru int rad; 724151497Sru rad = milliinches(p[0]/2); 725151497Sru sprintf(buf, "%s 0 0 %d %d 0 6.28319", 726151497Sru (fill_flag ? "ia" : "ar"), 727151497Sru rad, 728151497Sru rad); 729151497Sru do_special(buf); 730114402Sru break; 731114402Sru } 732114402Sru case 'l': 733114402Sru if (np != 2) { 734114402Sru error("2 arguments required for line"); 735114402Sru break; 736114402Sru } 737114402Sru moveto(env->hpos, env->vpos); 738114402Sru set_line_thickness(env); 739114402Sru do_special("pa 0 0"); 740114402Sru sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); 741114402Sru do_special(buf); 742114402Sru do_special("fp"); 743114402Sru break; 744114402Sru case 'E': 745114402Sru fill_flag = 1; 746114402Sru // fall through 747114402Sru case 'e': 748114402Sru if (np != 2) { 749114402Sru error("2 arguments required for ellipse"); 750114402Sru break; 751114402Sru } 752114402Sru moveto(env->hpos+p[0]/2, env->vpos); 753114402Sru if (fill_flag) 754114402Sru fill_next(env); 755114402Sru sprintf(buf, "%s 0 0 %d %d 0 6.28319", 756114402Sru (fill_flag ? "ia" : "ar"), 757114402Sru milliinches(p[0]/2), 758114402Sru milliinches(p[1]/2)); 759114402Sru do_special(buf); 760114402Sru break; 761114402Sru case 'P': 762114402Sru fill_flag = 1; 763114402Sru // fall through 764114402Sru case 'p': 765114402Sru { 766114402Sru if (np & 1) { 767114402Sru error("even number of arguments required for polygon"); 768114402Sru break; 769114402Sru } 770114402Sru if (np == 0) { 771114402Sru error("no arguments for polygon"); 772114402Sru break; 773114402Sru } 774114402Sru moveto(env->hpos, env->vpos); 775114402Sru if (fill_flag) 776114402Sru fill_next(env); 777114402Sru else 778114402Sru set_line_thickness(env); 779114402Sru do_special("pa 0 0"); 780114402Sru int h = 0, v = 0; 781114402Sru for (int i = 0; i < np; i += 2) { 782114402Sru h += p[i]; 783114402Sru v += p[i+1]; 784114402Sru sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 785114402Sru do_special(buf); 786114402Sru } 787114402Sru do_special("pa 0 0"); 788114402Sru do_special(fill_flag ? "ip" : "fp"); 789114402Sru break; 790114402Sru } 791114402Sru case '~': 792114402Sru { 793114402Sru if (np & 1) { 794114402Sru error("even number of arguments required for spline"); 795114402Sru break; 796114402Sru } 797114402Sru if (np == 0) { 798114402Sru error("no arguments for spline"); 799114402Sru break; 800114402Sru } 801114402Sru moveto(env->hpos, env->vpos); 802114402Sru set_line_thickness(env); 803114402Sru do_special("pa 0 0"); 804114402Sru int h = 0, v = 0; 805114402Sru for (int i = 0; i < np; i += 2) { 806114402Sru h += p[i]; 807114402Sru v += p[i+1]; 808114402Sru sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 809114402Sru do_special(buf); 810114402Sru } 811114402Sru do_special("sp"); 812114402Sru break; 813114402Sru } 814114402Sru case 'a': 815114402Sru { 816114402Sru if (np != 4) { 817114402Sru error("4 arguments required for arc"); 818114402Sru break; 819114402Sru } 820114402Sru set_line_thickness(env); 821114402Sru double c[2]; 822114402Sru if (adjust_arc_center(p, c)) { 823114402Sru int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); 824114402Sru moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); 825151497Sru double start = atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]); 826151497Sru double end = atan2(-c[1], -c[0]); 827151497Sru if (end - start < 0) 828151497Sru start -= 2 * 3.14159265358; 829151497Sru sprintf(buf, "ar 0 0 %d %d %f %f", rad, rad, start, end); 830114402Sru do_special(buf); 831114402Sru } 832114402Sru else { 833114402Sru moveto(env->hpos, env->vpos); 834114402Sru do_special("pa 0 0"); 835114402Sru sprintf(buf, 836114402Sru "pa %d %d", 837114402Sru milliinches(p[0] + p[2]), 838114402Sru milliinches(p[1] + p[3])); 839114402Sru do_special(buf); 840114402Sru do_special("fp"); 841114402Sru } 842114402Sru break; 843114402Sru } 844114402Sru case 't': 845114402Sru { 846114402Sru if (np == 0) { 847114402Sru line_thickness = -1; 848114402Sru } 849114402Sru else { 850114402Sru // troff gratuitously adds an extra 0 851114402Sru if (np != 1 && np != 2) { 852114402Sru error("0 or 1 argument required for thickness"); 853114402Sru break; 854114402Sru } 855114402Sru line_thickness = p[0]; 856114402Sru } 857114402Sru break; 858114402Sru } 859114402Sru case 'R': 860114402Sru { 861114402Sru if (np != 2) { 862114402Sru error("2 arguments required for rule"); 863114402Sru break; 864114402Sru } 865114402Sru int dh = p[0]; 866114402Sru if (dh == 0) 867114402Sru break; 868114402Sru int dv = p[1]; 869114402Sru if (dv == 0) 870114402Sru break; 871114402Sru int oh = env->hpos; 872114402Sru int ov = env->vpos; 873114402Sru if (dv > 0) { 874114402Sru ov += dv; 875114402Sru dv = -dv; 876114402Sru } 877114402Sru if (dh < 0) { 878114402Sru oh += dh; 879114402Sru dh = -dh; 880114402Sru } 881114402Sru moveto(oh, ov); 882114402Sru out1(put_rule); 883114402Sru out4(-dv); 884114402Sru out4(dh); 885114402Sru break; 886114402Sru } 887114402Sru default: 888114402Sru error("unrecognised drawing command `%1'", char(code)); 889114402Sru break; 890114402Sru } 891114402Sru} 892114402Sru 893114402Srufont *dvi_printer::make_font(const char *nm) 894114402Sru{ 895114402Sru return dvi_font::load_dvi_font(nm); 896114402Sru} 897114402Sru 898114402Sruprinter *make_printer() 899114402Sru{ 900114402Sru if (draw_flag) 901114402Sru return new draw_dvi_printer; 902114402Sru else 903114402Sru return new dvi_printer; 904114402Sru} 905114402Sru 906114402Srustatic void usage(FILE *stream); 907114402Sru 908114402Sruint main(int argc, char **argv) 909114402Sru{ 910114402Sru setlocale(LC_NUMERIC, "C"); 911114402Sru program_name = argv[0]; 912114402Sru static char stderr_buf[BUFSIZ]; 913114402Sru setbuf(stderr, stderr_buf); 914114402Sru int c; 915114402Sru static const struct option long_options[] = { 916114402Sru { "help", no_argument, 0, CHAR_MAX + 1 }, 917114402Sru { "version", no_argument, 0, 'v' }, 918114402Sru { NULL, 0, 0, 0 } 919114402Sru }; 920151497Sru while ((c = getopt_long(argc, argv, "dF:I:lp:vw:", long_options, NULL)) 921114402Sru != EOF) 922114402Sru switch(c) { 923114402Sru case 'd': 924114402Sru draw_flag = 0; 925114402Sru break; 926114402Sru case 'l': 927114402Sru landscape_flag = 1; 928114402Sru break; 929114402Sru case 'F': 930114402Sru font::command_line_font_dir(optarg); 931114402Sru break; 932151497Sru case 'I': 933151497Sru // ignore include search path 934151497Sru break; 935114402Sru case 'p': 936114402Sru if (!font::scan_papersize(optarg, 0, 937114402Sru &user_paper_length, &user_paper_width)) 938114402Sru error("invalid custom paper size `%1' ignored", optarg); 939114402Sru break; 940114402Sru case 'v': 941114402Sru { 942114402Sru printf("GNU grodvi (groff) version %s\n", Version_string); 943114402Sru exit(0); 944114402Sru break; 945114402Sru } 946114402Sru case 'w': 947114402Sru if (sscanf(optarg, "%d", &linewidth) != 1 948114402Sru || linewidth < 0 || linewidth > 1000) { 949114402Sru error("bad line width"); 950114402Sru linewidth = DEFAULT_LINEWIDTH; 951114402Sru } 952114402Sru break; 953114402Sru case CHAR_MAX + 1: // --help 954114402Sru usage(stdout); 955114402Sru exit(0); 956114402Sru break; 957114402Sru case '?': 958114402Sru usage(stderr); 959114402Sru exit(1); 960114402Sru break; 961114402Sru default: 962114402Sru assert(0); 963114402Sru } 964114402Sru SET_BINARY(fileno(stdout)); 965114402Sru if (optind >= argc) 966114402Sru do_file("-"); 967114402Sru else { 968114402Sru for (int i = optind; i < argc; i++) 969114402Sru do_file(argv[i]); 970114402Sru } 971114402Sru return 0; 972114402Sru} 973114402Sru 974114402Srustatic void usage(FILE *stream) 975114402Sru{ 976114402Sru fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n", 977114402Sru program_name); 978114402Sru} 979