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