~ubuntu-branches/ubuntu/dapper/groff/dapper

« back to all changes in this revision

Viewing changes to src/devices/grodvi/dvi.cc

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson
  • Date: 2002-03-17 04:11:50 UTC
  • Revision ID: james.westby@ubuntu.com-20020317041150-wkgfawjc3gxlk0o5
Tags: upstream-1.17.2
ImportĀ upstreamĀ versionĀ 1.17.2

Show diffs side-by-side

added added

removed removed

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