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