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