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. */
23 #include "file_case.h"
24 #include "stringclass.h"
29 #ifdef NEED_DECLARATION_PUTENV
31 int putenv(const char *);
33 #endif /* NEED_DECLARATION_PUTENV */
35 #define GROPS_PROLOGUE "prologue"
37 static void print_ps_string(const string
&s
, FILE *outfp
);
39 cset
white_space("\n\r \t\f");
40 string an_empty_string
;
42 char valid_input_table
[256]= {
43 #ifndef IS_EBCDIC_HOST
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
45 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
46 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
47 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
48 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
49 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
50 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
51 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
53 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
54 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
55 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
56 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
57 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
58 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
59 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
60 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
62 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
63 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
67 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
68 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
69 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
82 const char *extension_table
[] = {
89 const int NEXTENSIONS
= sizeof(extension_table
)/sizeof(extension_table
[0]);
91 const char *resource_table
[] = {
100 const int NRESOURCES
= sizeof(resource_table
)/sizeof(resource_table
[0]);
102 static int read_uint_arg(const char **pp
, unsigned *res
)
104 while (white_space(**pp
))
107 error("missing argument");
110 const char *start
= *pp
;
112 long n
= strtol(start
, (char **)pp
, 10);
113 if (n
== 0 && *pp
== start
) {
114 error("not an integer");
118 error("argument must not be negative");
129 enum { NEEDED
= 01, SUPPLIED
= 02, FONT_NEEDED
= 04, BUSY
= 010 };
135 resource(resource_type
, string
&, string
& = an_empty_string
, unsigned = 0);
137 void print_type_and_name(FILE *outfp
);
140 resource::resource(resource_type t
, string
&n
, string
&v
, unsigned r
)
141 : next(0), type(t
), flags(0), revision(r
), filename(0), rank(-1)
145 if (type
== RESOURCE_FILE
) {
146 if (name
.search('\0') >= 0)
147 error("filename contains a character with code 0");
148 filename
= name
.extract();
152 resource::~resource()
157 void resource::print_type_and_name(FILE *outfp
)
159 fputs(resource_table
[type
], outfp
);
161 print_ps_string(name
, outfp
);
162 if (type
== RESOURCE_PROCSET
) {
164 print_ps_string(version
, outfp
);
165 fprintf(outfp
, " %u", revision
);
169 resource_manager::resource_manager()
170 : extensions(0), language_level(0), resource_list(0)
172 read_download_file();
173 string
procset_name("grops");
174 extern const char *version_string
;
175 extern const char *revision_string
;
176 unsigned revision_uint
;
177 if (!read_uint_arg(&revision_string
, &revision_uint
))
179 string
procset_version(version_string
);
180 procset_resource
= lookup_resource(RESOURCE_PROCSET
, procset_name
,
181 procset_version
, revision_uint
);
182 procset_resource
->flags
|= resource::SUPPLIED
;
185 resource_manager::~resource_manager()
187 while (resource_list
) {
188 resource
*tem
= resource_list
;
189 resource_list
= resource_list
->next
;
194 resource
*resource_manager::lookup_resource(resource_type type
,
200 for (r
= resource_list
; r
; r
= r
->next
)
203 && r
->version
== version
204 && r
->revision
== revision
)
206 r
= new resource(type
, name
, version
, revision
);
207 r
->next
= resource_list
;
212 // Just a specialized version of lookup_resource().
214 resource
*resource_manager::lookup_font(const char *name
)
217 for (r
= resource_list
; r
; r
= r
->next
)
218 if (r
->type
== RESOURCE_FONT
219 && strlen(name
) == (size_t)r
->name
.length()
220 && memcmp(name
, r
->name
.contents(), r
->name
.length()) == 0)
223 r
= new resource(RESOURCE_FONT
, s
);
224 r
->next
= resource_list
;
229 void resource_manager::need_font(const char *name
)
231 lookup_font(name
)->flags
|= resource::FONT_NEEDED
;
234 typedef resource
*Presource
; // Work around g++ bug.
236 void resource_manager::document_setup(ps_output
&out
)
240 for (r
= resource_list
; r
; r
= r
->next
)
241 if (r
->rank
>= nranks
)
242 nranks
= r
->rank
+ 1;
244 // Sort resource_list in reverse order of rank.
245 Presource
*head
= new Presource
[nranks
+ 1];
246 Presource
**tail
= new Presource
*[nranks
+ 1];
248 for (i
= 0; i
< nranks
+ 1; i
++) {
252 for (r
= resource_list
; r
; r
= r
->next
) {
253 i
= r
->rank
< 0 ? 0 : r
->rank
+ 1;
255 tail
[i
] = &(*tail
[i
])->next
;
258 for (i
= 0; i
< nranks
+ 1; i
++)
260 *tail
[i
] = resource_list
;
261 resource_list
= head
[i
];
266 for (r
= resource_list
; r
; r
= r
->next
)
268 assert(r
->rank
>= r
->next
->rank
);
269 for (r
= resource_list
; r
; r
= r
->next
)
270 if (r
->type
== RESOURCE_FONT
&& r
->rank
>= 0)
271 supply_resource(r
, -1, out
.get_file());
275 void resource_manager::print_resources_comment(unsigned flag
, FILE *outfp
)
278 for (resource
*r
= resource_list
; r
; r
= r
->next
)
279 if (r
->flags
& flag
) {
281 fputs("%%+ ", outfp
);
283 fputs(flag
== resource::NEEDED
284 ? "%%DocumentNeededResources: "
285 : "%%DocumentSuppliedResources: ",
289 r
->print_type_and_name(outfp
);
294 void resource_manager::print_header_comments(ps_output
&out
)
296 for (resource
*r
= resource_list
; r
; r
= r
->next
)
297 if (r
->type
== RESOURCE_FONT
&& (r
->flags
& resource::FONT_NEEDED
))
298 supply_resource(r
, 0, 0);
299 print_resources_comment(resource::NEEDED
, out
.get_file());
300 print_resources_comment(resource::SUPPLIED
, out
.get_file());
301 print_language_level_comment(out
.get_file());
302 print_extensions_comment(out
.get_file());
305 void resource_manager::output_prolog(ps_output
&out
)
307 FILE *outfp
= out
.get_file();
309 if (!getenv("GROPS_PROLOGUE")) {
310 string e
= "GROPS_PROLOGUE";
314 if (putenv(strsave(e
.contents())))
315 fatal("putenv failed");
317 char *prologue
= getenv("GROPS_PROLOGUE");
319 file_case
*fcp
= font::open_file(prologue
);
321 fatal("can't find `%1'", prologue
);
323 fputs("%%BeginResource: ", outfp
);
324 procset_resource
->print_type_and_name(outfp
);
326 process_file(-1, fcp
, outfp
);
327 fputs("%%EndResource\n", outfp
);
332 void resource_manager::import_file(const char *filename
, ps_output
&out
)
335 string
name(filename
);
336 resource
*r
= lookup_resource(RESOURCE_FILE
, name
);
337 supply_resource(r
, -1, out
.get_file(), 1);
340 void resource_manager::supply_resource(resource
*r
, int rank
, FILE *outfp
,
343 if (r
->flags
& resource::BUSY
) {
345 fatal("loop detected in dependency graph for %1 `%2'",
346 resource_table
[r
->type
],
349 r
->flags
|= resource::BUSY
;
353 file_case
*fcp
= NULL
;
354 if (r
->filename
!= NULL
) {
355 if (r
->type
== RESOURCE_FONT
) {
356 if ((fcp
= font::open_file(r
->filename
)) == NULL
)
357 error("can't find `%1'", r
->filename
);
359 if ((fcp
= include_search_path
.open_file_cautious(r
->filename
)) == NULL
)
360 error("can't open `%1': %2", r
->filename
, strerror(errno
));
363 a_delete r
->filename
;
370 if (r
->type
== RESOURCE_FILE
&& is_document
) {
371 fputs("%%BeginDocument: ", outfp
);
372 print_ps_string(r
->name
, outfp
);
375 fputs("%%BeginResource: ", outfp
);
376 r
->print_type_and_name(outfp
);
380 process_file(rank
, fcp
, outfp
);
384 if (r
->type
== RESOURCE_FILE
&& is_document
)
385 fputs("%%EndDocument\n", outfp
);
387 fputs("%%EndResource\n", outfp
);
389 r
->flags
|= resource::SUPPLIED
;
392 if (r
->type
== RESOURCE_FILE
&& is_document
) {
393 fputs("%%IncludeDocument: ", outfp
);
394 print_ps_string(r
->name
, outfp
);
397 fputs("%%IncludeResource: ", outfp
);
398 r
->print_type_and_name(outfp
);
402 r
->flags
|= resource::NEEDED
;
404 r
->flags
&= ~resource::BUSY
;
407 #define PS_MAGIC "%!PS-Adobe-"
409 static int ps_get_line(string
&buf
, file_case
*fcp
)
412 int c
= fcp
->get_c();
416 while (c
!= '\r' && c
!= '\n' && c
!= EOF
) {
417 if (!valid_input_table
[c
])
418 error("invalid input character code %1", int(c
));
426 if (c
!= EOF
&& c
!= '\n')
432 static int read_text_arg(const char **pp
, string
&res
)
435 while (white_space(**pp
))
438 error("missing argument");
442 for (; **pp
!= '\0' && !white_space(**pp
); *pp
+= 1)
450 if (**pp
== '\0' || **pp
== '\r' || **pp
== '\n') {
451 error("missing ')'");
462 else if (**pp
== '(') {
466 else if (**pp
== '\\') {
493 int val
= **pp
- '0';
494 if ((*pp
)[1] >= '0' && (*pp
)[1] <= '7') {
496 val
= val
*8 + (**pp
- '0');
497 if ((*pp
)[1] >= '0' && (*pp
)[1] <= '7') {
499 val
= val
*8 + (**pp
- '0');
516 resource
*resource_manager::read_file_arg(const char **ptr
)
519 if (!read_text_arg(ptr
, arg
))
521 return lookup_resource(RESOURCE_FILE
, arg
);
524 resource
*resource_manager::read_font_arg(const char **ptr
)
527 if (!read_text_arg(ptr
, arg
))
529 return lookup_resource(RESOURCE_FONT
, arg
);
532 resource
*resource_manager::read_procset_arg(const char **ptr
)
535 if (!read_text_arg(ptr
, arg
))
538 if (!read_text_arg(ptr
, version
))
541 if (!read_uint_arg(ptr
, &revision
))
543 return lookup_resource(RESOURCE_PROCSET
, arg
, version
, revision
);
546 resource
*resource_manager::read_resource_arg(const char **ptr
)
548 while (white_space(**ptr
))
550 const char *name
= *ptr
;
551 while (**ptr
!= '\0' && !white_space(**ptr
))
554 error("missing resource type");
558 for (ri
= 0; ri
< NRESOURCES
; ri
++)
559 if (strlen(resource_table
[ri
]) == size_t(*ptr
- name
)
560 && memcmp(resource_table
[ri
], name
, *ptr
- name
) == 0)
562 if (ri
>= NRESOURCES
) {
563 error("unknown resource type");
566 if (ri
== RESOURCE_PROCSET
)
567 return read_procset_arg(ptr
);
569 if (!read_text_arg(ptr
, arg
))
571 return lookup_resource(resource_type(ri
), arg
);
574 static const char *matches_comment(string
&buf
, const char *comment
)
576 if ((size_t)buf
.length() < strlen(comment
) + 3)
578 if (buf
[0] != '%' || buf
[1] != '%')
580 const char *bufp
= buf
.contents() + 2;
581 for (; *comment
; comment
++, bufp
++)
582 if (*bufp
!= *comment
)
584 if (comment
[-1] == ':')
586 if (*bufp
== '\0' || white_space(*bufp
))
591 // Return 1 if the line should be copied out.
593 int resource_manager::do_begin_resource(const char *ptr
, int, file_case
*,
596 resource
*r
= read_resource_arg(&ptr
);
598 r
->flags
|= resource::SUPPLIED
;
602 int resource_manager::do_include_resource(const char *ptr
, int rank
,
603 file_case
*, FILE *outfp
)
605 resource
*r
= read_resource_arg(&ptr
);
607 if (r
->type
== RESOURCE_FONT
) {
609 supply_resource(r
, rank
+ 1, outfp
);
611 r
->flags
|= resource::FONT_NEEDED
;
614 supply_resource(r
, rank
, outfp
);
619 int resource_manager::do_begin_document(const char *ptr
, int, file_case
*,
622 resource
*r
= read_file_arg(&ptr
);
624 r
->flags
|= resource::SUPPLIED
;
628 int resource_manager::do_include_document(const char *ptr
, int rank
,
629 file_case
*, FILE *outfp
)
631 resource
*r
= read_file_arg(&ptr
);
633 supply_resource(r
, rank
, outfp
, 1);
637 int resource_manager::do_begin_procset(const char *ptr
, int, file_case
*,
640 resource
*r
= read_procset_arg(&ptr
);
642 r
->flags
|= resource::SUPPLIED
;
644 fputs("%%BeginResource: ", outfp
);
645 r
->print_type_and_name(outfp
);
652 int resource_manager::do_include_procset(const char *ptr
, int rank
,
653 file_case
*, FILE *outfp
)
655 resource
*r
= read_procset_arg(&ptr
);
657 supply_resource(r
, rank
, outfp
);
661 int resource_manager::do_begin_file(const char *ptr
, int, file_case
*,
664 resource
*r
= read_file_arg(&ptr
);
666 r
->flags
|= resource::SUPPLIED
;
668 fputs("%%BeginResource: ", outfp
);
669 r
->print_type_and_name(outfp
);
676 int resource_manager::do_include_file(const char *ptr
, int rank
, file_case
*,
679 resource
*r
= read_file_arg(&ptr
);
681 supply_resource(r
, rank
, outfp
);
685 int resource_manager::do_begin_font(const char *ptr
, int, file_case
*,
688 resource
*r
= read_font_arg(&ptr
);
690 r
->flags
|= resource::SUPPLIED
;
692 fputs("%%BeginResource: ", outfp
);
693 r
->print_type_and_name(outfp
);
700 int resource_manager::do_include_font(const char *ptr
, int rank
, file_case
*,
703 resource
*r
= read_font_arg(&ptr
);
706 supply_resource(r
, rank
+ 1, outfp
);
708 r
->flags
|= resource::FONT_NEEDED
;
713 int resource_manager::change_to_end_resource(const char *, int, file_case
*,
717 fputs("%%EndResource\n", outfp
);
721 int resource_manager::do_begin_preview(const char *, int, file_case
*fcp
,
726 if (!ps_get_line(buf
, fcp
)) {
727 error("end of file in preview section");
730 } while (!matches_comment(buf
, "EndPreview"));
734 int read_one_of(const char **ptr
, const char **s
, int n
)
736 while (white_space(**ptr
))
740 const char *start
= *ptr
;
743 } while (**ptr
!= '\0' && !white_space(**ptr
));
744 for (int i
= 0; i
< n
; i
++)
745 if (strlen(s
[i
]) == size_t(*ptr
- start
)
746 && memcmp(s
[i
], start
, *ptr
- start
) == 0)
751 void skip_possible_newline(file_case
*fcp
, FILE *outfp
)
753 int c
= fcp
->get_c();
758 int cc
= fcp
->get_c();
768 else if (c
== '\n') {
777 int resource_manager::do_begin_data(const char *ptr
, int, file_case
*fcp
,
780 while (white_space(*ptr
))
782 const char *start
= ptr
;
784 if (!read_uint_arg(&ptr
, &numberof
))
786 static const char *types
[] = { "Binary", "Hex", "ASCII" };
787 const int Binary
= 0;
789 static const char *units
[] = { "Bytes", "Lines" };
792 while (white_space(*ptr
))
795 type
= read_one_of(&ptr
, types
, 3);
797 error("bad data type");
800 while (white_space(*ptr
))
803 unit
= read_one_of(&ptr
, units
, 2);
805 error("expected `Bytes' or `Lines'");
813 fputs("%%BeginData: ", outfp
);
817 unsigned bytecount
= 0;
818 unsigned linecount
= 0;
820 int c
= fcp
->get_c();
822 error("end of file within data section");
829 int cc
= fcp
->get_c();
837 else if (c
== '\n') {
841 } while ((unit
== Bytes
? bytecount
: linecount
) < numberof
);
843 skip_possible_newline(fcp
, outfp
);
845 if (!ps_get_line(buf
, fcp
)) {
846 error("missing %%%%EndData line");
849 if (!matches_comment(buf
, "EndData"))
850 error("bad %%%%EndData line");
852 fputs(buf
.contents(), outfp
);
856 int resource_manager::do_begin_binary(const char *ptr
, int, file_case
*fcp
,
862 if (!read_uint_arg(&ptr
, &count
))
865 fprintf(outfp
, "%%%%BeginData: %u Binary Bytes\n", count
);
867 int c
= fcp
->get_c();
869 error("end of file within binary section");
876 int cc
= fcp
->get_c();
885 skip_possible_newline(fcp
, outfp
);
887 if (!ps_get_line(buf
, fcp
)) {
888 error("missing %%%%EndBinary line");
891 if (!matches_comment(buf
, "EndBinary")) {
892 error("bad %%%%EndBinary line");
894 fputs(buf
.contents(), outfp
);
897 fputs("%%EndData\n", outfp
);
901 static unsigned parse_extensions(const char *ptr
)
905 while (white_space(*ptr
))
909 const char *name
= ptr
;
912 } while (*ptr
!= '\0' && !white_space(*ptr
));
914 for (i
= 0; i
< NEXTENSIONS
; i
++)
915 if (strlen(extension_table
[i
]) == size_t(ptr
- name
)
916 && memcmp(extension_table
[i
], name
, ptr
- name
) == 0) {
920 if (i
>= NEXTENSIONS
) {
921 string
s(name
, ptr
- name
);
923 error("unknown extension `%1'", s
.contents());
929 // XXX if it has not been surrounded with {Begin,End}Document need to strip
930 // out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections.
932 // XXX Perhaps the decision whether to use BeginDocument or
933 // BeginResource: file should be postponed till we have seen
934 // the first line of the file.
936 void resource_manager::process_file(int rank
, file_case
*fcp
, FILE *outfp
)
938 // If none of these comments appear in the header section, and we are
939 // just analyzing the file (ie outfp is 0), then we can return immediately.
940 static const char *header_comment_table
[] = {
941 "DocumentNeededResources:",
942 "DocumentSuppliedResources:",
943 "DocumentNeededFonts:",
944 "DocumentSuppliedFonts:",
945 "DocumentNeededProcSets:",
946 "DocumentSuppliedProcSets:",
947 "DocumentNeededFiles:",
948 "DocumentSuppliedFiles:",
951 const int NHEADER_COMMENTS
= sizeof(header_comment_table
)
952 / sizeof(header_comment_table
[0]);
953 struct comment_info
{
955 int (resource_manager::*proc
)(const char *, int, file_case
*, FILE *);
958 static comment_info comment_table
[] = {
959 { "BeginResource:", &resource_manager::do_begin_resource
},
960 { "IncludeResource:", &resource_manager::do_include_resource
},
961 { "BeginDocument:", &resource_manager::do_begin_document
},
962 { "IncludeDocument:", &resource_manager::do_include_document
},
963 { "BeginProcSet:", &resource_manager::do_begin_procset
},
964 { "IncludeProcSet:", &resource_manager::do_include_procset
},
965 { "BeginFont:", &resource_manager::do_begin_font
},
966 { "IncludeFont:", &resource_manager::do_include_font
},
967 { "BeginFile:", &resource_manager::do_begin_file
},
968 { "IncludeFile:", &resource_manager::do_include_file
},
969 { "EndProcSet", &resource_manager::change_to_end_resource
},
970 { "EndFont", &resource_manager::change_to_end_resource
},
971 { "EndFile", &resource_manager::change_to_end_resource
},
972 { "BeginPreview:", &resource_manager::do_begin_preview
},
973 { "BeginData:", &resource_manager::do_begin_data
},
974 { "BeginBinary:", &resource_manager::do_begin_binary
},
977 const int NCOMMENTS
= sizeof(comment_table
)/sizeof(comment_table
[0]);
979 int saved_lineno
= current_lineno
;
980 const char *saved_filename
= current_filename
;
981 current_filename
= fcp
->path();
983 if (!ps_get_line(buf
, fcp
)) {
984 current_filename
= saved_filename
;
985 current_lineno
= saved_lineno
;
988 if ((size_t)buf
.length() < sizeof(PS_MAGIC
)
989 || memcmp(buf
.contents(), PS_MAGIC
, sizeof(PS_MAGIC
) - 1) != 0) {
992 if (!(broken_flags
& STRIP_PERCENT_BANG
)
993 || buf
[0] != '%' || buf
[1] != '!')
994 fputs(buf
.contents(), outfp
);
995 } while (ps_get_line(buf
, fcp
));
999 if (!(broken_flags
& STRIP_PERCENT_BANG
) && outfp
)
1000 fputs(buf
.contents(), outfp
);
1002 int interesting
= 0;
1003 int had_extensions_comment
= 0;
1004 int had_language_level_comment
= 0;
1006 if (!ps_get_line(buf
, fcp
))
1008 int copy_this_line
= 1;
1009 if (buf
[0] == '%') {
1010 if (buf
[1] == '%') {
1013 for (i
= 0; i
< NCOMMENTS
; i
++)
1014 if ((ptr
= matches_comment(buf
, comment_table
[i
].name
))) {
1016 = (this->*(comment_table
[i
].proc
))(ptr
, rank
, fcp
, outfp
);
1019 if (i
>= NCOMMENTS
&& in_header
) {
1020 if ((ptr
= matches_comment(buf
, "EndComments")))
1022 else if (!had_extensions_comment
1023 && (ptr
= matches_comment(buf
, "Extensions:"))) {
1024 extensions
|= parse_extensions(ptr
);
1025 // XXX handle possibility that next line is %%+
1026 had_extensions_comment
= 1;
1028 else if (!had_language_level_comment
1029 && (ptr
= matches_comment(buf
, "LanguageLevel:"))) {
1031 if (read_uint_arg(&ptr
, &ll
) && ll
> language_level
)
1032 language_level
= ll
;
1033 had_language_level_comment
= 1;
1036 for (i
= 0; i
< NHEADER_COMMENTS
; i
++)
1037 if (matches_comment(buf
, header_comment_table
[i
])) {
1043 if ((broken_flags
& STRIP_STRUCTURE_COMMENTS
)
1044 && (matches_comment(buf
, "EndProlog")
1045 || matches_comment(buf
, "Page:")
1046 || matches_comment(buf
, "Trailer")))
1049 else if (buf
[1] == '!') {
1050 if (broken_flags
& STRIP_PERCENT_BANG
)
1056 if (!outfp
&& !in_header
&& !interesting
)
1058 if (copy_this_line
&& outfp
)
1059 fputs(buf
.contents(), outfp
);
1062 current_filename
= saved_filename
;
1063 current_lineno
= saved_lineno
;
1066 void resource_manager::read_download_file()
1068 file_case
*fcp
= font::open_file("download");
1070 fatal("can't find `download'");
1073 for (int lineno
= 1; fcp
->get_line(buf
, sizeof(buf
)) != NULL
; ++lineno
) {
1074 char *p
= strtok(buf
, " \t\r\n");
1075 if (p
== NULL
|| *p
== '#')
1077 char *q
= strtok(0, " \t\r\n");
1079 fatal_with_file_and_line(fcp
->path(), lineno
, "missing filename");
1080 lookup_font(p
)->filename
= strsave(q
);
1086 // XXX Can we share some code with ps_output::put_string()?
1088 static void print_ps_string(const string
&s
, FILE *outfp
)
1090 int len
= s
.length();
1091 const char *str
= s
.contents();
1096 for (int i
= 0; i
< len
; i
++)
1097 if (str
[i
] <= 040 || str
[i
] > 0176) {
1103 put_string(s
, outfp
);
1108 for (i
= 0; i
< len
; i
++)
1111 else if (str
[i
] == ')' && --level
< 0)
1114 for (i
= 0; i
< len
; i
++)
1120 putc(str
[i
], outfp
);
1123 fputs("\\\\", outfp
);
1126 fputs("\\n", outfp
);
1129 fputs("\\r", outfp
);
1132 fputs("\\t", outfp
);
1135 fputs("\\b", outfp
);
1138 fputs("\\f", outfp
);
1141 if (str
[i
] < 040 || str
[i
] > 0176)
1142 fprintf(outfp
, "\\%03o", str
[i
] & 0377);
1144 putc(str
[i
], outfp
);
1150 void resource_manager::print_extensions_comment(FILE *outfp
)
1153 fputs("%%Extensions:", outfp
);
1154 for (int i
= 0; i
< NEXTENSIONS
; i
++)
1155 if (extensions
& (1 << i
)) {
1157 fputs(extension_table
[i
], outfp
);
1163 void resource_manager::print_language_level_comment(FILE *outfp
)
1166 fprintf(outfp
, "%%%%LanguageLevel: %u\n", language_level
);