home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / grodvi / dvi.cc next >
C/C++ Source or Header  |  1995-06-22  |  19KB  |  897 lines

  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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.  
  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.  
  66. dvi_font::dvi_font(const char *nm)
  67. : font(nm), checksum(0), design_size(0)
  68. {
  69. }
  70.  
  71. dvi_font::~dvi_font()
  72. {
  73. }
  74.  
  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;
  105.   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.  
  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.  
  206. dvi_printer::~dvi_printer()
  207. {
  208.   postamble();
  209. }
  210.  
  211.  
  212. draw_dvi_printer::draw_dvi_printer()
  213. : output_pen_size(-1), fill(FILL_MAX)
  214. {
  215. }
  216.  
  217. draw_dvi_printer::~draw_dvi_printer()
  218. {
  219. }
  220.  
  221.  
  222. void dvi_printer::out1(int n)
  223. {
  224.   byte_count += 1;
  225.   putc(n & 0xff, fp);
  226. }
  227.  
  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.  
  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.  
  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.  
  252. void dvi_printer::out_string(const char *s)
  253. {
  254.   out1(strlen(s));
  255.   while (*s != 0)
  256.     out1(*s++);
  257. }
  258.  
  259.  
  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.  
  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.  
  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.  
  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.     int i;
  309.     for (i = 0;; i++) {
  310.       if (i >= FONTS_MAX) {
  311.     fatal("too many output fonts required");
  312.       }
  313.       if (output_font_table[i].f == 0) {
  314.     output_font_table[i].f = (dvi_font *)cur_font;
  315.     output_font_table[i].point_size = cur_point_size;
  316.     define_font(i);
  317.       }
  318.       if (output_font_table[i].f == cur_font
  319.       && output_font_table[i].point_size == cur_point_size)
  320.     break;
  321.     }
  322.     set_font(i);
  323.   }
  324.   int distance = env->hpos - cur_h;
  325.   if (env->hpos != end_h && distance != 0) {
  326.     out_signed(right1, distance);
  327.     cur_h = env->hpos;
  328.   }
  329.   else if (distance > max_drift) {
  330.     out_signed(right1, distance - max_drift);
  331.     cur_h = env->hpos - max_drift;
  332.   }
  333.   else if (distance < -max_drift) {
  334.     out_signed(right1, distance + max_drift);
  335.     cur_h = env->hpos + max_drift;
  336.   }
  337.   if (env->vpos != cur_v) {
  338.     out_signed(down1, env->vpos - cur_v);
  339.     cur_v = env->vpos;
  340.   }
  341.   possibly_begin_line();
  342.   end_h = env->hpos + w;
  343.   cur_h += scale(f->get_width(index, UNITWIDTH)/MULTIPLIER,
  344.         cur_point_size*RES_7227);
  345.   if (cur_h > max_h)
  346.     max_h = cur_h;
  347.   if (cur_v > max_v)
  348.     max_v = cur_v;
  349.   if (code >= 0 && code <= 127)
  350.     out1(code);
  351.   else
  352.     out_unsigned(set1, code);
  353. }
  354.  
  355. void dvi_printer::define_font(int i)
  356. {
  357.   out_unsigned(fnt_def1, i);
  358.   dvi_font *f = output_font_table[i].f;
  359.   out4(f->checksum);
  360.   out4(output_font_table[i].point_size*RES_7227);
  361.   out4(int((double(f->design_size)/(1<<20))*RES_7227*100 + .5));
  362.   const char *nm = f->get_internal_name();
  363.   out1(0);
  364.   out_string(nm);
  365. }
  366.  
  367. void dvi_printer::set_font(int i)
  368. {
  369.   if (i >= 0 && i <= 63)
  370.     out1(fnt_num_0 + i);
  371.   else
  372.     out_unsigned(fnt1, i);
  373. }
  374.  
  375. void dvi_printer::out_signed(unsigned char base, int param)
  376. {
  377.   if (-128 <= param && param < 128) {
  378.     out1(base);
  379.     out1(param);
  380.   }
  381.   else if (-32768 <= param && param < 32768) {
  382.     out1(base+1);
  383.     out2(param);
  384.   }
  385.   else if (-(1 << 23) <= param && param < (1 << 23)) {
  386.     out1(base+2);
  387.     out3(param);
  388.   }
  389.   else {
  390.     out1(base+3);
  391.     out4(param);
  392.   }
  393. }
  394.  
  395. void dvi_printer::out_unsigned(unsigned char base, int param)
  396. {
  397.   if (param >= 0) {
  398.     if (param < 256) {
  399.       out1(base);
  400.       out1(param);
  401.     }
  402.     else if (param < 65536) {
  403.       out1(base+1);
  404.       out2(param);
  405.     }
  406.     else if (param < (1 << 24)) {
  407.       out1(base+2);
  408.       out3(param);
  409.     }
  410.     else {
  411.       out1(base+3);
  412.       out4(param);
  413.     }
  414.   }
  415.   else {
  416.     out1(base+3);
  417.     out4(param);
  418.   }
  419. }
  420.  
  421. void dvi_printer::preamble()
  422. {
  423.   out1(pre);
  424.   out1(id_byte);
  425.   out4(254000);
  426.   out4(font::res);
  427.   out4(1000);
  428.   out1(0);
  429. }
  430.  
  431. void dvi_printer::postamble()
  432. {
  433.   int tem = byte_count;
  434.   out1(post);
  435.   out4(last_bop);
  436.   out4(254000);
  437.   out4(font::res);
  438.   out4(1000);
  439.   out4(max_v);
  440.   out4(max_h);
  441.   out2(have_pushed); // stack depth
  442.   out2(page_count);
  443.   int i;
  444.   for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++)
  445.     define_font(i);
  446.   out1(post_post);
  447.   out4(tem);
  448.   out1(id_byte);
  449.   for (i = 0; i < 4 || byte_count % 4 != 0; i++)
  450.     out1(filler);
  451. }  
  452.   
  453. void dvi_printer::begin_page(int i)
  454. {
  455.   page_count++;
  456.   int tem = byte_count;
  457.   out1(bop);
  458.   out4(i);
  459.   for (int j = 1; j < 10; j++)
  460.     out4(0);
  461.   out4(last_bop);
  462.   last_bop = tem;
  463.   // By convention position (0,0) in a dvi file is placed at (1in, 1in).
  464.   cur_h = font::res;
  465.   cur_v = font::res;
  466.   end_h = 0;
  467. }
  468.  
  469. void dvi_printer::end_page(int)
  470. {
  471.   if (pushed)
  472.     end_of_line();
  473.   out1(eop);
  474.   cur_font = 0;
  475. }
  476.  
  477. void draw_dvi_printer::end_page(int len)
  478. {
  479.   dvi_printer::end_page(len);
  480.   output_pen_size = -1;
  481. }
  482.  
  483. void dvi_printer::do_special(const char *s)
  484. {
  485.   int len = strlen(s);
  486.   if (len == 0)
  487.     return;
  488.   possibly_begin_line();
  489.   out_unsigned(xxx1, len);
  490.   while (*s)
  491.     out1(*s++);
  492. }
  493.  
  494. void dvi_printer::special(char *arg, const environment *env)
  495. {
  496.   moveto(env->hpos, env->vpos);
  497.   do_special(arg);
  498. }
  499.  
  500. void dvi_printer::moveto(int h, int v)
  501. {
  502.   if (h != cur_h) {
  503.     out_signed(right1, h - cur_h);
  504.     cur_h = h;
  505.     if (cur_h > max_h)
  506.       max_h = cur_h;
  507.   }
  508.   if (v != cur_v) {
  509.     out_signed(down1, v - cur_v);
  510.     cur_v = v;
  511.     if (cur_v > max_v)
  512.       max_v = cur_v;
  513.   }
  514.   end_h = 0;
  515. }
  516.  
  517. void dvi_printer::draw(int code, int *p, int np, const environment *env)
  518. {
  519.   if (code == 'l') {
  520.     int x, y;
  521.     int height = 0, width;
  522.     int thickness;
  523.     if (line_thickness < 0)
  524.       thickness = env->size*RES_7227*linewidth/1000;
  525.     else if (line_thickness > 0)
  526.       thickness = line_thickness;
  527.     else
  528.       thickness = 1;
  529.     if (np != 2) {
  530.       error("2 arguments required for line");
  531.     }
  532.     else if (p[0] == 0) {
  533.       // vertical rule
  534.       if (p[1] > 0) {
  535.     x = env->hpos - thickness/2;
  536.     y = env->vpos + p[1] + thickness/2;
  537.     height = p[1] + thickness;
  538.     width = thickness;
  539.       }
  540.       else if (p[1] < 0) {
  541.     x = env->hpos - thickness/2;
  542.     y = env->vpos + thickness/2;
  543.     height = thickness - p[1];
  544.     width = thickness;
  545.       }
  546.     }
  547.     else if (p[1] == 0) {
  548.       if (p[0] > 0) {
  549.     x = env->hpos - thickness/2;
  550.     y = env->vpos + thickness/2;
  551.     height = thickness;
  552.     width = p[0] + thickness;
  553.       }
  554.       else if (p[0] < 0) {
  555.     x = env->hpos - p[0] - thickness/2;
  556.     y = env->vpos + thickness/2;
  557.     height = thickness;
  558.     width = thickness - p[0];
  559.       }
  560.     }
  561.     if (height != 0) {
  562.       moveto(x, y);
  563.       out1(put_rule);
  564.       out4(height);
  565.       out4(width);
  566.     }
  567.   }
  568.   else if (code == 't') {
  569.     if (np == 0) {
  570.       line_thickness = -1;
  571.     }
  572.     else {
  573.       // troff gratuitously adds an extra 0
  574.       if (np != 1 && np != 2)
  575.     error("0 or 1 argument required for thickness");
  576.       else
  577.     line_thickness = p[0];
  578.     }
  579.   }
  580.   else if (code == 'R') {
  581.     if (np != 2)
  582.       error("2 arguments required for rule");
  583.     else if (p[0] != 0 || p[1] != 0) {
  584.       int dh = p[0];
  585.       int dv = p[1];
  586.       int oh = env->hpos;
  587.       int ov = env->vpos;
  588.       if (dv > 0) {
  589.     ov += dv;
  590.     dv = -dv;
  591.       }
  592.       if (dh < 0) {
  593.     oh += dh;
  594.     dh = -dh;
  595.       }
  596.       moveto(oh, ov);
  597.       out1(put_rule);
  598.       out4(-dv);
  599.       out4(dh);
  600.     }
  601.   }
  602. }
  603.  
  604. // XXX Will this overflow?
  605.  
  606. inline int milliinches(int n)
  607. {
  608.   return (n*1000 + font::res/2)/font::res;
  609. }
  610.  
  611. void draw_dvi_printer::set_line_thickness(const environment *env)
  612. {
  613.   int desired_pen_size
  614.     = milliinches(line_thickness < 0
  615.           // Will this overflow?
  616.           ? env->size*RES_7227*linewidth/1000
  617.           : line_thickness);
  618.   if (desired_pen_size != output_pen_size) {
  619.     char buf[256];
  620.     sprintf(buf, "pn %d", desired_pen_size);
  621.     do_special(buf);
  622.     output_pen_size = desired_pen_size;
  623.   }
  624. }
  625.  
  626. void draw_dvi_printer::fill_next()
  627. {
  628.   char buf[256];
  629.   sprintf(buf, "sh %.3f", double(fill)/FILL_MAX);
  630.   do_special(buf);
  631. }
  632.  
  633. void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
  634. {
  635.   char buf[1024];
  636.   int fill_flag = 0;
  637.   switch (code) {
  638.   case 'C':
  639.     fill_flag = 1;
  640.     // fall through
  641.   case 'c':
  642.     // troff adds an extra argument to C
  643.     if (np != 1 && !(code == 'C' && np == 2)) {
  644.       error("1 argument required for circle");
  645.       break;
  646.     }
  647.     moveto(env->hpos+p[0]/2, env->vpos);
  648.     if (fill_flag)
  649.       fill_next();
  650.     else
  651.       set_line_thickness(env);
  652.     int rad;
  653.     rad = milliinches(p[0]/2);
  654.     sprintf(buf, "%s 0 0 %d %d 0 6.28319",
  655.         (fill_flag ? "ia" : "ar"),
  656.         rad,
  657.         rad);
  658.     do_special(buf);
  659.     break;
  660.   case 'l':
  661.     if (np != 2) {
  662.       error("2 arguments required for line");
  663.       break;
  664.     }
  665.     moveto(env->hpos, env->vpos);
  666.     set_line_thickness(env);
  667.     do_special("pa 0 0");
  668.     sprintf(buf, "pa %d %d", milliinches(p[0]), milliinches(p[1]));
  669.     do_special(buf);
  670.     do_special("fp");
  671.     break;
  672.   case 'E':
  673.     fill_flag = 1;
  674.     // fall through
  675.   case 'e':
  676.     if (np != 2) {
  677.       error("2 arguments required for ellipse");
  678.       break;
  679.     }
  680.     moveto(env->hpos+p[0]/2, env->vpos);
  681.     if (fill_flag)
  682.       fill_next();
  683.     sprintf(buf, "%s 0 0 %d %d 0 6.28319",
  684.         (fill_flag ? "ia" : "ar"),
  685.         milliinches(p[0]/2),
  686.         milliinches(p[1]/2));
  687.     do_special(buf);
  688.     break;
  689.   case 'P':
  690.     fill_flag = 1;
  691.     // fall through
  692.   case 'p':
  693.     {
  694.       if (np & 1) {
  695.     error("even number of arguments required for polygon");
  696.     break;
  697.       }
  698.       if (np == 0) {
  699.     error("no arguments for polygon");
  700.     break;
  701.       }
  702.       moveto(env->hpos, env->vpos);
  703.       if (fill_flag)
  704.     fill_next();
  705.       else
  706.     set_line_thickness(env);
  707.       do_special("pa 0 0");
  708.       int h = 0, v = 0;
  709.       for (int i = 0; i < np; i += 2) {
  710.     h += p[i];
  711.     v += p[i+1];
  712.     sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
  713.     do_special(buf);
  714.       }
  715.       do_special("pa 0 0");
  716.       do_special(fill_flag ? "ip" : "fp");
  717.       break;
  718.     }
  719.   case '~':
  720.     {
  721.       if (np & 1) {
  722.     error("even number of arguments required for spline");
  723.     break;
  724.       }
  725.       if (np == 0) {
  726.     error("no arguments for spline");
  727.     break;
  728.       }
  729.       moveto(env->hpos, env->vpos);
  730.       set_line_thickness(env);
  731.       do_special("pa 0 0");
  732.       int h = 0, v = 0;
  733.       for (int i = 0; i < np; i += 2) {
  734.     h += p[i];
  735.     v += p[i+1];
  736.     sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
  737.     do_special(buf);
  738.       }
  739.       do_special("sp");
  740.       break;
  741.     }
  742.   case 'a':
  743.     {
  744.       if (np != 4) {
  745.     error("4 arguments required for arc");
  746.     break;
  747.       }
  748.       set_line_thickness(env);
  749.       double c[2];
  750.       if (adjust_arc_center(p, c)) {
  751.     int rad = milliinches(int(sqrt(c[0]*c[0] + c[1]*c[1]) + .5));
  752.     moveto(env->hpos + int(c[0]), env->vpos + int(c[1]));
  753.     sprintf(buf, "ar 0 0 %d %d %f %f",
  754.         rad,
  755.         rad,
  756.         atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]),
  757.         atan2(-c[1], -c[0]));
  758.     do_special(buf);
  759.       }
  760.       else {
  761.     moveto(env->hpos, env->vpos);
  762.     do_special("pa 0 0");
  763.     sprintf(buf,
  764.         "pa %d %d",
  765.         milliinches(p[0] + p[2]),
  766.         milliinches(p[1] + p[3]));
  767.     do_special(buf);
  768.     do_special("fp");
  769.       }
  770.       break;
  771.     }
  772.   case 't':
  773.     {
  774.       if (np == 0) {
  775.     line_thickness = -1;
  776.       }
  777.       else {
  778.     // troff gratuitously adds an extra 0
  779.     if (np != 1 && np != 2) {
  780.       error("0 or 1 argument required for thickness");
  781.       break;
  782.     }
  783.     line_thickness = p[0];
  784.       }
  785.       break;
  786.     }
  787.   case 'f':
  788.     {
  789.       if (np != 1 && np != 2) {
  790.     error("1 argument required for fill");
  791.     break;
  792.       }
  793.       fill = p[0];
  794.       if (fill < 0 || fill > FILL_MAX)
  795.     fill = FILL_MAX;
  796.       break;
  797.     }
  798.   case 'R':
  799.     {
  800.       if (np != 2) {
  801.     error("2 arguments required for rule");
  802.     break;
  803.       }
  804.       int dh = p[0];
  805.       if (dh == 0)
  806.     break;
  807.       int dv = p[1];
  808.       if (dv == 0)
  809.     break;
  810.       int oh = env->hpos;
  811.       int ov = env->vpos;
  812.       if (dv > 0) {
  813.     ov += dv;
  814.     dv = -dv;
  815.       }
  816.       if (dh < 0) {
  817.     oh += dh;
  818.     dh = -dh;
  819.       }
  820.       moveto(oh, ov);
  821.       out1(put_rule);
  822.       out4(-dv);
  823.       out4(dh);
  824.       break;
  825.     }
  826.   default:
  827.     error("unrecognised drawing command `%1'", char(code));
  828.     break;
  829.   }
  830. }
  831.  
  832. font *dvi_printer::make_font(const char *nm)
  833. {
  834.   return dvi_font::load_dvi_font(nm);
  835. }
  836.  
  837. printer *make_printer()
  838. {
  839.   if (draw_flag)
  840.     return new draw_dvi_printer;
  841.   else
  842.     return new dvi_printer;
  843. }
  844.  
  845. static void usage();
  846.  
  847. int main(int argc, char **argv)
  848. {
  849.   program_name = argv[0];
  850.   static char stderr_buf[BUFSIZ];
  851.   setbuf(stderr, stderr_buf);
  852.   int c;
  853.   while ((c = getopt(argc, argv, "F:vw:d")) != EOF)
  854.     switch(c) {
  855.     case 'v':
  856.       {
  857.     extern const char *version_string;
  858.     fprintf(stderr, "grodvi version %s\n", version_string);
  859.     fflush(stderr);
  860.     break;
  861.       }
  862.     case 'w':
  863.       if (sscanf(optarg, "%d", &linewidth) != 1
  864.       || linewidth < 0 || linewidth > 1000) {
  865.     error("bad line width");
  866.     linewidth = DEFAULT_LINEWIDTH;
  867.       }
  868.       break;
  869.     case 'd':
  870.       draw_flag = 0;
  871.       break;
  872.     case 'F':
  873.       font::command_line_font_dir(optarg);
  874.       break;
  875.     case '?':
  876.       usage();
  877.       break;
  878.     default:
  879.       assert(0);
  880.     }
  881.   if (optind >= argc)
  882.     do_file("-");
  883.   else {
  884.     for (int i = optind; i < argc; i++)
  885.       do_file(argv[i]);
  886.   }
  887.   delete pr;
  888.   return 0;
  889. }
  890.  
  891. static void usage()
  892. {
  893.   fprintf(stderr, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",
  894.       program_name);
  895.   exit(1);
  896. }
  897.