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