2
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001
3
Free Software Foundation, Inc.
4
Written by James Clark (jjc@jclark.com)
6
This file is part of groff.
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
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
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. */
25
extern "C" const char *Version_string;
27
#define DEFAULT_LINEWIDTH 40
28
static int linewidth = DEFAULT_LINEWIDTH;
30
static int draw_flag = 1;
32
/* These values were chosen because:
34
(MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
36
and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
38
The width in the groff font file is the product of MULTIPLIER and the
39
width in the tfm file. */
42
#define RES_7227 (RES/7227)
43
#define UNITWIDTH 131072
49
class dvi_font : public font {
50
dvi_font(const char *);
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 *);
60
dvi_font *dvi_font::load_dvi_font(const char *s)
62
dvi_font *f = new dvi_font(s);
70
dvi_font::dvi_font(const char *nm)
71
: font(nm), checksum(0), design_size(0)
79
void dvi_font::handle_unknown_font_command(const char *command,
81
const char *filename, int lineno)
84
if (strcmp(command, "checksum") == 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");
93
else if (strcmp(command, "designsize") == 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");
104
#define FONTS_MAX 256
109
output_font() : f(0) { }
112
class dvi_printer : public printer {
123
output_font output_font_table[FONTS_MAX];
132
void define_font(int);
134
void possibly_begin_line();
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 *);
170
font *make_font(const char *);
171
void begin_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);
176
void draw(int code, int *p, int np, const environment *env);
180
class draw_dvi_printer : public dvi_printer {
183
void set_line_thickness(const environment *);
188
void draw(int code, int *p, int np, const environment *env);
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)
196
if (font::res != RES)
197
fatal("resolution must be %1", RES);
198
if (font::unitwidth != UNITWIDTH)
199
fatal("unitwidth must be %1", UNITWIDTH);
201
fatal("hor must be equal to 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
210
dvi_printer::~dvi_printer()
216
draw_dvi_printer::draw_dvi_printer()
217
: output_pen_size(-1), fill(FILL_MAX)
221
draw_dvi_printer::~draw_dvi_printer()
226
void dvi_printer::out1(int n)
232
void dvi_printer::out2(int n)
235
putc((n >> 8) & 0xff, fp);
239
void dvi_printer::out3(int n)
242
putc((n >> 16) & 0xff, fp);
243
putc((n >> 8) & 0xff, fp);
247
void dvi_printer::out4(int n)
250
putc((n >> 24) & 0xff, fp);
251
putc((n >> 16) & 0xff, fp);
252
putc((n >> 8) & 0xff, fp);
256
void dvi_printer::out_string(const char *s)
264
void dvi_printer::end_of_line()
274
void dvi_printer::possibly_begin_line()
277
have_pushed = pushed = 1;
284
int scale(int x, int z)
289
alpha = 16*z; beta = 16;
290
while (z >= 040000000L) {
297
sw = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
306
void dvi_printer::set_char(int index, font *f, const environment *env, int w, const char *name)
308
int code = f->get_code(index);
309
if (env->size != cur_point_size || f != cur_font) {
311
cur_point_size = env->size;
314
if (i >= FONTS_MAX) {
315
fatal("too many output fonts required");
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;
322
if (output_font_table[i].f == cur_font
323
&& output_font_table[i].point_size == cur_point_size)
328
int distance = env->hpos - cur_h;
329
if (env->hpos != end_h && distance != 0) {
330
out_signed(right1, distance);
333
else if (distance > max_drift) {
334
out_signed(right1, distance - max_drift);
335
cur_h = env->hpos - max_drift;
337
else if (distance < -max_drift) {
338
out_signed(right1, distance + max_drift);
339
cur_h = env->hpos + max_drift;
341
if (env->vpos != cur_v) {
342
out_signed(down1, env->vpos - cur_v);
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);
353
if (code >= 0 && code <= 127)
356
out_unsigned(set1, code);
359
void dvi_printer::define_font(int i)
361
out_unsigned(fnt_def1, i);
362
dvi_font *f = output_font_table[i].f;
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();
371
void dvi_printer::set_font(int i)
373
if (i >= 0 && i <= 63)
376
out_unsigned(fnt1, i);
379
void dvi_printer::out_signed(unsigned char base, int param)
381
if (-128 <= param && param < 128) {
385
else if (-32768 <= param && param < 32768) {
389
else if (-(1 << 23) <= param && param < (1 << 23)) {
399
void dvi_printer::out_unsigned(unsigned char base, int param)
406
else if (param < 65536) {
410
else if (param < (1 << 24)) {
425
void dvi_printer::preamble()
435
void dvi_printer::postamble()
437
int tem = byte_count;
445
out2(have_pushed); // stack depth
448
for (i = 0; i < FONTS_MAX && output_font_table[i].f != 0; i++)
453
for (i = 0; i < 4 || byte_count % 4 != 0; i++)
457
void dvi_printer::begin_page(int i)
460
int tem = byte_count;
463
for (int j = 1; j < 10; j++)
467
// By convention position (0,0) in a dvi file is placed at (1in, 1in).
473
void dvi_printer::end_page(int)
481
void draw_dvi_printer::end_page(int len)
483
dvi_printer::end_page(len);
484
output_pen_size = -1;
487
void dvi_printer::do_special(const char *s)
492
possibly_begin_line();
493
out_unsigned(xxx1, len);
498
void dvi_printer::special(char *arg, const environment *env, char type)
502
moveto(env->hpos, env->vpos);
506
void dvi_printer::moveto(int h, int v)
509
out_signed(right1, h - cur_h);
515
out_signed(down1, v - cur_v);
523
void dvi_printer::draw(int code, int *p, int np, const environment *env)
527
int height = 0, width = 0;
529
if (line_thickness < 0)
530
thickness = env->size*RES_7227*linewidth/1000;
531
else if (line_thickness > 0)
532
thickness = line_thickness;
536
error("2 arguments required for line");
538
else if (p[0] == 0) {
541
x = env->hpos - thickness/2;
542
y = env->vpos + p[1] + thickness/2;
543
height = p[1] + thickness;
547
x = env->hpos - thickness/2;
548
y = env->vpos + thickness/2;
549
height = thickness - p[1];
553
else if (p[1] == 0) {
555
x = env->hpos - thickness/2;
556
y = env->vpos + thickness/2;
558
width = p[0] + thickness;
561
x = env->hpos - p[0] - thickness/2;
562
y = env->vpos + thickness/2;
564
width = thickness - p[0];
574
else if (code == 't') {
579
// troff gratuitously adds an extra 0
580
if (np != 1 && np != 2)
581
error("0 or 1 argument required for thickness");
583
line_thickness = p[0];
586
else if (code == 'R') {
588
error("2 arguments required for rule");
589
else if (p[0] != 0 || p[1] != 0) {
610
// XXX Will this overflow?
612
inline int milliinches(int n)
614
return (n*1000 + font::res/2)/font::res;
617
void draw_dvi_printer::set_line_thickness(const environment *env)
620
= milliinches(line_thickness < 0
621
// Will this overflow?
622
? env->size*RES_7227*linewidth/1000
624
if (desired_pen_size != output_pen_size) {
626
sprintf(buf, "pn %d", desired_pen_size);
628
output_pen_size = desired_pen_size;
632
void draw_dvi_printer::fill_next()
635
sprintf(buf, "sh %.3f", double(fill)/FILL_MAX);
639
void draw_dvi_printer::draw(int code, int *p, int np, const environment *env)
648
// troff adds an extra argument to C
649
if (np != 1 && !(code == 'C' && np == 2)) {
650
error("1 argument required for circle");
653
moveto(env->hpos+p[0]/2, env->vpos);
657
set_line_thickness(env);
659
rad = milliinches(p[0]/2);
660
sprintf(buf, "%s 0 0 %d %d 0 6.28319",
661
(fill_flag ? "ia" : "ar"),
668
error("2 arguments required for line");
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]));
683
error("2 arguments required for ellipse");
686
moveto(env->hpos+p[0]/2, env->vpos);
689
sprintf(buf, "%s 0 0 %d %d 0 6.28319",
690
(fill_flag ? "ia" : "ar"),
692
milliinches(p[1]/2));
701
error("even number of arguments required for polygon");
705
error("no arguments for polygon");
708
moveto(env->hpos, env->vpos);
712
set_line_thickness(env);
713
do_special("pa 0 0");
715
for (int i = 0; i < np; i += 2) {
718
sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
721
do_special("pa 0 0");
722
do_special(fill_flag ? "ip" : "fp");
728
error("even number of arguments required for spline");
732
error("no arguments for spline");
735
moveto(env->hpos, env->vpos);
736
set_line_thickness(env);
737
do_special("pa 0 0");
739
for (int i = 0; i < np; i += 2) {
742
sprintf(buf, "pa %d %d", milliinches(h), milliinches(v));
751
error("4 arguments required for arc");
754
set_line_thickness(env);
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",
762
atan2(p[1] + p[3] - c[1], p[0] + p[2] - c[0]),
763
atan2(-c[1], -c[0]));
767
moveto(env->hpos, env->vpos);
768
do_special("pa 0 0");
771
milliinches(p[0] + p[2]),
772
milliinches(p[1] + p[3]));
784
// troff gratuitously adds an extra 0
785
if (np != 1 && np != 2) {
786
error("0 or 1 argument required for thickness");
789
line_thickness = p[0];
795
if (np != 1 && np != 2) {
796
error("1 argument required for fill");
800
if (fill < 0 || fill > FILL_MAX)
807
error("2 arguments required for rule");
833
error("unrecognised drawing command `%1'", char(code));
838
font *dvi_printer::make_font(const char *nm)
840
return dvi_font::load_dvi_font(nm);
843
printer *make_printer()
846
return new draw_dvi_printer;
848
return new dvi_printer;
851
static void usage(FILE *stream);
853
int main(int argc, char **argv)
855
program_name = argv[0];
856
static char stderr_buf[BUFSIZ];
857
setbuf(stderr, stderr_buf);
859
static const struct option long_options[] = {
860
{ "help", no_argument, 0, CHAR_MAX + 1 },
861
{ "version", no_argument, 0, 'v' },
864
while ((c = getopt_long(argc, argv, "F:vw:d", long_options, NULL)) != EOF)
868
printf("GNU grodvi (groff) version %s\n", Version_string);
873
if (sscanf(optarg, "%d", &linewidth) != 1
874
|| linewidth < 0 || linewidth > 1000) {
875
error("bad line width");
876
linewidth = DEFAULT_LINEWIDTH;
883
font::command_line_font_dir(optarg);
885
case CHAR_MAX + 1: // --help
897
SET_BINARY(fileno(stdout));
902
for (int i = optind; i < argc; i++)
909
static void usage(FILE *stream)
911
fprintf(stream, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",