1 /* $NetBSD: dvi.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $ */
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
8 This file is part of groff.
9
10 groff is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free
12 Software Foundation; either version 2, or (at your option) any later
13 version.
14
15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 for more details.
19
20 You should have received a copy of the GNU General Public License along
21 with groff; see the file COPYING. If not, write to the Free Software
22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
23
24 #include "driver.h"
25 #include "nonposix.h"
26 #include "paper.h"
27
28 extern "C" const char *Version_string;
29
30 #define DEFAULT_LINEWIDTH 40
31 static int linewidth = DEFAULT_LINEWIDTH;
32
33 static int draw_flag = 1;
34
35 static int landscape_flag = 0;
36 static double user_paper_length = 0;
37 static double user_paper_width = 0;
38
39 /* These values were chosen because:
40
41 (MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
42
43 and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
44
45 The width in the groff font file is the product of MULTIPLIER and the
46 width 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
54 class dvi_font : public font {
55 dvi_font(const char *);
56 public:
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
load_dvi_font(const char * s)65 dvi_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
dvi_font(const char * nm)75 dvi_font::dvi_font(const char *nm)
76 : font(nm), checksum(0), design_size(0)
77 {
78 }
79
~dvi_font()80 dvi_font::~dvi_font()
81 {
82 }
83
handle_unknown_font_command(const char * command,const char * arg,const char * filename,int lineno)84 void 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
111 struct output_font {
112 dvi_font *f;
113 int point_size;
output_fontoutput_font114 output_font() : f(0) { }
115 };
116
117 class 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 *);
142 protected:
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 *);
174 public:
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
187 class draw_dvi_printer : public dvi_printer {
188 int output_pen_size;
189 void set_line_thickness(const environment *);
190 void fill_next(const environment *);
191 public:
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
dvi_printer()198 dvi_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
~dvi_printer()216 dvi_printer::~dvi_printer()
217 {
218 postamble();
219 }
220
221
draw_dvi_printer()222 draw_dvi_printer::draw_dvi_printer()
223 : output_pen_size(-1)
224 {
225 }
226
~draw_dvi_printer()227 draw_dvi_printer::~draw_dvi_printer()
228 {
229 }
230
231
out1(int n)232 void dvi_printer::out1(int n)
233 {
234 byte_count += 1;
235 putc(n & 0xff, fp);
236 }
237
out2(int n)238 void dvi_printer::out2(int n)
239 {
240 byte_count += 2;
241 putc((n >> 8) & 0xff, fp);
242 putc(n & 0xff, fp);
243 }
244
out3(int n)245 void 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
out4(int n)253 void 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
out_string(const char * s)262 void dvi_printer::out_string(const char *s)
263 {
264 out1(strlen(s));
265 while (*s != 0)
266 out1(*s++);
267 }
268
269
end_of_line()270 void 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
possibly_begin_line()280 void 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
scale(int x,int z)290 int 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
set_color(color * col)311 void 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
set_char(int idx,font * f,const environment * env,int w,const char *)345 void 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
define_font(int i)401 void 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
set_font(int i)413 void 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
out_signed(unsigned char base,int param)421 void 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
out_unsigned(unsigned char base,int param)441 void 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
preamble()467 void 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
postamble()477 void 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
begin_page(int i)499 void 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
end_page(int)531 void 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
end_page(int len)540 void draw_dvi_printer::end_page(int len)
541 {
542 dvi_printer::end_page(len);
543 output_pen_size = -1;
544 }
545
do_special(const char * s)546 void 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
special(char * arg,const environment * env,char type)557 void 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
moveto(int h,int v)565 void 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
draw(int code,int * p,int np,const environment * env)582 void 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
milliinches(int n)671 inline int milliinches(int n)
672 {
673 return (n*1000 + font::res/2)/font::res;
674 }
675
set_line_thickness(const environment * env)676 void 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
fill_next(const environment * env)691 void 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
draw(int code,int * p,int np,const environment * env)705 void 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
make_font(const char * nm)895 font *dvi_printer::make_font(const char *nm)
896 {
897 return dvi_font::load_dvi_font(nm);
898 }
899
make_printer()900 printer *make_printer()
901 {
902 if (draw_flag)
903 return new draw_dvi_printer;
904 else
905 return new dvi_printer;
906 }
907
908 static void usage(FILE *stream);
909
main(int argc,char ** argv)910 int 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
usage(FILE * stream)976 static void usage(FILE *stream)
977 {
978 fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",
979 program_name);
980 }
981