2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2000 - 2004
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
24 #include "ps-config.h"
28 #include "file_case.h"
29 #include "stringclass.h"
33 #ifdef NEED_DECLARATION_PUTENV /* FIXME */
35 int putenv(const char *);
37 #endif /* NEED_DECLARATION_PUTENV */
39 static void print_ps_string(const string
&s
, FILE *outfp
);
41 cset
white_space("\n\r \t\f");
42 string an_empty_string
;
44 char valid_input_table
[256]= {
45 #ifndef IS_EBCDIC_HOST
46 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
47 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 1,
52 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
53 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
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,
61 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
62 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
64 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
65 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
66 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
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,
70 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,
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, 1,
79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
84 const char *extension_table
[] = {
91 const int NEXTENSIONS
= sizeof(extension_table
)/sizeof(extension_table
[0]);
93 const char *resource_table
[] = {
102 const int NRESOURCES
= sizeof(resource_table
)/sizeof(resource_table
[0]);
104 static int read_uint_arg(const char **pp
, unsigned *res
)
106 while (white_space(**pp
))
109 error("missing argument");
112 const char *start
= *pp
;
114 long n
= strtol(start
, (char **)pp
, 10);
115 if (n
== 0 && *pp
== start
) {
116 error("not an integer");
120 error("argument must not be negative");
133 enum { NEEDED
= 01, SUPPLIED
= 02, FONT_NEEDED
= 04, BUSY
= 010 };
139 resource(resource_type
, string
&, string
& = an_empty_string
, unsigned = 0);
141 void print_type_and_name(FILE *outfp
);
144 resource::resource(resource_type t
, string
&n
, string
&v
, unsigned r
)
145 : next(0), type(t
), flags(0), revision(r
), filename(0), rank(-1)
149 if (type
== RESOURCE_FILE
) {
150 if (name
.search('\0') >= 0)
151 error("filename contains a character with code 0");
152 filename
= name
.extract();
156 resource::~resource()
161 void resource::print_type_and_name(FILE *outfp
)
163 fputs(resource_table
[type
], outfp
);
165 print_ps_string(name
, outfp
);
166 if (type
== RESOURCE_PROCSET
) {
168 print_ps_string(version
, outfp
);
169 fprintf(outfp
, " %u", revision
);
173 resource_manager::resource_manager()
174 : extensions(0), language_level(0), resource_list(0)
176 read_download_file();
177 string
procset_name(L_D_PS
);
178 extern const char *version_string
; /* FIXME */
179 extern const char *revision_string
; /* FIXME */
180 unsigned revision_uint
;
181 if (!read_uint_arg(&revision_string
, &revision_uint
))
183 string
procset_version(version_string
);
184 procset_resource
= lookup_resource(RESOURCE_PROCSET
, procset_name
,
185 procset_version
, revision_uint
);
186 procset_resource
->flags
|= resource::SUPPLIED
;
189 resource_manager::~resource_manager()
191 while (resource_list
) {
192 resource
*tem
= resource_list
;
193 resource_list
= resource_list
->next
;
198 resource
*resource_manager::lookup_resource(resource_type type
,
204 for (r
= resource_list
; r
; r
= r
->next
)
207 && r
->version
== version
208 && r
->revision
== revision
)
210 r
= new resource(type
, name
, version
, revision
);
211 r
->next
= resource_list
;
216 // Just a specialized version of lookup_resource().
218 resource
*resource_manager::lookup_font(const char *name
)
221 for (r
= resource_list
; r
; r
= r
->next
)
222 if (r
->type
== RESOURCE_FONT
223 && strlen(name
) == (size_t)r
->name
.length()
224 && memcmp(name
, r
->name
.contents(), r
->name
.length()) == 0)
227 r
= new resource(RESOURCE_FONT
, s
);
228 r
->next
= resource_list
;
233 void resource_manager::need_font(const char *name
)
235 lookup_font(name
)->flags
|= resource::FONT_NEEDED
;
238 typedef resource
*Presource
; // Work around g++ bug.
240 void resource_manager::document_setup(ps_output
&out
)
244 for (r
= resource_list
; r
; r
= r
->next
)
245 if (r
->rank
>= nranks
)
246 nranks
= r
->rank
+ 1;
248 // Sort resource_list in reverse order of rank.
249 Presource
*head
= new Presource
[nranks
+ 1];
250 Presource
**tail
= new Presource
*[nranks
+ 1];
252 for (i
= 0; i
< nranks
+ 1; i
++) {
256 for (r
= resource_list
; r
; r
= r
->next
) {
257 i
= r
->rank
< 0 ? 0 : r
->rank
+ 1;
259 tail
[i
] = &(*tail
[i
])->next
;
262 for (i
= 0; i
< nranks
+ 1; i
++)
264 *tail
[i
] = resource_list
;
265 resource_list
= head
[i
];
270 for (r
= resource_list
; r
; r
= r
->next
)
272 assert(r
->rank
>= r
->next
->rank
);
273 for (r
= resource_list
; r
; r
= r
->next
)
274 if (r
->type
== RESOURCE_FONT
&& r
->rank
>= 0)
275 supply_resource(r
, -1, out
.get_file());
279 void resource_manager::print_resources_comment(unsigned flag
, FILE *outfp
)
282 for (resource
*r
= resource_list
; r
; r
= r
->next
)
283 if (r
->flags
& flag
) {
285 fputs("%%+ ", outfp
);
287 fputs(flag
== resource::NEEDED
288 ? "%%DocumentNeededResources: "
289 : "%%DocumentSuppliedResources: ",
293 r
->print_type_and_name(outfp
);
298 void resource_manager::print_header_comments(ps_output
&out
)
300 for (resource
*r
= resource_list
; r
; r
= r
->next
)
301 if (r
->type
== RESOURCE_FONT
&& (r
->flags
& resource::FONT_NEEDED
))
302 supply_resource(r
, 0, 0);
303 print_resources_comment(resource::NEEDED
, out
.get_file());
304 print_resources_comment(resource::SUPPLIED
, out
.get_file());
305 print_language_level_comment(out
.get_file());
306 print_extensions_comment(out
.get_file());
309 void resource_manager::output_prolog(ps_output
&out
)
311 FILE *outfp
= out
.get_file();
313 char const *prologue
;
314 if ((prologue
= getenv(U_D_PS_PROLOGUE
)) == NULL
) {
315 string e
= U_D_PS_PROLOGUE
;
317 e
+= (prologue
= PROLOGUE_DEFAULT
);
319 if (putenv(strsave(e
.contents())))
320 fatal("putenv failed");
323 file_case
*fcp
= font::open_file(prologue
);
325 fatal("can't find `%1'", prologue
);
327 fputs("%%BeginResource: ", outfp
);
328 procset_resource
->print_type_and_name(outfp
);
330 process_file(-1, fcp
, outfp
);
331 fputs("%%EndResource\n", outfp
);
336 void resource_manager::import_file(const char *filename
, ps_output
&out
)
339 string
name(filename
);
340 resource
*r
= lookup_resource(RESOURCE_FILE
, name
);
341 supply_resource(r
, -1, out
.get_file(), 1);
344 void resource_manager::supply_resource(resource
*r
, int rank
, FILE *outfp
,
347 if (r
->flags
& resource::BUSY
) {
349 fatal("loop detected in dependency graph for %1 `%2'",
350 resource_table
[r
->type
],
353 r
->flags
|= resource::BUSY
;
357 file_case
*fcp
= NULL
;
358 if (r
->filename
!= NULL
) {
359 if (r
->type
== RESOURCE_FONT
) {
360 if ((fcp
= font::open_file(r
->filename
)) == NULL
)
361 error("can't find `%1'", r
->filename
);
363 if ((fcp
= include_search_path
.open_file_cautious(r
->filename
)) == NULL
)
364 error("can't open `%1': %2", r
->filename
, strerror(errno
));
367 a_delete r
->filename
;
374 if (r
->type
== RESOURCE_FILE
&& is_document
) {
375 fputs("%%BeginDocument: ", outfp
);
376 print_ps_string(r
->name
, outfp
);
379 fputs("%%BeginResource: ", outfp
);
380 r
->print_type_and_name(outfp
);
384 process_file(rank
, fcp
, outfp
);
388 if (r
->type
== RESOURCE_FILE
&& is_document
)
389 fputs("%%EndDocument\n", outfp
);
391 fputs("%%EndResource\n", outfp
);
393 r
->flags
|= resource::SUPPLIED
;
396 if (r
->type
== RESOURCE_FILE
&& is_document
) {
397 fputs("%%IncludeDocument: ", outfp
);
398 print_ps_string(r
->name
, outfp
);
401 fputs("%%IncludeResource: ", outfp
);
402 r
->print_type_and_name(outfp
);
406 r
->flags
|= resource::NEEDED
;
408 r
->flags
&= ~resource::BUSY
;
411 static int ps_get_line(string
&buf
, file_case
*fcp
)
414 int c
= fcp
->get_c();
418 while (c
!= '\r' && c
!= '\n' && c
!= EOF
) {
419 if (!valid_input_table
[c
])
420 error("invalid input character code %1", int(c
));
428 if (c
!= EOF
&& c
!= '\n')
434 static int read_text_arg(const char **pp
, string
&res
)
437 while (white_space(**pp
))
440 error("missing argument");
444 for (; **pp
!= '\0' && !white_space(**pp
); *pp
+= 1)
452 if (**pp
== '\0' || **pp
== '\r' || **pp
== '\n') {
453 error("missing ')'");
464 else if (**pp
== '(') {
468 else if (**pp
== '\\') {
495 int val
= **pp
- '0';
496 if ((*pp
)[1] >= '0' && (*pp
)[1] <= '7') {
498 val
= val
*8 + (**pp
- '0');
499 if ((*pp
)[1] >= '0' && (*pp
)[1] <= '7') {
501 val
= val
*8 + (**pp
- '0');
518 resource
*resource_manager::read_file_arg(const char **ptr
)
521 if (!read_text_arg(ptr
, arg
))
523 return lookup_resource(RESOURCE_FILE
, arg
);
526 resource
*resource_manager::read_font_arg(const char **ptr
)
529 if (!read_text_arg(ptr
, arg
))
531 return lookup_resource(RESOURCE_FONT
, arg
);
534 resource
*resource_manager::read_procset_arg(const char **ptr
)
537 if (!read_text_arg(ptr
, arg
))
540 if (!read_text_arg(ptr
, version
))
543 if (!read_uint_arg(ptr
, &revision
))
545 return lookup_resource(RESOURCE_PROCSET
, arg
, version
, revision
);
548 resource
*resource_manager::read_resource_arg(const char **ptr
)
550 while (white_space(**ptr
))
552 const char *name
= *ptr
;
553 while (**ptr
!= '\0' && !white_space(**ptr
))
556 error("missing resource type");
560 for (ri
= 0; ri
< NRESOURCES
; ri
++)
561 if (strlen(resource_table
[ri
]) == size_t(*ptr
- name
)
562 && memcmp(resource_table
[ri
], name
, *ptr
- name
) == 0)
564 if (ri
>= NRESOURCES
) {
565 error("unknown resource type");
568 if (ri
== RESOURCE_PROCSET
)
569 return read_procset_arg(ptr
);
571 if (!read_text_arg(ptr
, arg
))
573 return lookup_resource(resource_type(ri
), arg
);
576 static const char *matches_comment(string
&buf
, const char *comment
)
578 if ((size_t)buf
.length() < strlen(comment
) + 3)
580 if (buf
[0] != '%' || buf
[1] != '%')
582 const char *bufp
= buf
.contents() + 2;
583 for (; *comment
; comment
++, bufp
++)
584 if (*bufp
!= *comment
)
586 if (comment
[-1] == ':')
588 if (*bufp
== '\0' || white_space(*bufp
))
593 // Return 1 if the line should be copied out.
595 int resource_manager::do_begin_resource(const char *ptr
, int, file_case
*,
598 resource
*r
= read_resource_arg(&ptr
);
600 r
->flags
|= resource::SUPPLIED
;
604 int resource_manager::do_include_resource(const char *ptr
, int rank
,
605 file_case
*, FILE *outfp
)
607 resource
*r
= read_resource_arg(&ptr
);
609 if (r
->type
== RESOURCE_FONT
) {
611 supply_resource(r
, rank
+ 1, outfp
);
613 r
->flags
|= resource::FONT_NEEDED
;
616 supply_resource(r
, rank
, outfp
);
621 int resource_manager::do_begin_document(const char *ptr
, int, file_case
*,
624 resource
*r
= read_file_arg(&ptr
);
626 r
->flags
|= resource::SUPPLIED
;
630 int resource_manager::do_include_document(const char *ptr
, int rank
,
631 file_case
*, FILE *outfp
)
633 resource
*r
= read_file_arg(&ptr
);
635 supply_resource(r
, rank
, outfp
, 1);
639 int resource_manager::do_begin_procset(const char *ptr
, int, file_case
*,
642 resource
*r
= read_procset_arg(&ptr
);
644 r
->flags
|= resource::SUPPLIED
;
646 fputs("%%BeginResource: ", outfp
);
647 r
->print_type_and_name(outfp
);
654 int resource_manager::do_include_procset(const char *ptr
, int rank
,
655 file_case
*, FILE *outfp
)
657 resource
*r
= read_procset_arg(&ptr
);
659 supply_resource(r
, rank
, outfp
);
663 int resource_manager::do_begin_file(const char *ptr
, int, file_case
*,
666 resource
*r
= read_file_arg(&ptr
);
668 r
->flags
|= resource::SUPPLIED
;
670 fputs("%%BeginResource: ", outfp
);
671 r
->print_type_and_name(outfp
);
678 int resource_manager::do_include_file(const char *ptr
, int rank
, file_case
*,
681 resource
*r
= read_file_arg(&ptr
);
683 supply_resource(r
, rank
, outfp
);
687 int resource_manager::do_begin_font(const char *ptr
, int, file_case
*,
690 resource
*r
= read_font_arg(&ptr
);
692 r
->flags
|= resource::SUPPLIED
;
694 fputs("%%BeginResource: ", outfp
);
695 r
->print_type_and_name(outfp
);
702 int resource_manager::do_include_font(const char *ptr
, int rank
, file_case
*,
705 resource
*r
= read_font_arg(&ptr
);
708 supply_resource(r
, rank
+ 1, outfp
);
710 r
->flags
|= resource::FONT_NEEDED
;
715 int resource_manager::change_to_end_resource(const char *, int, file_case
*,
719 fputs("%%EndResource\n", outfp
);
723 int resource_manager::do_begin_preview(const char *, int, file_case
*fcp
,
728 if (!ps_get_line(buf
, fcp
)) {
729 error("end of file in preview section");
732 } while (!matches_comment(buf
, "EndPreview"));
736 int read_one_of(const char **ptr
, const char **s
, int n
)
738 while (white_space(**ptr
))
742 const char *start
= *ptr
;
745 } while (**ptr
!= '\0' && !white_space(**ptr
));
746 for (int i
= 0; i
< n
; i
++)
747 if (strlen(s
[i
]) == size_t(*ptr
- start
)
748 && memcmp(s
[i
], start
, *ptr
- start
) == 0)
753 void skip_possible_newline(file_case
*fcp
, FILE *outfp
)
755 int c
= fcp
->get_c();
760 int cc
= fcp
->get_c();
770 else if (c
== '\n') {
779 int resource_manager::do_begin_data(const char *ptr
, int, file_case
*fcp
,
782 while (white_space(*ptr
))
784 const char *start
= ptr
;
786 if (!read_uint_arg(&ptr
, &numberof
))
788 static const char *types
[] = { "Binary", "Hex", "ASCII" };
789 const int Binary
= 0;
791 static const char *units
[] = { "Bytes", "Lines" };
794 while (white_space(*ptr
))
797 type
= read_one_of(&ptr
, types
, 3);
799 error("bad data type");
802 while (white_space(*ptr
))
805 unit
= read_one_of(&ptr
, units
, 2);
807 error("expected `Bytes' or `Lines'");
815 fputs("%%BeginData: ", outfp
);
819 unsigned bytecount
= 0;
820 unsigned linecount
= 0;
822 int c
= fcp
->get_c();
824 error("end of file within data section");
831 int cc
= fcp
->get_c();
839 else if (c
== '\n') {
843 } while ((unit
== Bytes
? bytecount
: linecount
) < numberof
);
845 skip_possible_newline(fcp
, outfp
);
847 if (!ps_get_line(buf
, fcp
)) {
848 error("missing %%%%EndData line");
851 if (!matches_comment(buf
, "EndData"))
852 error("bad %%%%EndData line");
854 fputs(buf
.contents(), outfp
);
858 int resource_manager::do_begin_binary(const char *ptr
, int, file_case
*fcp
,
864 if (!read_uint_arg(&ptr
, &count
))
867 fprintf(outfp
, "%%%%BeginData: %u Binary Bytes\n", count
);
869 int c
= fcp
->get_c();
871 error("end of file within binary section");
878 int cc
= fcp
->get_c();
887 skip_possible_newline(fcp
, outfp
);
889 if (!ps_get_line(buf
, fcp
)) {
890 error("missing %%%%EndBinary line");
893 if (!matches_comment(buf
, "EndBinary")) {
894 error("bad %%%%EndBinary line");
896 fputs(buf
.contents(), outfp
);
899 fputs("%%EndData\n", outfp
);
903 static unsigned parse_extensions(const char *ptr
)
907 while (white_space(*ptr
))
911 const char *name
= ptr
;
914 } while (*ptr
!= '\0' && !white_space(*ptr
));
916 for (i
= 0; i
< NEXTENSIONS
; i
++)
917 if (strlen(extension_table
[i
]) == size_t(ptr
- name
)
918 && memcmp(extension_table
[i
], name
, ptr
- name
) == 0) {
922 if (i
>= NEXTENSIONS
) {
923 string
s(name
, ptr
- name
);
925 error("unknown extension `%1'", s
.contents());
931 // XXX if it has not been surrounded with {Begin,End}Document need to strip
932 // out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections.
934 // XXX Perhaps the decision whether to use BeginDocument or
935 // BeginResource: file should be postponed till we have seen
936 // the first line of the file.
938 void resource_manager::process_file(int rank
, file_case
*fcp
, FILE *outfp
)
940 // If none of these comments appear in the header section, and we are
941 // just analyzing the file (ie outfp is 0), then we can return immediately.
942 static const char *header_comment_table
[] = {
943 "DocumentNeededResources:",
944 "DocumentSuppliedResources:",
945 "DocumentNeededFonts:",
946 "DocumentSuppliedFonts:",
947 "DocumentNeededProcSets:",
948 "DocumentSuppliedProcSets:",
949 "DocumentNeededFiles:",
950 "DocumentSuppliedFiles:",
953 const int NHEADER_COMMENTS
= sizeof(header_comment_table
)
954 / sizeof(header_comment_table
[0]);
955 struct comment_info
{
957 int (resource_manager::*proc
)(const char *, int, file_case
*, FILE *);
960 static comment_info comment_table
[] = {
961 { "BeginResource:", &resource_manager::do_begin_resource
},
962 { "IncludeResource:", &resource_manager::do_include_resource
},
963 { "BeginDocument:", &resource_manager::do_begin_document
},
964 { "IncludeDocument:", &resource_manager::do_include_document
},
965 { "BeginProcSet:", &resource_manager::do_begin_procset
},
966 { "IncludeProcSet:", &resource_manager::do_include_procset
},
967 { "BeginFont:", &resource_manager::do_begin_font
},
968 { "IncludeFont:", &resource_manager::do_include_font
},
969 { "BeginFile:", &resource_manager::do_begin_file
},
970 { "IncludeFile:", &resource_manager::do_include_file
},
971 { "EndProcSet", &resource_manager::change_to_end_resource
},
972 { "EndFont", &resource_manager::change_to_end_resource
},
973 { "EndFile", &resource_manager::change_to_end_resource
},
974 { "BeginPreview:", &resource_manager::do_begin_preview
},
975 { "BeginData:", &resource_manager::do_begin_data
},
976 { "BeginBinary:", &resource_manager::do_begin_binary
},
979 const int NCOMMENTS
= sizeof(comment_table
)/sizeof(comment_table
[0]);
981 int saved_lineno
= current_lineno
;
982 const char *saved_filename
= current_filename
;
983 current_filename
= fcp
->path();
985 if (!ps_get_line(buf
, fcp
)) {
986 current_filename
= saved_filename
;
987 current_lineno
= saved_lineno
;
990 if ((size_t)buf
.length() < sizeof(PS_MAGIC
)
991 || memcmp(buf
.contents(), PS_MAGIC
, sizeof(PS_MAGIC
) - 1) != 0) {
994 if (!(broken_flags
& STRIP_PERCENT_BANG
)
995 || buf
[0] != '%' || buf
[1] != '!')
996 fputs(buf
.contents(), outfp
);
997 } while (ps_get_line(buf
, fcp
));
1001 if (!(broken_flags
& STRIP_PERCENT_BANG
) && outfp
)
1002 fputs(buf
.contents(), outfp
);
1004 int interesting
= 0;
1005 int had_extensions_comment
= 0;
1006 int had_language_level_comment
= 0;
1008 if (!ps_get_line(buf
, fcp
))
1010 int copy_this_line
= 1;
1011 if (buf
[0] == '%') {
1012 if (buf
[1] == '%') {
1015 for (i
= 0; i
< NCOMMENTS
; i
++)
1016 if ((ptr
= matches_comment(buf
, comment_table
[i
].name
))) {
1018 = (this->*(comment_table
[i
].proc
))(ptr
, rank
, fcp
, outfp
);
1021 if (i
>= NCOMMENTS
&& in_header
) {
1022 if ((ptr
= matches_comment(buf
, "EndComments")))
1024 else if (!had_extensions_comment
1025 && (ptr
= matches_comment(buf
, "Extensions:"))) {
1026 extensions
|= parse_extensions(ptr
);
1027 // XXX handle possibility that next line is %%+
1028 had_extensions_comment
= 1;
1030 else if (!had_language_level_comment
1031 && (ptr
= matches_comment(buf
, "LanguageLevel:"))) {
1033 if (read_uint_arg(&ptr
, &ll
) && ll
> language_level
)
1034 language_level
= ll
;
1035 had_language_level_comment
= 1;
1038 for (i
= 0; i
< NHEADER_COMMENTS
; i
++)
1039 if (matches_comment(buf
, header_comment_table
[i
])) {
1045 if ((broken_flags
& STRIP_STRUCTURE_COMMENTS
)
1046 && (matches_comment(buf
, "EndProlog")
1047 || matches_comment(buf
, "Page:")
1048 || matches_comment(buf
, "Trailer")))
1051 else if (buf
[1] == '!') {
1052 if (broken_flags
& STRIP_PERCENT_BANG
)
1058 if (!outfp
&& !in_header
&& !interesting
)
1060 if (copy_this_line
&& outfp
)
1061 fputs(buf
.contents(), outfp
);
1064 current_filename
= saved_filename
;
1065 current_lineno
= saved_lineno
;
1068 void resource_manager::read_download_file()
1070 file_case
*fcp
= font::open_file("download");
1072 fatal("can't find `download'");
1075 for (int lineno
= 1; fcp
->get_line(buf
, sizeof(buf
)) != NULL
; ++lineno
) {
1076 char *p
= strtok(buf
, " \t\r\n");
1077 if (p
== NULL
|| *p
== '#')
1079 char *q
= strtok(0, " \t\r\n");
1081 fatal_with_file_and_line(fcp
->path(), lineno
, "missing filename");
1082 lookup_font(p
)->filename
= strsave(q
);
1088 // XXX Can we share some code with ps_output::put_string()?
1090 static void print_ps_string(const string
&s
, FILE *outfp
)
1092 int len
= s
.length();
1093 const char *str
= s
.contents();
1098 for (int i
= 0; i
< len
; i
++)
1099 if (str
[i
] <= 040 || str
[i
] > 0176) {
1105 put_string(s
, outfp
);
1110 for (i
= 0; i
< len
; i
++)
1113 else if (str
[i
] == ')' && --level
< 0)
1116 for (i
= 0; i
< len
; i
++)
1122 putc(str
[i
], outfp
);
1125 fputs("\\\\", outfp
);
1128 fputs("\\n", outfp
);
1131 fputs("\\r", outfp
);
1134 fputs("\\t", outfp
);
1137 fputs("\\b", outfp
);
1140 fputs("\\f", outfp
);
1143 if (str
[i
] < 040 || str
[i
] > 0176)
1144 fprintf(outfp
, "\\%03o", str
[i
] & 0377);
1146 putc(str
[i
], outfp
);
1152 void resource_manager::print_extensions_comment(FILE *outfp
)
1155 fputs("%%Extensions:", outfp
);
1156 for (int i
= 0; i
< NEXTENSIONS
; i
++)
1157 if (extensions
& (1 << i
)) {
1159 fputs(extension_table
[i
], outfp
);
1165 void resource_manager::print_language_level_comment(FILE *outfp
)
1168 fprintf(outfp
, "%%%%LanguageLevel: %u\n", language_level
);