home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / groff / dvi / dvi.c next >
Encoding:
C/C++ Source or Header  |  1991-04-30  |  18.1 KB  |  896 lines

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