groff: update vendor branch to v1.20.1
[dragonfly.git] / contrib / groff / src / devices / grodvi / dvi.cpp
CommitLineData
92d0a6a6 1// -*- C++ -*-
4d3e9548
JL
2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2006,
3 2007, 2009
92d0a6a6
JR
4 Free Software Foundation, Inc.
5 Written by James Clark (jjc@jclark.com)
6
7This file is part of groff.
8
9groff is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
4d3e9548
JL
11Software Foundation, either version 3 of the License, or
12(at your option) any later version.
92d0a6a6
JR
13
14groff is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17for more details.
18
4d3e9548
JL
19You should have received a copy of the GNU General Public License
20along with this program. If not, see <http://www.gnu.org/licenses/>. */
92d0a6a6
JR
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);
4d3e9548
JL
178 void set_char(glyph *, font *, const environment *, int, const char *);
179 void special(char *, const environment *, char);
92d0a6a6 180 void end_of_line();
4d3e9548 181 void draw(int, int *, int, const environment *);
92d0a6a6
JR
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
4d3e9548 343void dvi_printer::set_char(glyph *g, font *f, const environment *env,
92d0a6a6
JR
344 int w, const char *)
345{
346 if (*env->col != cur_color)
347 set_color(env->col);
4d3e9548 348 int code = f->get_code(g);
92d0a6a6
JR
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;
4d3e9548
JL
387 cur_h += scale(f->get_width(g, UNITWIDTH) / MULTIPLIER,
388 cur_point_size * RES_7227);
92d0a6a6
JR
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);
4d3e9548
JL
755 else
756 set_line_thickness(env);
92d0a6a6
JR
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}