2 /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
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
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
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #include "stringclass.h"
27 static int landscape_flag
= 0;
28 static int ncopies
= 1;
29 static int linewidth
= -1;
30 // Non-zero means generate PostScript code that guesses the paper
31 // length using the imageable area.
32 static int guess_flag
= 0;
34 // Non-zero if -b was specified on the command line.
36 unsigned broken_flags
= 0;
38 #define DEFAULT_LINEWIDTH 40 /* in ems/1000 */
41 const char *const dict_name
= "grops";
42 const char *const defs_dict_name
= "DEFS";
43 const int DEFS_DICT_SPARE
= 50;
45 double degrees(double r
)
50 double radians(double d
)
55 inline double transform_fill(int fill
)
57 return 1 - fill
/double(FILL_MAX
);
60 ps_output::ps_output(FILE *f
, int n
)
61 : fp(f
), max_line_length(n
), col(0), need_space(0), fixed_point(0)
65 ps_output
&ps_output::set_file(FILE *f
)
72 ps_output
&ps_output::copy_file(FILE *infp
)
75 while ((c
= getc(infp
)) != EOF
)
80 ps_output
&ps_output::end_line()
90 ps_output
&ps_output::special(const char *s
)
92 if (s
== 0 || *s
== '\0')
99 if (strchr(s
, '\0')[-1] != '\n')
105 ps_output
&ps_output::simple_comment(const char *s
)
118 ps_output
&ps_output::begin_comment(const char *s
)
129 ps_output
&ps_output::end_comment()
139 ps_output
&ps_output::comment_arg(const char *s
)
142 if (col
+ len
+ 1 > max_line_length
) {
153 ps_output
&ps_output::set_fixed_point(int n
)
155 assert(n
>= 0 && n
<= 10);
160 ps_output
&ps_output::put_delimiter(char c
)
162 if (col
+ 1 > max_line_length
) {
172 ps_output
&ps_output::put_string(const char *s
, int n
)
175 for (int i
= 0; i
< n
; i
++) {
177 if (isascii(c
) && isprint(c
)) {
178 if (c
== '(' || c
== ')' || c
== '\\')
187 if (col
+ n
*2 + 2 > max_line_length
&& n
*2 + 2 <= max_line_length
) {
191 if (col
+ 1 > max_line_length
) {
197 for (i
= 0; i
< n
; i
++) {
198 if (col
+ 2 > max_line_length
) {
202 fprintf(fp
, "%02x", s
[i
] & 0377);
209 if (col
+ len
+ 2 > max_line_length
&& len
+ 2 <= max_line_length
) {
213 if (col
+ 2 > max_line_length
) {
219 for (i
= 0; i
< n
; i
++) {
221 if (isascii(c
) && isprint(c
)) {
222 if (c
== '(' || c
== ')' || c
== '\\')
229 if (col
+ len
+ 1 > max_line_length
) {
243 fprintf(fp
, "\\%03o", c
& 0377);
257 ps_output
&ps_output::put_number(int n
)
259 char buf
[1 + INT_DIGITS
+ 1];
260 sprintf(buf
, "%d", n
);
261 int len
= strlen(buf
);
262 if (col
> 0 && col
+ len
+ need_space
> max_line_length
) {
277 ps_output
&ps_output::put_fix_number(int i
)
279 const char *p
= iftoa(i
, fixed_point
);
281 if (col
> 0 && col
+ len
+ need_space
> max_line_length
) {
296 ps_output
&ps_output::put_float(double d
)
299 sprintf(buf
, "%.4f", d
);
300 int len
= strlen(buf
);
301 if (col
> 0 && col
+ len
+ need_space
> max_line_length
) {
316 ps_output
&ps_output::put_symbol(const char *s
)
319 if (col
> 0 && col
+ len
+ need_space
> max_line_length
) {
334 ps_output
&ps_output::put_literal_symbol(const char *s
)
337 if (col
> 0 && col
+ len
+ 1 > max_line_length
) {
348 class ps_font
: public font
{
349 ps_font(const char *);
353 char *reencoded_name
;
355 void handle_unknown_font_command(const char *command
, const char *arg
,
356 const char *filename
, int lineno
);
357 static ps_font
*load_ps_font(const char *);
360 ps_font
*ps_font::load_ps_font(const char *s
)
362 ps_font
*f
= new ps_font(s
);
370 ps_font::ps_font(const char *nm
)
371 : font(nm
), encoding(0), reencoded_name(0), encoding_index(-1)
378 a_delete reencoded_name
;
381 void ps_font::handle_unknown_font_command(const char *command
, const char *arg
,
382 const char *filename
, int lineno
)
384 if (strcmp(command
, "encoding") == 0) {
386 error_with_file_and_line(filename
, lineno
,
387 "`encoding' command requires an argument");
389 encoding
= strsave(arg
);
393 static void handle_unknown_desc_command(const char *command
, const char *arg
,
394 const char *filename
, int lineno
)
396 if (strcmp(command
, "broken") == 0) {
398 error_with_file_and_line(filename
, lineno
,
399 "`broken' command requires an argument");
401 broken_flags
= atoi(arg
);
411 style(font
*, int, int, int);
412 int operator==(const style
&) const;
413 int operator!=(const style
&) const;
416 style::style() : f(0)
420 style::style(font
*p
, int sz
, int h
, int sl
)
421 : f(p
), point_size(sz
), height(h
), slant(sl
)
425 int style::operator==(const style
&s
) const
427 return (f
== s
.f
&& point_size
== s
.point_size
428 && height
== s
.height
&& slant
== s
.slant
);
431 int style::operator!=(const style
&s
) const
433 return !(*this == s
);
436 class ps_printer
: public printer
{
440 int space_char_index
;
444 enum { SBUF_SIZE
= 256 };
445 char sbuf
[SBUF_SIZE
];
450 int sbuf_space_width
;
451 int sbuf_space_count
;
452 int sbuf_space_diff_count
;
459 int output_draw_point_size
;
461 int output_line_thickness
;
463 unsigned char output_space_code
;
464 enum { MAX_DEFINED_STYLES
= 50 };
465 style defined_styles
[MAX_DEFINED_STYLES
];
467 int next_encoding_index
;
474 void set_style(const style
&);
475 void set_space_code(unsigned char c
);
476 int set_encoding_index(ps_font
*);
477 void do_exec(char *, const environment
*);
478 void do_import(char *, const environment
*);
479 void do_def(char *, const environment
*);
480 void do_mdef(char *, const environment
*);
481 void do_file(char *, const environment
*);
482 void do_invis(char *, const environment
*);
483 void do_endinvis(char *, const environment
*);
484 void set_line_thickness(const environment
*);
487 void define_encoding(const char *, int);
488 void reencode_font(ps_font
*);
492 void set_char(int i
, font
*f
, const environment
*env
, int w
);
493 void draw(int code
, int *p
, int np
, const environment
*env
);
494 void begin_page(int);
496 void special(char *arg
, const environment
*env
);
497 font
*make_font(const char *);
501 ps_printer::ps_printer()
508 next_encoding_index(0),
515 out
.set_file(tempfp
);
517 linewidth
= DEFAULT_LINEWIDTH
;
519 fatal("horizontal resolution must be 1");
521 fatal("vertical resolution must be 1");
522 if (font::res
% (font::sizescale
*72) != 0)
523 fatal("res must be a multiple of 72*sizescale");
526 while (r
% 10 == 0) {
531 out
.set_fixed_point(point
);
532 space_char_index
= font::name_to_index("space");
533 paper_length
= font::paperlength
;
534 if (paper_length
== 0)
535 paper_length
= 11*font::res
;
536 equalise_spaces
= font::res
>= 72000;
539 int ps_printer::set_encoding_index(ps_font
*f
)
541 if (f
->encoding_index
>= 0)
542 return f
->encoding_index
;
543 for (font_pointer_list
*p
= font_list
; p
; p
= p
->next
)
545 char *encoding
= ((ps_font
*)p
->p
)->encoding
;
546 int encoding_index
= ((ps_font
*)p
->p
)->encoding_index
;
547 if (encoding
!= 0 && encoding_index
>= 0
548 && strcmp(f
->encoding
, encoding
) == 0) {
549 return f
->encoding_index
= encoding_index
;
552 return f
->encoding_index
= next_encoding_index
++;
555 void ps_printer::set_char(int i
, font
*f
, const environment
*env
, int w
)
557 if (i
== space_char_index
|| invis_count
> 0)
559 unsigned char code
= f
->get_code(i
);
560 style
sty(f
, env
->size
, env
->height
, env
->slant
);
561 if (sty
.slant
!= 0) {
562 if (sty
.slant
> 80 || sty
.slant
< -80) {
563 error("silly slant `%1' degrees", sty
.slant
);
568 if (sbuf_len
< SBUF_SIZE
570 && sbuf_vpos
== env
->vpos
) {
571 if (sbuf_end_hpos
== env
->hpos
) {
572 sbuf
[sbuf_len
++] = code
;
573 sbuf_end_hpos
+= w
+ sbuf_kern
;
576 if (sbuf_len
== 1 && sbuf_kern
== 0) {
577 sbuf_kern
= env
->hpos
- sbuf_end_hpos
;
578 sbuf_end_hpos
= env
->hpos
+ sbuf_kern
+ w
;
579 sbuf
[sbuf_len
++] = code
;
582 /* If sbuf_end_hpos - sbuf_kern == env->hpos, we are better off
583 starting a new string. */
584 if (sbuf_len
< SBUF_SIZE
- 1 && env
->hpos
>= sbuf_end_hpos
585 && (sbuf_kern
== 0 || sbuf_end_hpos
- sbuf_kern
!= env
->hpos
)) {
586 if (sbuf_space_code
< 0) {
587 if (f
->contains(space_char_index
)) {
588 sbuf_space_code
= f
->get_code(space_char_index
);
589 sbuf_space_width
= env
->hpos
- sbuf_end_hpos
;
590 sbuf_end_hpos
= env
->hpos
+ w
+ sbuf_kern
;
591 sbuf
[sbuf_len
++] = sbuf_space_code
;
592 sbuf
[sbuf_len
++] = code
;
598 int diff
= env
->hpos
- sbuf_end_hpos
- sbuf_space_width
;
599 if (diff
== 0 || (equalise_spaces
&& (diff
== 1 || diff
== -1))) {
600 sbuf_end_hpos
= env
->hpos
+ w
+ sbuf_kern
;
601 sbuf
[sbuf_len
++] = sbuf_space_code
;
602 sbuf
[sbuf_len
++] = code
;
605 sbuf_space_diff_count
++;
607 sbuf_space_diff_count
--;
617 sbuf_end_hpos
= env
->hpos
+ w
;
618 sbuf_start_hpos
= env
->hpos
;
619 sbuf_vpos
= env
->vpos
;
621 sbuf_space_code
= -1;
622 sbuf_space_width
= 0;
623 sbuf_space_count
= sbuf_space_diff_count
= 0;
627 int is_small_h(int n
)
629 return n
< (font::res
*2)/72 && n
> -(font::res
*10)/72;
632 int is_small_v(int n
)
634 return n
< (font::res
*4)/72 && n
> -(font::res
*4)/72;
637 static char *make_encoding_name(int encoding_index
)
639 static char buf
[3 + INT_DIGITS
+ 1];
640 sprintf(buf
, "ENC%d", encoding_index
);
644 const char *const WS
= " \t\n\r";
646 void ps_printer::define_encoding(const char *encoding
, int encoding_index
)
649 for (int i
= 0; i
< 256; i
++)
652 FILE *fp
= font::open_file(encoding
, &path
);
654 fatal("can't open encoding file `%1'", encoding
);
657 while (fgets(buf
, 512, fp
) != 0) {
659 while (isascii(*p
) && isspace(*p
))
661 if (*p
!= '#' && *p
!= '\0' && (p
= strtok(buf
, WS
)) != 0) {
662 char *q
= strtok(0, WS
);
664 if (q
== 0 || sscanf(q
, "%d", &n
) != 1 || n
< 0 || n
>= 256)
665 fatal_with_file_and_line(path
, lineno
, "bad second field");
666 vec
[n
] = new char[strlen(p
) + 1];
672 out
.put_literal_symbol(make_encoding_name(encoding_index
));
673 out
.put_delimiter('[');
674 for (i
= 0; i
< 256; i
++) {
676 out
.put_literal_symbol(".notdef");
678 out
.put_literal_symbol(vec
[i
]);
682 out
.put_delimiter(']').put_symbol("def");
685 void ps_printer::reencode_font(ps_font
*f
)
687 out
.put_literal_symbol(f
->reencoded_name
)
688 .put_symbol(make_encoding_name(f
->encoding_index
))
689 .put_literal_symbol(f
->get_internal_name())
693 void ps_printer::encode_fonts()
695 if (next_encoding_index
== 0)
697 char *done_encoding
= new char[next_encoding_index
];
698 for (int i
= 0; i
< next_encoding_index
; i
++)
699 done_encoding
[i
] = 0;
700 for (font_pointer_list
*f
= font_list
; f
; f
= f
->next
) {
701 int encoding_index
= ((ps_font
*)f
->p
)->encoding_index
;
702 if (encoding_index
>= 0) {
703 assert(encoding_index
< next_encoding_index
);
704 if (!done_encoding
[encoding_index
]) {
705 done_encoding
[encoding_index
] = 1;
706 define_encoding(((ps_font
*)f
->p
)->encoding
, encoding_index
);
708 reencode_font((ps_font
*)f
->p
);
711 a_delete done_encoding
;
714 void ps_printer::set_style(const style
&sty
)
716 char buf
[1 + INT_DIGITS
+ 1];
717 for (int i
= 0; i
< ndefined_styles
; i
++)
718 if (sty
== defined_styles
[i
]) {
719 sprintf(buf
, "F%d", i
);
723 if (ndefined_styles
>= MAX_DEFINED_STYLES
)
725 sprintf(buf
, "F%d", ndefined_styles
);
726 out
.put_literal_symbol(buf
);
727 const char *psname
= sty
.f
->get_internal_name();
729 fatal("no internalname specified for font `%1'", sty
.f
->get_name());
730 char *encoding
= ((ps_font
*)sty
.f
)->encoding
;
732 char *s
= ((ps_font
*)sty
.f
)->reencoded_name
;
734 int ei
= set_encoding_index((ps_font
*)sty
.f
);
735 char *tem
= new char[strlen(psname
) + 1 + INT_DIGITS
+ 1];
736 sprintf(tem
, "%s@%d", psname
, ei
);
738 ((ps_font
*)sty
.f
)->reencoded_name
= tem
;
743 out
.put_fix_number((font::res
/(72*font::sizescale
))*sty
.point_size
);
744 if (sty
.height
!= 0 || sty
.slant
!= 0) {
745 int h
= sty
.height
== 0 ? sty
.point_size
: sty
.height
;
746 h
*= font::res
/(72*font::sizescale
);
747 int c
= int(h
*tan(radians(sty
.slant
)) + .5);
748 out
.put_fix_number(c
).put_fix_number(h
).put_literal_symbol(psname
)
752 out
.put_literal_symbol(psname
).put_symbol("SF");
754 defined_styles
[ndefined_styles
++] = sty
;
757 void ps_printer::set_space_code(unsigned char c
)
759 out
.put_literal_symbol("SC").put_number(c
).put_symbol("def");
762 void ps_printer::end_of_line()
765 // this ensures that we do an absolute motion to the beginning of a line
766 output_vpos
= output_hpos
= -1;
769 void ps_printer::flush_sbuf()
781 if (output_style
!= sbuf_style
) {
782 set_style(sbuf_style
);
783 output_style
= sbuf_style
;
786 if (output_hpos
< 0 || output_vpos
< 0
787 || !is_small_h(output_hpos
- sbuf_start_hpos
)
788 || !is_small_v(output_vpos
- sbuf_vpos
))
791 if (output_hpos
!= sbuf_start_hpos
)
793 if (output_vpos
!= sbuf_vpos
) {
795 motion
= RELATIVE_HV
;
800 if (sbuf_space_code
>= 0) {
801 int w
= sbuf_style
.f
->get_width(space_char_index
, sbuf_style
.point_size
);
802 if (w
+ sbuf_kern
!= sbuf_space_width
) {
803 if (sbuf_space_code
!= output_space_code
) {
804 set_space_code(sbuf_space_code
);
805 output_space_code
= sbuf_space_code
;
808 extra_space
= sbuf_space_width
- w
- sbuf_kern
;
809 if (sbuf_space_diff_count
> sbuf_space_count
/2)
811 else if (sbuf_space_diff_count
< -(sbuf_space_count
/2))
816 out
.put_fix_number(extra_space
);
818 out
.put_fix_number(sbuf_kern
);
819 out
.put_string(sbuf
, sbuf_len
);
821 sym
[0] = 'A' + motion
*4 + space_flag
+ 2*(sbuf_kern
!= 0);
827 out
.put_fix_number(sbuf_start_hpos
)
828 .put_fix_number(sbuf_vpos
);
831 out
.put_fix_number(sbuf_start_hpos
- output_hpos
);
834 out
.put_fix_number(sbuf_vpos
- output_vpos
);
837 out
.put_fix_number(sbuf_start_hpos
- output_hpos
)
838 .put_fix_number(sbuf_vpos
- output_vpos
);
844 output_hpos
= sbuf_end_hpos
;
845 output_vpos
= sbuf_vpos
;
850 void ps_printer::set_line_thickness(const environment
*env
)
852 if (line_thickness
< 0) {
853 if (output_draw_point_size
!= env
->size
) {
854 // we ought to check for overflow here
855 int lw
= ((font::res
/(72*font::sizescale
))*linewidth
*env
->size
)/1000;
856 out
.put_fix_number(lw
).put_symbol("LW");
857 output_draw_point_size
= env
->size
;
858 output_line_thickness
= -1;
862 if (output_line_thickness
!= line_thickness
) {
863 out
.put_fix_number(line_thickness
).put_symbol("LW");
864 output_line_thickness
= line_thickness
;
865 output_draw_point_size
= -1;
870 void ps_printer::fill_path()
873 out
.put_symbol("BL");
875 out
.put_float(transform_fill(fill
)).put_symbol("FL");
878 void ps_printer::draw(int code
, int *p
, int np
, const environment
*env
)
888 // troff adds an extra argument to C
889 if (np
!= 1 && !(code
== 'C' && np
== 2)) {
890 error("1 argument required for circle");
893 out
.put_fix_number(env
->hpos
+ p
[0]/2)
894 .put_fix_number(env
->vpos
)
895 .put_fix_number(p
[0]/2)
901 set_line_thickness(env
);
902 out
.put_symbol("ST");
907 error("2 arguments required for line");
910 set_line_thickness(env
);
911 out
.put_fix_number(p
[0] + env
->hpos
)
912 .put_fix_number(p
[1] + env
->vpos
)
913 .put_fix_number(env
->hpos
)
914 .put_fix_number(env
->vpos
)
922 error("2 arguments required for ellipse");
925 out
.put_fix_number(p
[0])
926 .put_fix_number(p
[1])
927 .put_fix_number(env
->hpos
+ p
[0]/2)
928 .put_fix_number(env
->vpos
)
934 set_line_thickness(env
);
935 out
.put_symbol("ST");
944 error("even number of arguments required for polygon");
948 error("no arguments for polygon");
951 out
.put_fix_number(env
->hpos
)
952 .put_fix_number(env
->vpos
)
954 for (int i
= 0; i
< np
; i
+= 2)
955 out
.put_fix_number(p
[i
])
956 .put_fix_number(p
[i
+1])
958 out
.put_symbol("CL");
963 set_line_thickness(env
);
964 out
.put_symbol("ST");
971 error("even number of arguments required for spline");
975 error("no arguments for spline");
978 out
.put_fix_number(env
->hpos
)
979 .put_fix_number(env
->vpos
)
981 out
.put_fix_number(p
[0]/2)
982 .put_fix_number(p
[1]/2)
984 /* tnum/tden should be between 0 and 1; the closer it is to 1
985 the tighter the curve will be to the guiding lines; 2/3
986 is the standard value */
989 for (int i
= 0; i
< np
- 2; i
+= 2) {
990 out
.put_fix_number((p
[i
]*tnum
)/(2*tden
))
991 .put_fix_number((p
[i
+ 1]*tnum
)/(2*tden
))
992 .put_fix_number(p
[i
]/2 + (p
[i
+ 2]*(tden
- tnum
))/(2*tden
))
993 .put_fix_number(p
[i
+ 1]/2 + (p
[i
+ 3]*(tden
- tnum
))/(2*tden
))
994 .put_fix_number((p
[i
] - p
[i
]/2) + p
[i
+ 2]/2)
995 .put_fix_number((p
[i
+ 1] - p
[i
+ 1]/2) + p
[i
+ 3]/2)
998 out
.put_fix_number(p
[np
- 2] - p
[np
- 2]/2)
999 .put_fix_number(p
[np
- 1] - p
[np
- 1]/2)
1001 set_line_thickness(env
);
1002 out
.put_symbol("ST");
1008 error("4 arguments required for arc");
1011 set_line_thickness(env
);
1013 if (adjust_arc_center(p
, c
))
1014 out
.put_fix_number(env
->hpos
+ int(c
[0]))
1015 .put_fix_number(env
->vpos
+ int(c
[1]))
1016 .put_fix_number(int(sqrt(c
[0]*c
[0] + c
[1]*c
[1])))
1017 .put_float(degrees(atan2(-c
[1], -c
[0])))
1018 .put_float(degrees(atan2(p
[1] + p
[3] - c
[1], p
[0] + p
[2] - c
[0])))
1021 out
.put_fix_number(p
[0] + p
[2] + env
->hpos
)
1022 .put_fix_number(p
[1] + p
[3] + env
->vpos
)
1023 .put_fix_number(env
->hpos
)
1024 .put_fix_number(env
->vpos
)
1031 line_thickness
= -1;
1034 // troff gratuitously adds an extra 0
1035 if (np
!= 1 && np
!= 2) {
1036 error("0 or 1 argument required for thickness");
1039 line_thickness
= p
[0];
1045 if (np
!= 1 && np
!= 2) {
1046 error("1 argument required for fill");
1050 if (fill
< 0 || fill
> FILL_MAX
) {
1051 // This means fill with the current color.
1052 fill
= FILL_MAX
+ 1;
1057 error("unrecognised drawing command `%1'", char(code
));
1061 output_hpos
= output_vpos
= -1;
1065 void ps_printer::begin_page(int n
)
1067 out
.begin_comment("Page:").comment_arg(itoa(n
));
1068 out
.comment_arg(itoa(++pages_output
)).end_comment();
1070 output_space_code
= 32;
1071 output_draw_point_size
= -1;
1072 output_line_thickness
= -1;
1073 output_hpos
= output_vpos
= -1;
1074 ndefined_styles
= 0;
1075 out
.simple_comment("BeginPageSetup");
1076 out
.put_symbol("BP");
1077 out
.simple_comment("EndPageSetup");
1080 void ps_printer::end_page(int)
1083 out
.put_symbol("EP");
1084 if (invis_count
!= 0) {
1085 error("missing `endinvis' command");
1090 font
*ps_printer::make_font(const char *nm
)
1092 return ps_font::load_ps_font(nm
);
1095 ps_printer::~ps_printer()
1097 out
.simple_comment("Trailer");
1098 out
.put_symbol("end");
1099 out
.simple_comment("EOF");
1100 if (fseek(tempfp
, 0L, 0) < 0)
1101 fatal("fseek on temporary file failed");
1102 fputs("%!PS-Adobe-3.0\n", stdout
);
1103 out
.set_file(stdout
);
1105 extern const char *version_string
;
1106 out
.begin_comment("Creator:")
1107 .comment_arg("groff")
1108 .comment_arg("version")
1109 .comment_arg(version_string
)
1112 for (font_pointer_list
*f
= font_list
; f
; f
= f
->next
) {
1113 ps_font
*psf
= (ps_font
*)(f
->p
);
1114 rm
.need_font(psf
->get_internal_name());
1116 rm
.print_header_comments(out
);
1117 out
.begin_comment("Pages:").comment_arg(itoa(pages_output
)).end_comment();
1118 out
.begin_comment("PageOrder:").comment_arg("Ascend").end_comment();
1120 fprintf(out
.get_file(), "%%%%DocumentMedia: () %g %g 0 () ()\n",
1121 font::paperwidth
*72.0/font::res
,
1122 paper_length
*72.0/font::res
);
1124 out
.begin_comment("Orientation:")
1125 .comment_arg(landscape_flag
? "Landscape" : "Portrait")
1129 fprintf(out
.get_file(), "%%%%Requirements: numcopies(%d)\n", ncopies
);
1131 out
.simple_comment("EndComments");
1132 out
.simple_comment("BeginProlog");
1133 rm
.output_prolog(out
);
1134 if (!(broken_flags
& NO_SETUP_SECTION
)) {
1135 out
.simple_comment("EndProlog");
1136 out
.simple_comment("BeginSetup");
1138 rm
.document_setup(out
);
1139 out
.put_symbol(dict_name
).put_symbol("begin");
1141 ndefs
+= DEFS_DICT_SPARE
;
1142 out
.put_literal_symbol(defs_dict_name
)
1143 .put_number(ndefs
+ 1)
1146 out
.put_symbol(defs_dict_name
)
1147 .put_symbol("begin");
1148 out
.put_literal_symbol("u")
1156 out
.special(defs
.contents());
1157 out
.put_symbol("end");
1159 out
.put_literal_symbol("#copies").put_number(ncopies
).put_symbol("def");
1160 out
.put_literal_symbol("RES").put_number(res
).put_symbol("def");
1161 out
.put_literal_symbol("PL");
1163 out
.put_symbol("PLG");
1165 out
.put_fix_number(paper_length
);
1166 out
.put_symbol("def");
1167 out
.put_literal_symbol("LS")
1168 .put_symbol(landscape_flag
? "true" : "false")
1171 out
.simple_comment((broken_flags
& NO_SETUP_SECTION
)
1175 out
.copy_file(tempfp
);
1179 void ps_printer::special(char *arg
, const environment
*env
)
1181 typedef void (ps_printer::*SPECIAL_PROCP
)(char *, const environment
*);
1186 "exec", &ps_printer::do_exec
,
1187 "def", &ps_printer::do_def
,
1188 "mdef", &ps_printer::do_mdef
,
1189 "import", &ps_printer::do_import
,
1190 "file", &ps_printer::do_file
,
1191 "invis", &ps_printer::do_invis
,
1192 "endinvis", &ps_printer::do_endinvis
,
1194 for (char *p
= arg
; *p
== ' ' || *p
== '\n'; p
++)
1197 for (; *p
!= '\0' && *p
!= ':' && *p
!= ' ' && *p
!= '\n'; p
++)
1199 if (*p
== '\0' || strncmp(tag
, "ps", p
- tag
) != 0) {
1200 error("X command without `ps:' tag ignored");
1204 for (; *p
== ' ' || *p
== '\n'; p
++)
1207 for (; *p
!= '\0' && *p
!= ' ' && *p
!= '\n'; p
++)
1209 if (*command
== '\0') {
1210 error("X command without `ps:' tag ignored");
1213 for (int i
= 0; i
< sizeof(proc_table
)/sizeof(proc_table
[0]); i
++)
1214 if (strncmp(command
, proc_table
[i
].name
, p
- command
) == 0) {
1215 (this->*(proc_table
[i
].proc
))(p
, env
);
1218 error("X command `%1' not recognised", command
);
1221 // A conforming PostScript document must not have lines longer
1222 // than 255 characters (excluding line termination characters).
1224 static int check_line_lengths(const char *p
)
1227 const char *end
= strchr(p
, '\n');
1229 end
= strchr(p
, '\0');
1239 void ps_printer::do_exec(char *arg
, const environment
*env
)
1242 while (csspace(*arg
))
1245 error("missing argument to X exec command");
1248 if (!check_line_lengths(arg
)) {
1249 error("lines in X exec command must not be more than 255 characters long");
1252 out
.put_fix_number(env
->hpos
)
1253 .put_fix_number(env
->vpos
)
1254 .put_symbol("EBEGIN")
1256 .put_symbol("EEND");
1257 output_hpos
= output_vpos
= -1;
1259 output_draw_point_size
= -1;
1260 output_line_thickness
= -1;
1261 ndefined_styles
= 0;
1266 void ps_printer::do_file(char *arg
, const environment
*env
)
1269 while (csspace(*arg
))
1272 error("missing argument to X file command");
1275 const char *filename
= arg
;
1278 } while (*arg
!= '\0' && *arg
!= ' ' && *arg
!= '\n');
1279 out
.put_fix_number(env
->hpos
)
1280 .put_fix_number(env
->vpos
)
1281 .put_symbol("EBEGIN");
1282 rm
.import_file(filename
, out
);
1283 out
.put_symbol("EEND");
1284 output_hpos
= output_vpos
= -1;
1286 output_draw_point_size
= -1;
1287 output_line_thickness
= -1;
1288 ndefined_styles
= 0;
1293 void ps_printer::do_def(char *arg
, const environment
*)
1296 while (csspace(*arg
))
1298 if (!check_line_lengths(arg
)) {
1299 error("lines in X def command must not be more than 255 characters long");
1303 if (*arg
!= '\0' && strchr(arg
, '\0')[-1] != '\n')
1308 // Like def, but the first argument says how many definitions it contains.
1310 void ps_printer::do_mdef(char *arg
, const environment
*)
1314 int n
= (int)strtol(arg
, &p
, 10);
1315 if (n
== 0 && p
== arg
) {
1316 error("first argument to X mdef must be an integer");
1320 error("out of range argument `%1' to X mdef command", int(n
));
1324 while (csspace(*arg
))
1326 if (!check_line_lengths(arg
)) {
1327 error("lines in X mdef command must not be more than 255 characters long");
1331 if (*arg
!= '\0' && strchr(arg
, '\0')[-1] != '\n')
1336 void ps_printer::do_import(char *arg
, const environment
*env
)
1339 while (*arg
== ' ' || *arg
== '\n')
1341 for (char *p
= arg
; *p
!= '\0' && *p
!= ' ' && *p
!= '\n'; p
++)
1347 while (nparms
< 6) {
1349 long n
= strtol(p
, &end
, 10);
1350 if (n
== 0 && end
== p
)
1352 parms
[nparms
++] = int(n
);
1355 if (csalpha(*p
) && (p
[1] == '\0' || p
[1] == ' ' || p
[1] == '\n')) {
1356 error("scaling indicators not allowed in arguments for X import command");
1359 while (*p
== ' ' || *p
== '\n')
1363 error("too few arguments for X import command");
1365 error("invalid argument `%1' for X import command", p
);
1369 error("superflous argument `%1' for X import command", p
);
1376 int desired_width
= parms
[4];
1377 int desired_height
= parms
[5];
1378 if (desired_width
<= 0) {
1379 error("bad width argument `%1' for X import command: must be > 0",
1383 if (nparms
== 6 && desired_height
<= 0) {
1384 error("bad height argument `%1' for X import command: must be > 0",
1389 error("llx and urx arguments for X import command must not be equal");
1393 error("lly and ury arguments for X import command must not be equal");
1397 int old_wid
= urx
- llx
;
1398 int old_ht
= ury
- lly
;
1403 desired_height
= int(desired_width
*(double(old_ht
)/double(old_wid
)) + .5);
1405 if (env
->vpos
- desired_height
< 0)
1406 warning("top of imported graphic is above the top of the page");
1409 .put_fix_number(desired_width
)
1410 .put_number(urx
- llx
)
1411 .put_fix_number(-desired_height
)
1412 .put_number(ury
- lly
)
1413 .put_fix_number(env
->hpos
)
1414 .put_fix_number(env
->vpos
)
1415 .put_symbol("PBEGIN");
1416 rm
.import_file(arg
, out
);
1417 // do this here just in case application defines PEND
1418 out
.put_symbol("end");
1419 out
.put_symbol("PEND");
1422 void ps_printer::do_invis(char *, const environment
*)
1427 void ps_printer::do_endinvis(char *, const environment
*)
1429 if (invis_count
== 0)
1430 error("unbalanced `endinvis' command");
1435 printer
*make_printer()
1437 return new ps_printer
;
1440 static void usage();
1442 int main(int argc
, char **argv
)
1444 program_name
= argv
[0];
1445 static char stderr_buf
[BUFSIZ
];
1446 setbuf(stderr
, stderr_buf
);
1448 while ((c
= getopt(argc
, argv
, "F:glc:w:vb:")) != EOF
)
1452 extern const char *version_string
;
1453 fprintf(stderr
, "grops version %s\n", version_string
);
1458 if (sscanf(optarg
, "%d", &ncopies
) != 1 || ncopies
<= 0) {
1459 error("bad number of copies `%s'", optarg
);
1470 font::command_line_font_dir(optarg
);
1473 if (sscanf(optarg
, "%d", &linewidth
) != 1 || linewidth
< 0) {
1474 error("bad linewidth `%s'", optarg
);
1480 broken_flags
= atoi(optarg
);
1489 font::set_unknown_desc_command_handler(handle_unknown_desc_command
);
1493 for (int i
= optind
; i
< argc
; i
++)
1502 fprintf(stderr
, "usage: %s [-glv] [-b n] [-c n] [-w n] [-F dir] [files ...]\n",