1// -*- C++ -*- 2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004 3 Free Software Foundation, Inc. 4 Written by James Clark (jjc@jclark.com) 5 6This file is part of groff. 7 8groff is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13groff is distributed in the hope that it will be useful, but WITHOUT ANY 14WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License along 19with groff; see the file COPYING. If not, write to the Free Software 20Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21 22#include "driver.h" 23#include "nonposix.h" 24#include "paper.h" 25 26extern "C" const char *Version_string; 27 28#define DEFAULT_LINEWIDTH 40 29static int linewidth = DEFAULT_LINEWIDTH; 30 31static int draw_flag = 1; 32 33static int landscape_flag = 0; 34static double user_paper_length = 0; 35static double user_paper_width = 0; 36 37/* These values were chosen because: 38 39(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27) 40 41and 57816 is an exact multiple of both 72.27*SIZESCALE and 72. 42 43The width in the groff font file is the product of MULTIPLIER and the 44width in the tfm file. */ 45 46#define RES 57816 47#define RES_7227 (RES/7227) 48#define UNITWIDTH 131072 49#define SIZESCALE 100 50#define MULTIPLIER 1 51 52class dvi_font : public font { 53 dvi_font(const char *); 54public: 55 int checksum; 56 int design_size; 57 ~dvi_font(); 58 void handle_unknown_font_command(const char *command, const char *arg, 59 const char *filename, int lineno); 60 static dvi_font *load_dvi_font(const char *); 61}; 62 63dvi_font *dvi_font::load_dvi_font(const char *s) 64{ 65 dvi_font *f = new dvi_font(s); 66 if (!f->load()) { 67 delete f; 68 return 0; 69 } 70 return f; 71} 72 73dvi_font::dvi_font(const char *nm) 74: font(nm), checksum(0), design_size(0) 75{ 76} 77 78dvi_font::~dvi_font() 79{ 80} 81 82void dvi_font::handle_unknown_font_command(const char *command, 83 const char *arg, 84 const char *filename, int lineno) 85{ 86 char *ptr; 87 if (strcmp(command, "checksum") == 0) { 88 if (arg == 0) 89 fatal_with_file_and_line(filename, lineno, 90 "`checksum' command requires an argument"); 91 checksum = int(strtol(arg, &ptr, 10)); 92 if (checksum == 0 && ptr == arg) { 93 fatal_with_file_and_line(filename, lineno, "bad checksum"); 94 } 95 } 96 else if (strcmp(command, "designsize") == 0) { 97 if (arg == 0) 98 fatal_with_file_and_line(filename, lineno, 99 "`designsize' command requires an argument"); 100 design_size = int(strtol(arg, &ptr, 10)); 101 if (design_size == 0 && ptr == arg) { 102 fatal_with_file_and_line(filename, lineno, "bad design size"); 103 } 104 } 105} 106 107#define FONTS_MAX 256 108 109struct output_font { 110 dvi_font *f; 111 int point_size; 112 output_font() : f(0) { } 113}; 114 115class dvi_printer : public printer { 116 FILE *fp; 117 int max_drift; 118 int byte_count; 119 int last_bop; 120 int page_count; 121 int cur_h; 122 int cur_v; 123 int end_h; 124 int max_h; 125 int max_v; 126 output_font output_font_table[FONTS_MAX]; 127 font *cur_font; 128 int cur_point_size; 129 color cur_color; 130 int pushed; 131 int pushed_h; 132 int pushed_v; 133 int have_pushed; 134 void preamble(); 135 void postamble(); 136 void define_font(int); 137 void set_font(int); 138 void possibly_begin_line(); 139 void set_color(color *); 140protected: 141 enum { 142 id_byte = 2, 143 set1 = 128, 144 put1 = 133, 145 put_rule = 137, 146 bop = 139, 147 eop = 140, 148 push = 141, 149 pop = 142, 150 right1 = 143, 151 down1 = 157, 152 fnt_num_0 = 171, 153 fnt1 = 235, 154 xxx1 = 239, 155 fnt_def1 = 243, 156 pre = 247, 157 post = 248, 158 post_post = 249, 159 filler = 223 160 }; 161 int line_thickness; 162 163 void out1(int); 164 void out2(int); 165 void out3(int); 166 void out4(int); 167 void moveto(int, int); 168 void out_string(const char *); 169 void out_signed(unsigned char, int); 170 void out_unsigned(unsigned char, int); 171 void do_special(const char *); 172public: 173 dvi_printer(); 174 ~dvi_printer(); 175 font *make_font(const char *); 176 void begin_page(int); 177 void end_page(int); 178 void set_char(int, font *, const environment *, int w, const char *name); 179 void special(char *arg, const environment *env, char type); 180 void end_of_line(); 181 void draw(int code, int *p, int np, const environment *env); 182}; 183 184 185class draw_dvi_printer : public dvi_printer { 186 int output_pen_size; 187 void set_line_thickness(const environment *); 188 void fill_next(const environment *); 189public: 190 draw_dvi_printer(); 191 ~draw_dvi_printer(); 192 void draw(int code, int *p, int np, const environment *env); 193 void end_page(int); 194}; 195 196dvi_printer::dvi_printer() 197: fp(stdout), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0), 198 cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1) 199{ 200 if (font::res != RES) 201 fatal("resolution must be %1", RES); 202 if (font::unitwidth != UNITWIDTH) 203 fatal("unitwidth must be %1", UNITWIDTH); 204 if (font::hor != 1) 205 fatal("hor must be equal to 1"); 206 if (font::vert != 1) 207 fatal("vert must be equal to 1"); 208 if (font::sizescale != SIZESCALE) 209 fatal("sizescale must be equal to %1", SIZESCALE); 210 max_drift = font::res/1000; // this is fairly arbitrary 211 preamble(); 212} 213 214dvi_printer::~dvi_printer() 215{ 216 postamble(); 217} 218 219 220draw_dvi_printer::draw_dvi_printer() 221: output_pen_size(-1) 222{ 223} 224 225draw_dvi_printer::~draw_dvi_printer() 226{ 227} 228 229 230void dvi_printer::out1(int n) 231{ 232 byte_count += 1; 233 putc(n & 0xff, fp); 234} 235 236void dvi_printer::out2(int n) 237{ 238 byte_count += 2; 239 putc((n >> 8) & 0xff, fp); 240 putc(n & 0xff, fp); 241} 242 243void dvi_printer::out3(int n) 244{ 245 byte_count += 3; 246 putc((n >> 16) & 0xff, fp); 247 putc((n >> 8) & 0xff, fp); 248 putc(n & 0xff, fp); 249} 250 251void dvi_printer::out4(int n) 252{ 253 byte_count += 4; 254 putc((n >> 24) & 0xff, fp); 255 putc((n >> 16) & 0xff, fp); 256 putc((n >> 8) & 0xff, fp); 257 putc(n & 0xff, fp); 258} 259 260void dvi_printer::out_string(const char *s) 261{ 262 out1(strlen(s)); 263 while (*s != 0) 264 out1(*s++); 265} 266 267 268void dvi_printer::end_of_line() 269{ 270 if (pushed) { 271 out1(pop); 272 pushed = 0; 273 cur_h = pushed_h; 274 cur_v = pushed_v; 275 } 276} 277 278void dvi_printer::possibly_begin_line() 279{ 280 if (!pushed) { 281 have_pushed = pushed = 1; 282 pushed_h = cur_h; 283 pushed_v = cur_v; 284 out1(push); 285 } 286} 287 288int scale(int x, int z) 289{ 290 int sw; 291 int a, b, c, d; 292 int alpha, beta; 293 alpha = 16*z; beta = 16; 294 while (z >= 040000000L) { 295 z /= 2; beta /= 2; 296 } 297 d = x & 255; 298 c = (x >> 8) & 255; 299 b = (x >> 16) & 255; 300 a = (x >> 24) & 255; 301 sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta; 302 if (a == 255) 303 sw -= alpha; 304 else 305 assert(a == 0); 306 return sw; 307} 308 309void dvi_printer::set_color(color *col) 310{ 311 cur_color = *col; 312 char buf[256]; 313 unsigned int components[4]; 314 color_scheme cs = col->get_components(components); 315 switch (cs) { 316 case DEFAULT: 317 sprintf(buf, "color gray 0"); 318 break; 319 case RGB: 320 sprintf(buf, "color rgb %.3g %.3g %.3g", 321 double(Red) / color::MAX_COLOR_VAL, 322 double(Green) / color::MAX_COLOR_VAL, 323 double(Blue) / color::MAX_COLOR_VAL); 324 break; 325 case CMY: 326 col->get_cmyk(&Cyan, &Magenta, &Yellow, &Black); 327 // fall through 328 case CMYK: 329 sprintf(buf, "color cmyk %.3g %.3g %.3g %.3g", 330 double(Cyan) / color::MAX_COLOR_VAL, 331 double(Magenta) / color::MAX_COLOR_VAL, 332 double(Yellow) / color::MAX_COLOR_VAL, 333 double(Black) / color::MAX_COLOR_VAL); 334 break; 335 case GRAY: 336 sprintf(buf, "color gray %.3g", 337 double(Gray) / color::MAX_COLOR_VAL); 338 break; 339 } 340 do_special(buf); 341} 342 343void dvi_printer::set_char(int idx, font *f, const environment *env, 344 int w, const char *) 345{ 346 if (*env->col != cur_color) 347 set_color(env->col); 348 int code = f->get_code(idx); 349 if (env->size != cur_point_size || f != cur_font) { 350 cur_font = f; 351 cur_point_size = env->size; 352 int i; 353 for (i = 0;; i++) { 354 if (i >= FONTS_MAX) { 355 fatal("too many output fonts required"); 356 } 357 if (output_font_table[i].f == 0) { 358 output_font_table[i].f = (dvi_font *)cur_font; 359 output_font_table[i].point_size = cur_point_size; 360 define_font(i); 361 } 362 if (output_font_table[i].f == cur_font 363 && output_font_table[i].point_size == cur_point_size) 364 break; 365 } 366 set_font(i); 367 } 368 int distance = env->hpos - cur_h; 369 if (env->hpos != end_h && distance != 0) { 370 out_signed(right1, distance); 371 cur_h = env->hpos; 372 } 373 else if (distance > max_drift) { 374 out_signed(right1, distance - max_drift); 375 cur_h = env->hpos - max_drift; 376 } 377 else if (distance < -max_drift) { 378 out_signed(right1, distance + max_drift); 379 cur_h = env->hpos + max_drift; 380 } 381 if (env->vpos != cur_v) { 382 out_signed(down1, env->vpos - cur_v); 383 cur_v = env->vpos; 384 } 385 possibly_begin_line(); 386 end_h = env->hpos + w; 387 cur_h += scale(f->get_width(idx, UNITWIDTH)/MULTIPLIER, 388 cur_point_size*RES_7227); 389 if (cur_h > max_h) 390 max_h = cur_h; 391 if (cur_v > max_v) 392 max_v = cur_v; 393 if (code >= 0 && code <= 127) 394 out1(code); 395 else 396 out_unsigned(set1, code); 397} 398 399void dvi_printer::define_font(int i) 400{ 401 out_unsigned(fnt_def1, i); 402 dvi_font *f = output_font_table[i].f; 403 out4(f->checksum); 404 out4(output_font_table[i].point_size*RES_7227); 405 out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5)); 406 const char *nm = f->get_internal_name(); 407 out1(0); 408 out_string(nm); 409} 410 411void dvi_printer::set_font(int i) 412{ 413 if (i >= 0 && i <= 63) 414 out1(fnt_num_0 + i); 415 else 416 out_unsigned(fnt1, i); 417} 418 419void dvi_printer::out_signed(unsigned char base, int param) 420{ 421 if (-128 <= param && param < 128) { 422 out1(base); 423 out1(param); 424 } 425 else if (-32768 <= param && param < 32768) { 426 out1(base+1); 427 out2(param); 428 } 429 else if (-(1 << 23) <= param && param < (1 << 23)) { 430 out1(base+2); 431 out3(param); 432 } 433 else { 434 out1(base+3); 435 out4(param); 436 } 437} 438 439void dvi_printer::out_unsigned(unsigned char base, int param) 440{ 441 if (param >= 0) { 442 if (param < 256) { 443 out1(base); 444 out1(param); 445 } 446 else if (param < 65536) { 447 out1(base+1); 448 out2(param); 449 } 450 else if (param < (1 << 24)) { 451 out1(base+2); 452 out3(param); 453 } 454 else { 455 out1(base+3); 456 out4(param); 457 } 458 } 459 else { 460 out1(base+3); 461 out4(param); 462 } 463} 464 465void dvi_printer::preamble() 466{ 467 out1(pre); 468 out1(id_byte); 469 out4(254000); 470 out4(font::res); 471 out4(1000); 472 out1(0); 473} 474 475void dvi_printer::postamble() 476{ 477 int tem = byte_count; 478 out1(post); 479 out4(last_bop); 480 out4(254000); 481 out4(font::res); 482 out4(1000); 483 out4(max_v); 484 out4(max_h); 485 out2(have_pushed); // stack depth 486 out2(page_count); 487 int i; 488 for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++) 489 define_font(i); 490 out1(post_post); 491 out4(tem); 492 out1(id_byte); 493 for (i = 0; i < 4 || byte_count % 4 != 0; i++) 494 out1(filler); 495} 496 497void dvi_printer::begin_page(int i) 498{ 499 page_count++; 500 int tem = byte_count; 501 out1(bop); 502 out4(i); 503 for (int j = 1; j < 10; j++) 504 out4(0); 505 out4(last_bop); 506 last_bop = tem; 507 // By convention position (0,0) in a dvi file is placed at (1in, 1in). 508 cur_h = font::res; 509 cur_v = font::res; 510 end_h = 0; 511 if (page_count == 1) { 512 char buf[256]; 513 // at least dvips uses this 514 double length = user_paper_length ? user_paper_length : 515 double(font::paperlength) / font::res; 516 double width = user_paper_width ? user_paper_width : 517 double(font::paperwidth) / font::res; 518 if (width > 0 && length > 0) { 519 sprintf(buf, "papersize=%.3fin,%.3fin", 520 landscape_flag ? length : width, 521 landscape_flag ? width : length); 522 do_special(buf); 523 } 524 } 525 if (cur_color != default_color) 526 set_color(&cur_color); 527} 528 529void dvi_printer::end_page(int) 530{ 531 set_color(&default_color); 532 if (pushed) 533 end_of_line(); 534 out1(eop); 535 cur_font = 0; 536} 537 538void draw_dvi_printer::end_page(int len) 539{ 540 dvi_printer::end_page(len); 541 output_pen_size = -1; 542} 543 544void dvi_printer::do_special(const char *s) 545{ 546 int len = strlen(s); 547 if (len == 0) 548 return; 549 possibly_begin_line(); 550 out_unsigned(xxx1, len); 551 while (*s) 552 out1(*s++); 553} 554 555void dvi_printer::special(char *arg, const environment *env, char type) 556{ 557 if (type != 'p') 558 return; 559 moveto(env->hpos, env->vpos); 560 do_special(arg); 561} 562 563void dvi_printer::moveto(int h, int v) 564{ 565 if (h != cur_h) { 566 out_signed(right1, h - cur_h); 567 cur_h = h; 568 if (cur_h > max_h) 569 max_h = cur_h; 570 } 571 if (v != cur_v) { 572 out_signed(down1, v - cur_v); 573 cur_v = v; 574 if (cur_v > max_v) 575 max_v = cur_v; 576 } 577 end_h = 0; 578} 579 580void dvi_printer::draw(int code, int *p, int np, const environment *env) 581{ 582 if (code == 'l') { 583 int x = 0, y = 0; 584 int height = 0, width = 0; 585 int thickness; 586 if (line_thickness < 0) 587 thickness = env->size*RES_7227*linewidth/1000; 588 else if (line_thickness > 0) 589 thickness = line_thickness; 590 else 591 thickness = 1; 592 if (np != 2) { 593 error("2 arguments required for line"); 594 } 595 else if (p[0] == 0) { 596 // vertical rule 597 if (p[1] > 0) { 598 x = env->hpos - thickness/2; 599 y = env->vpos + p[1] + thickness/2; 600 height = p[1] + thickness; 601 width = thickness; 602 } 603 else if (p[1] < 0) { 604 x = env->hpos - thickness/2; 605 y = env->vpos + thickness/2; 606 height = thickness - p[1]; 607 width = thickness; 608 } 609 } 610 else if (p[1] == 0) { 611 if (p[0] > 0) { 612 x = env->hpos - thickness/2; 613 y = env->vpos + thickness/2; 614 height = thickness; 615 width = p[0] + thickness; 616 } 617 else if (p[0] < 0) { 618 x = env->hpos - p[0] - thickness/2; 619 y = env->vpos + thickness/2; 620 height = thickness; 621 width = thickness - p[0]; 622 } 623 } 624 if (height != 0) { 625 moveto(x, y); 626 out1(put_rule); 627 out4(height); 628 out4(width); 629 } 630 } 631 else if (code == 't') { 632 if (np == 0) { 633 line_thickness = -1; 634 } 635 else { 636 // troff gratuitously adds an extra 0 637 if (np != 1 && np != 2) 638 error("0 or 1 argument required for thickness"); 639 else 640 line_thickness = p[0]; 641 } 642 } 643 else if (code == 'R') { 644 if (np != 2) 645 error("2 arguments required for rule"); 646 else if (p[0] != 0 || p[1] != 0) { 647 int dh = p[0]; 648 int dv = p[1]; 649 int oh = env->hpos; 650 int ov = env->vpos; 651 if (dv > 0) { 652 ov += dv; 653 dv = -dv; 654 } 655 if (dh < 0) { 656 oh += dh; 657 dh = -dh; 658 } 659 moveto(oh, ov); 660 out1(put_rule); 661 out4(-dv); 662 out4(dh); 663 } 664 } 665} 666 667// XXX Will this overflow? 668 669inline int milliinches(int n) 670{ 671 return (n*1000 + font::res/2)/font::res; 672} 673 674void draw_dvi_printer::set_line_thickness(const environment *env) 675{ 676 int desired_pen_size 677 = milliinches(line_thickness < 0 678 // Will this overflow? 679 ? env->size*RES_7227*linewidth/1000 680 : line_thickness); 681 if (desired_pen_size != output_pen_size) { 682 char buf[256]; 683 sprintf(buf, "pn %d", desired_pen_size); 684 do_special(buf); 685 output_pen_size = desired_pen_size; 686 } 687} 688 689void draw_dvi_printer::fill_next(const environment *env) 690{ 691 unsigned int g; 692 if (env->fill->is_default()) 693 g = 0; 694 else { 695 // currently, only BW support 696 env->fill->get_gray(&g); 697 } 698 char buf[256]; 699 sprintf(buf, "sh %.3g", 1 - double(g)/color::MAX_COLOR_VAL); 700 do_special(buf); 701} 702 703void draw_dvi_printer::draw(int code, int *p, int np, const environment *env) 704{ 705 char buf[1024]; 706 int fill_flag = 0; 707 switch (code) { 708 case 'C': 709 fill_flag = 1; 710 // fall through 711 case 'c': 712 { 713 // troff adds an extra argument to C 714 if (np != 1 && !(code == 'C' && np == 2)) { 715 error("1 argument required for circle"); 716 break; 717 } 718 moveto(env->hpos+p[0]/2, env->vpos); 719 if (fill_flag) 720 fill_next(env); 721 else 722 set_line_thickness(env); 723 int rad; 724 rad = milliinches(p[0]/2); 725 sprintf(buf, "%s 0 0 %d %d 0 6.28319", 726 (fill_flag ? "ia" : "ar"), 727 rad, 728 rad); 729 do_special(buf); 730 break; 731 } 732 case 'l': 733 if (np != 2) { 734 error("2 arguments required for line"); 735 break; 736 } 737 moveto(env->hpos, env->vpos); 738 set_line_thickness(env); 739 do_special("pa 0 0"); 740 sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1])); 741 do_special(buf); 742 do_special("fp"); 743 break; 744 case 'E': 745 fill_flag = 1; 746 // fall through 747 case 'e': 748 if (np != 2) { 749 error("2 arguments required for ellipse"); 750 break; 751 } 752 moveto(env->hpos+p[0]/2, env->vpos); 753 if (fill_flag) 754 fill_next(env); 755 sprintf(buf, "%s 0 0 %d %d 0 6.28319", 756 (fill_flag ? "ia" : "ar"), 757 milliinches(p[0]/2), 758 milliinches(p[1]/2)); 759 do_special(buf); 760 break; 761 case 'P': 762 fill_flag = 1; 763 // fall through 764 case 'p': 765 { 766 if (np & 1) { 767 error("even number of arguments required for polygon"); 768 break; 769 } 770 if (np == 0) { 771 error("no arguments for polygon"); 772 break; 773 } 774 moveto(env->hpos, env->vpos); 775 if (fill_flag) 776 fill_next(env); 777 else 778 set_line_thickness(env); 779 do_special("pa 0 0"); 780 int h = 0, v = 0; 781 for (int i = 0; i < np; i += 2) { 782 h += p[i]; 783 v += p[i+1]; 784 sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 785 do_special(buf); 786 } 787 do_special("pa 0 0"); 788 do_special(fill_flag ? "ip" : "fp"); 789 break; 790 } 791 case '~': 792 { 793 if (np & 1) { 794 error("even number of arguments required for spline"); 795 break; 796 } 797 if (np == 0) { 798 error("no arguments for spline"); 799 break; 800 } 801 moveto(env->hpos, env->vpos); 802 set_line_thickness(env); 803 do_special("pa 0 0"); 804 int h = 0, v = 0; 805 for (int i = 0; i < np; i += 2) { 806 h += p[i]; 807 v += p[i+1]; 808 sprintf(buf, "pa %d %d", milliinches(h), milliinches(v)); 809 do_special(buf); 810 } 811 do_special("sp"); 812 break; 813 } 814 case 'a': 815 { 816 if (np != 4) { 817 error("4 arguments required for arc"); 818 break; 819 } 820 set_line_thickness(env); 821 double c[2]; 822 if (adjust_arc_center(p, c)) { 823 int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5)); 824 moveto(env->hpos + int(c[0]), env->vpos + int(c[1])); 825 double start = atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]); 826 double end = atan2(-c[1], -c[0]); 827 if (end - start < 0) 828 start -= 2 * 3.14159265358; 829 sprintf(buf, "ar 0 0 %d %d %f %f", rad, rad, start, end); 830 do_special(buf); 831 } 832 else { 833 moveto(env->hpos, env->vpos); 834 do_special("pa 0 0"); 835 sprintf(buf, 836 "pa %d %d", 837 milliinches(p[0] + p[2]), 838 milliinches(p[1] + p[3])); 839 do_special(buf); 840 do_special("fp"); 841 } 842 break; 843 } 844 case 't': 845 { 846 if (np == 0) { 847 line_thickness = -1; 848 } 849 else { 850 // troff gratuitously adds an extra 0 851 if (np != 1 && np != 2) { 852 error("0 or 1 argument required for thickness"); 853 break; 854 } 855 line_thickness = p[0]; 856 } 857 break; 858 } 859 case 'R': 860 { 861 if (np != 2) { 862 error("2 arguments required for rule"); 863 break; 864 } 865 int dh = p[0]; 866 if (dh == 0) 867 break; 868 int dv = p[1]; 869 if (dv == 0) 870 break; 871 int oh = env->hpos; 872 int ov = env->vpos; 873 if (dv > 0) { 874 ov += dv; 875 dv = -dv; 876 } 877 if (dh < 0) { 878 oh += dh; 879 dh = -dh; 880 } 881 moveto(oh, ov); 882 out1(put_rule); 883 out4(-dv); 884 out4(dh); 885 break; 886 } 887 default: 888 error("unrecognised drawing command `%1'", char(code)); 889 break; 890 } 891} 892 893font *dvi_printer::make_font(const char *nm) 894{ 895 return dvi_font::load_dvi_font(nm); 896} 897 898printer *make_printer() 899{ 900 if (draw_flag) 901 return new draw_dvi_printer; 902 else 903 return new dvi_printer; 904} 905 906static void usage(FILE *stream); 907 908int main(int argc, char **argv) 909{ 910 setlocale(LC_NUMERIC, "C"); 911 program_name = argv[0]; 912 static char stderr_buf[BUFSIZ]; 913 setbuf(stderr, stderr_buf); 914 int c; 915 static const struct option long_options[] = { 916 { "help", no_argument, 0, CHAR_MAX + 1 }, 917 { "version", no_argument, 0, 'v' }, 918 { NULL, 0, 0, 0 } 919 }; 920 while ((c = getopt_long(argc, argv, "dF:I:lp:vw:", long_options, NULL)) 921 != EOF) 922 switch(c) { 923 case 'd': 924 draw_flag = 0; 925 break; 926 case 'l': 927 landscape_flag = 1; 928 break; 929 case 'F': 930 font::command_line_font_dir(optarg); 931 break; 932 case 'I': 933 // ignore include search path 934 break; 935 case 'p': 936 if (!font::scan_papersize(optarg, 0, 937 &user_paper_length, &user_paper_width)) 938 error("invalid custom paper size `%1' ignored", optarg); 939 break; 940 case 'v': 941 { 942 printf("GNU grodvi (groff) version %s\n", Version_string); 943 exit(0); 944 break; 945 } 946 case 'w': 947 if (sscanf(optarg, "%d", &linewidth) != 1 948 || linewidth < 0 || linewidth > 1000) { 949 error("bad line width"); 950 linewidth = DEFAULT_LINEWIDTH; 951 } 952 break; 953 case CHAR_MAX + 1: // --help 954 usage(stdout); 955 exit(0); 956 break; 957 case '?': 958 usage(stderr); 959 exit(1); 960 break; 961 default: 962 assert(0); 963 } 964 SET_BINARY(fileno(stdout)); 965 if (optind >= argc) 966 do_file("-"); 967 else { 968 for (int i = optind; i < argc; i++) 969 do_file(argv[i]); 970 } 971 return 0; 972} 973 974static void usage(FILE *stream) 975{ 976 fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n", 977 program_name); 978} 979