2 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
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, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
26 extern "C" const char *Version_string
;
28 #define DEFAULT_LINEWIDTH 40
29 static int linewidth
= DEFAULT_LINEWIDTH
;
31 static int draw_flag
= 1;
33 static int landscape_flag
= 0;
34 static double user_paper_length
= 0;
35 static double user_paper_width
= 0;
37 /* These values were chosen because:
39 (MULTIPLIER*SIZESCALE)/(RES*UNITWIDTH) == 1/(2^20 * 72.27)
41 and 57816 is an exact multiple of both 72.27*SIZESCALE and 72.
43 The width in the groff font file is the product of MULTIPLIER and the
44 width in the tfm file. */
47 #define RES_7227 (RES/7227)
48 #define UNITWIDTH 131072
52 class dvi_font
: public font
{
53 dvi_font(const char *);
58 void handle_unknown_font_command(const char *command
, const char *arg
,
59 const char *filename
, int lineno
);
60 static dvi_font
*load_dvi_font(const char *);
63 dvi_font
*dvi_font::load_dvi_font(const char *s
)
65 dvi_font
*f
= new dvi_font(s
);
73 dvi_font::dvi_font(const char *nm
)
74 : font(nm
), checksum(0), design_size(0)
82 void dvi_font::handle_unknown_font_command(const char *command
,
84 const char *filename
, int lineno
)
87 if (strcmp(command
, "checksum") == 0) {
89 fatal_with_file_and_line(filename
, lineno
,
90 "`checksum' command requires an argument");
91 checksum
= int(strtol(arg
, &ptr
, 10));
92 if (checksum
== 0 && ptr
== arg
) {
93 fatal_with_file_and_line(filename
, lineno
, "bad checksum");
96 else if (strcmp(command
, "designsize") == 0) {
98 fatal_with_file_and_line(filename
, lineno
,
99 "`designsize' command requires an argument");
100 design_size
= int(strtol(arg
, &ptr
, 10));
101 if (design_size
== 0 && ptr
== arg
) {
102 fatal_with_file_and_line(filename
, lineno
, "bad design size");
107 #define FONTS_MAX 256
112 output_font() : f(0) { }
115 class dvi_printer
: public printer
{
126 output_font output_font_table
[FONTS_MAX
];
136 void define_font(int);
138 void possibly_begin_line();
139 void set_color(color
*);
167 void moveto(int, int);
168 void out_string(const char *);
169 void out_signed(unsigned char, int);
170 void out_unsigned(unsigned char, int);
171 void do_special(const char *);
175 font
*make_font(const char *);
176 void begin_page(int);
178 void set_char(int, font
*, const environment
*, int w
, const char *name
);
179 void special(char *arg
, const environment
*env
, char type
);
181 void draw(int code
, int *p
, int np
, const environment
*env
);
185 class draw_dvi_printer
: public dvi_printer
{
187 void set_line_thickness(const environment
*);
188 void fill_next(const environment
*);
192 void draw(int code
, int *p
, int np
, const environment
*env
);
196 dvi_printer::dvi_printer()
197 : fp(stdout
), byte_count(0), last_bop(-1), page_count(0), max_h(0), max_v(0),
198 cur_font(0), cur_point_size(-1), pushed(0), line_thickness(-1)
200 if (font::res
!= RES
)
201 fatal("resolution must be %1", RES
);
202 if (font::unitwidth
!= UNITWIDTH
)
203 fatal("unitwidth must be %1", UNITWIDTH
);
205 fatal("hor must be equal to 1");
207 fatal("vert must be equal to 1");
208 if (font::sizescale
!= SIZESCALE
)
209 fatal("sizescale must be equal to %1", SIZESCALE
);
210 max_drift
= font::res
/1000; // this is fairly arbitrary
214 dvi_printer::~dvi_printer()
220 draw_dvi_printer::draw_dvi_printer()
221 : output_pen_size(-1)
225 draw_dvi_printer::~draw_dvi_printer()
230 void dvi_printer::out1(int n
)
236 void dvi_printer::out2(int n
)
239 putc((n
>> 8) & 0xff, fp
);
243 void dvi_printer::out3(int n
)
246 putc((n
>> 16) & 0xff, fp
);
247 putc((n
>> 8) & 0xff, fp
);
251 void dvi_printer::out4(int n
)
254 putc((n
>> 24) & 0xff, fp
);
255 putc((n
>> 16) & 0xff, fp
);
256 putc((n
>> 8) & 0xff, fp
);
260 void dvi_printer::out_string(const char *s
)
268 void dvi_printer::end_of_line()
278 void dvi_printer::possibly_begin_line()
281 have_pushed
= pushed
= 1;
288 int scale(int x
, int z
)
293 alpha
= 16*z
; beta
= 16;
294 while (z
>= 040000000L) {
301 sw
= (((((d
* z
) / 0400) + (c
* z
)) / 0400) + (b
* z
)) / beta
;
309 void dvi_printer::set_color(color
*col
)
313 unsigned int components
[4];
314 color_scheme cs
= col
->get_components(components
);
317 sprintf(buf
, "color gray 0");
320 sprintf(buf
, "color rgb %.3g %.3g %.3g",
321 double(Red
) / color::MAX_COLOR_VAL
,
322 double(Green
) / color::MAX_COLOR_VAL
,
323 double(Blue
) / color::MAX_COLOR_VAL
);
326 col
->get_cmyk(&Cyan
, &Magenta
, &Yellow
, &Black
);
329 sprintf(buf
, "color cmyk %.3g %.3g %.3g %.3g",
330 double(Cyan
) / color::MAX_COLOR_VAL
,
331 double(Magenta
) / color::MAX_COLOR_VAL
,
332 double(Yellow
) / color::MAX_COLOR_VAL
,
333 double(Black
) / color::MAX_COLOR_VAL
);
336 sprintf(buf
, "color gray %.3g",
337 double(Gray
) / color::MAX_COLOR_VAL
);
343 void dvi_printer::set_char(int idx
, font
*f
, const environment
*env
,
346 if (*env
->col
!= cur_color
)
348 int code
= f
->get_code(idx
);
349 if (env
->size
!= cur_point_size
|| f
!= cur_font
) {
351 cur_point_size
= env
->size
;
354 if (i
>= FONTS_MAX
) {
355 fatal("too many output fonts required");
357 if (output_font_table
[i
].f
== 0) {
358 output_font_table
[i
].f
= (dvi_font
*)cur_font
;
359 output_font_table
[i
].point_size
= cur_point_size
;
362 if (output_font_table
[i
].f
== cur_font
363 && output_font_table
[i
].point_size
== cur_point_size
)
368 int distance
= env
->hpos
- cur_h
;
369 if (env
->hpos
!= end_h
&& distance
!= 0) {
370 out_signed(right1
, distance
);
373 else if (distance
> max_drift
) {
374 out_signed(right1
, distance
- max_drift
);
375 cur_h
= env
->hpos
- max_drift
;
377 else if (distance
< -max_drift
) {
378 out_signed(right1
, distance
+ max_drift
);
379 cur_h
= env
->hpos
+ max_drift
;
381 if (env
->vpos
!= cur_v
) {
382 out_signed(down1
, env
->vpos
- cur_v
);
385 possibly_begin_line();
386 end_h
= env
->hpos
+ w
;
387 cur_h
+= scale(f
->get_width(idx
, UNITWIDTH
)/MULTIPLIER
,
388 cur_point_size
*RES_7227
);
393 if (code
>= 0 && code
<= 127)
396 out_unsigned(set1
, code
);
399 void dvi_printer::define_font(int i
)
401 out_unsigned(fnt_def1
, i
);
402 dvi_font
*f
= output_font_table
[i
].f
;
404 out4(output_font_table
[i
].point_size
*RES_7227
);
405 out4(int((double(f
->design_size
)/(1<<20))*RES_7227
*100 + .5));
406 const char *nm
= f
->get_internal_name();
411 void dvi_printer::set_font(int i
)
413 if (i
>= 0 && i
<= 63)
416 out_unsigned(fnt1
, i
);
419 void dvi_printer::out_signed(unsigned char base
, int param
)
421 if (-128 <= param
&& param
< 128) {
425 else if (-32768 <= param
&& param
< 32768) {
429 else if (-(1 << 23) <= param
&& param
< (1 << 23)) {
439 void dvi_printer::out_unsigned(unsigned char base
, int param
)
446 else if (param
< 65536) {
450 else if (param
< (1 << 24)) {
465 void dvi_printer::preamble()
475 void dvi_printer::postamble()
477 int tem
= byte_count
;
485 out2(have_pushed
); // stack depth
488 for (i
= 0; i
< FONTS_MAX
&& output_font_table
[i
].f
!= 0; i
++)
493 for (i
= 0; i
< 4 || byte_count
% 4 != 0; i
++)
497 void dvi_printer::begin_page(int i
)
500 int tem
= byte_count
;
503 for (int j
= 1; j
< 10; j
++)
507 // By convention position (0,0) in a dvi file is placed at (1in, 1in).
511 if (page_count
== 1) {
513 // at least dvips uses this
514 double length
= user_paper_length
? user_paper_length
:
515 double(font::paperlength
) / font::res
;
516 double width
= user_paper_width
? user_paper_width
:
517 double(font::paperwidth
) / font::res
;
518 if (width
> 0 && length
> 0) {
519 sprintf(buf
, "papersize=%.3fin,%.3fin",
520 landscape_flag
? length
: width
,
521 landscape_flag
? width
: length
);
525 if (cur_color
!= default_color
)
526 set_color(&cur_color
);
529 void dvi_printer::end_page(int)
531 set_color(&default_color
);
538 void draw_dvi_printer::end_page(int len
)
540 dvi_printer::end_page(len
);
541 output_pen_size
= -1;
544 void dvi_printer::do_special(const char *s
)
549 possibly_begin_line();
550 out_unsigned(xxx1
, len
);
555 void dvi_printer::special(char *arg
, const environment
*env
, char type
)
559 moveto(env
->hpos
, env
->vpos
);
563 void dvi_printer::moveto(int h
, int v
)
566 out_signed(right1
, h
- cur_h
);
572 out_signed(down1
, v
- cur_v
);
580 void dvi_printer::draw(int code
, int *p
, int np
, const environment
*env
)
584 int height
= 0, width
= 0;
586 if (line_thickness
< 0)
587 thickness
= env
->size
*RES_7227
*linewidth
/1000;
588 else if (line_thickness
> 0)
589 thickness
= line_thickness
;
593 error("2 arguments required for line");
595 else if (p
[0] == 0) {
598 x
= env
->hpos
- thickness
/2;
599 y
= env
->vpos
+ p
[1] + thickness
/2;
600 height
= p
[1] + thickness
;
604 x
= env
->hpos
- thickness
/2;
605 y
= env
->vpos
+ thickness
/2;
606 height
= thickness
- p
[1];
610 else if (p
[1] == 0) {
612 x
= env
->hpos
- thickness
/2;
613 y
= env
->vpos
+ thickness
/2;
615 width
= p
[0] + thickness
;
618 x
= env
->hpos
- p
[0] - thickness
/2;
619 y
= env
->vpos
+ thickness
/2;
621 width
= thickness
- p
[0];
631 else if (code
== 't') {
636 // troff gratuitously adds an extra 0
637 if (np
!= 1 && np
!= 2)
638 error("0 or 1 argument required for thickness");
640 line_thickness
= p
[0];
643 else if (code
== 'R') {
645 error("2 arguments required for rule");
646 else if (p
[0] != 0 || p
[1] != 0) {
667 // XXX Will this overflow?
669 inline int milliinches(int n
)
671 return (n
*1000 + font::res
/2)/font::res
;
674 void draw_dvi_printer::set_line_thickness(const environment
*env
)
677 = milliinches(line_thickness
< 0
678 // Will this overflow?
679 ? env
->size
*RES_7227
*linewidth
/1000
681 if (desired_pen_size
!= output_pen_size
) {
683 sprintf(buf
, "pn %d", desired_pen_size
);
685 output_pen_size
= desired_pen_size
;
689 void draw_dvi_printer::fill_next(const environment
*env
)
692 if (env
->fill
->is_default())
695 // currently, only BW support
696 env
->fill
->get_gray(&g
);
699 sprintf(buf
, "sh %.3g", 1 - double(g
)/color::MAX_COLOR_VAL
);
703 void draw_dvi_printer::draw(int code
, int *p
, int np
, const environment
*env
)
713 // troff adds an extra argument to C
714 if (np
!= 1 && !(code
== 'C' && np
== 2)) {
715 error("1 argument required for circle");
718 moveto(env
->hpos
+p
[0]/2, env
->vpos
);
722 set_line_thickness(env
);
724 rad
= milliinches(p
[0]/2);
725 sprintf(buf
, "%s 0 0 %d %d 0 6.28319",
726 (fill_flag
? "ia" : "ar"),
734 error("2 arguments required for line");
737 moveto(env
->hpos
, env
->vpos
);
738 set_line_thickness(env
);
739 do_special("pa 0 0");
740 sprintf(buf
, "pa %d %d", milliinches(p
[0]), milliinches(p
[1]));
749 error("2 arguments required for ellipse");
752 moveto(env
->hpos
+p
[0]/2, env
->vpos
);
755 sprintf(buf
, "%s 0 0 %d %d 0 6.28319",
756 (fill_flag
? "ia" : "ar"),
758 milliinches(p
[1]/2));
767 error("even number of arguments required for polygon");
771 error("no arguments for polygon");
774 moveto(env
->hpos
, env
->vpos
);
778 set_line_thickness(env
);
779 do_special("pa 0 0");
781 for (int i
= 0; i
< np
; i
+= 2) {
784 sprintf(buf
, "pa %d %d", milliinches(h
), milliinches(v
));
787 do_special("pa 0 0");
788 do_special(fill_flag
? "ip" : "fp");
794 error("even number of arguments required for spline");
798 error("no arguments for spline");
801 moveto(env
->hpos
, env
->vpos
);
802 set_line_thickness(env
);
803 do_special("pa 0 0");
805 for (int i
= 0; i
< np
; i
+= 2) {
808 sprintf(buf
, "pa %d %d", milliinches(h
), milliinches(v
));
817 error("4 arguments required for arc");
820 set_line_thickness(env
);
822 if (adjust_arc_center(p
, c
)) {
823 int rad
= milliinches(int(sqrt(c
[0]*c
[0] + c
[1]*c
[1]) + .5));
824 moveto(env
->hpos
+ int(c
[0]), env
->vpos
+ int(c
[1]));
825 double start
= atan2(p
[1] + p
[3] - c
[1], p
[0] + p
[2] - c
[0]);
826 double end
= atan2(-c
[1], -c
[0]);
828 start
-= 2 * 3.14159265358;
829 sprintf(buf
, "ar 0 0 %d %d %f %f", rad
, rad
, start
, end
);
833 moveto(env
->hpos
, env
->vpos
);
834 do_special("pa 0 0");
837 milliinches(p
[0] + p
[2]),
838 milliinches(p
[1] + p
[3]));
850 // troff gratuitously adds an extra 0
851 if (np
!= 1 && np
!= 2) {
852 error("0 or 1 argument required for thickness");
855 line_thickness
= p
[0];
862 error("2 arguments required for rule");
888 error("unrecognised drawing command `%1'", char(code
));
893 font
*dvi_printer::make_font(const char *nm
)
895 return dvi_font::load_dvi_font(nm
);
898 printer
*make_printer()
901 return new draw_dvi_printer
;
903 return new dvi_printer
;
906 static void usage(FILE *stream
);
908 int main(int argc
, char **argv
)
910 setlocale(LC_NUMERIC
, "C");
911 program_name
= argv
[0];
912 static char stderr_buf
[BUFSIZ
];
913 setbuf(stderr
, stderr_buf
);
915 static const struct option long_options
[] = {
916 { "help", no_argument
, 0, CHAR_MAX
+ 1 },
917 { "version", no_argument
, 0, 'v' },
920 while ((c
= getopt_long(argc
, argv
, "dF:I:lp:vw:", long_options
, NULL
))
930 font::command_line_font_dir(optarg
);
933 // ignore include search path
936 if (!font::scan_papersize(optarg
, 0,
937 &user_paper_length
, &user_paper_width
))
938 error("invalid custom paper size `%1' ignored", optarg
);
942 printf("GNU grodvi (groff) version %s\n", Version_string
);
947 if (sscanf(optarg
, "%d", &linewidth
) != 1
948 || linewidth
< 0 || linewidth
> 1000) {
949 error("bad line width");
950 linewidth
= DEFAULT_LINEWIDTH
;
953 case CHAR_MAX
+ 1: // --help
964 SET_BINARY(fileno(stdout
));
968 for (int i
= optind
; i
< argc
; i
++)
974 static void usage(FILE *stream
)
976 fprintf(stream
, "usage: %s [-dv] [-F dir] [-w n] [files ...]\n",