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 "stringclass.h"
28 #ifdef NEED_DECLARATION_PUTENV
30 int putenv(const char *);
32 #endif /* NEED_DECLARATION_PUTENV */
34 #define GROPS_PROLOGUE "prologue"
36 static void print_ps_string(const string &s, FILE *outfp);
38 cset white_space("\n\r \t\f");
39 string an_empty_string;
41 char valid_input_table[256]= {
42 #ifndef IS_EBCDIC_HOST
43 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
45 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 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, 0,
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, 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,
61 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
62 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
65 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
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,
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, 0,
81 const char *extension_table[] = {
88 const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]);
90 const char *resource_table[] = {
99 const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]);
101 static int read_uint_arg(const char **pp, unsigned *res)
103 while (white_space(**pp))
106 error("missing argument");
109 const char *start = *pp;
111 long n = strtol(start, (char **)pp, 10);
112 if (n == 0 && *pp == start) {
113 error("not an integer");
117 error("argument must not be negative");
128 enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 };
134 resource(resource_type, string &, string & = an_empty_string, unsigned = 0);
136 void print_type_and_name(FILE *outfp);
139 resource::resource(resource_type t, string &n, string &v, unsigned r)
140 : next(0), type(t), flags(0), revision(r), filename(0), rank(-1)
144 if (type == RESOURCE_FILE) {
145 if (name.search('\0') >= 0)
146 error("filename contains a character with code 0");
147 filename = name.extract();
151 resource::~resource()
156 void resource::print_type_and_name(FILE *outfp)
158 fputs(resource_table[type], outfp);
160 print_ps_string(name, outfp);
161 if (type == RESOURCE_PROCSET) {
163 print_ps_string(version, outfp);
164 fprintf(outfp, " %u", revision);
168 resource_manager::resource_manager()
169 : extensions(0), language_level(0), resource_list(0)
171 read_download_file();
172 string procset_name("grops");
173 extern const char *version_string;
174 extern const char *revision_string;
175 unsigned revision_uint;
176 if (!read_uint_arg(&revision_string, &revision_uint))
178 string procset_version(version_string);
179 procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name,
180 procset_version, revision_uint);
181 procset_resource->flags |= resource::SUPPLIED;
184 resource_manager::~resource_manager()
186 while (resource_list) {
187 resource *tem = resource_list;
188 resource_list = resource_list->next;
193 resource *resource_manager::lookup_resource(resource_type type,
199 for (r = resource_list; r; r = r->next)
202 && r->version == version
203 && r->revision == revision)
205 r = new resource(type, name, version, revision);
206 r->next = resource_list;
211 // Just a specialized version of lookup_resource().
213 resource *resource_manager::lookup_font(const char *name)
216 for (r = resource_list; r; r = r->next)
217 if (r->type == RESOURCE_FONT
218 && strlen(name) == (size_t)r->name.length()
219 && memcmp(name, r->name.contents(), r->name.length()) == 0)
222 r = new resource(RESOURCE_FONT, s);
223 r->next = resource_list;
228 void resource_manager::need_font(const char *name)
230 lookup_font(name)->flags |= resource::FONT_NEEDED;
233 typedef resource *Presource; // Work around g++ bug.
235 void resource_manager::document_setup(ps_output &out)
239 for (r = resource_list; r; r = r->next)
240 if (r->rank >= nranks)
241 nranks = r->rank + 1;
243 // Sort resource_list in reverse order of rank.
244 Presource *head = new Presource[nranks + 1];
245 Presource **tail = new Presource *[nranks + 1];
247 for (i = 0; i < nranks + 1; i++) {
251 for (r = resource_list; r; r = r->next) {
252 i = r->rank < 0 ? 0 : r->rank + 1;
254 tail[i] = &(*tail[i])->next;
257 for (i = 0; i < nranks + 1; i++)
259 *tail[i] = resource_list;
260 resource_list = head[i];
265 for (r = resource_list; r; r = r->next)
267 assert(r->rank >= r->next->rank);
268 for (r = resource_list; r; r = r->next)
269 if (r->type == RESOURCE_FONT && r->rank >= 0)
270 supply_resource(r, -1, out.get_file());
274 void resource_manager::print_resources_comment(unsigned flag, FILE *outfp)
277 for (resource *r = resource_list; r; r = r->next)
278 if (r->flags & flag) {
280 fputs("%%+ ", outfp);
282 fputs(flag == resource::NEEDED
283 ? "%%DocumentNeededResources: "
284 : "%%DocumentSuppliedResources: ",
288 r->print_type_and_name(outfp);
293 void resource_manager::print_header_comments(ps_output &out)
295 for (resource *r = resource_list; r; r = r->next)
296 if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED))
297 supply_resource(r, 0, 0);
298 print_resources_comment(resource::NEEDED, out.get_file());
299 print_resources_comment(resource::SUPPLIED, out.get_file());
300 print_language_level_comment(out.get_file());
301 print_extensions_comment(out.get_file());
304 void resource_manager::output_prolog(ps_output &out)
306 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");
318 FILE *fp = font::open_file(prologue, &path);
320 fatal("can't find `%1'", prologue);
321 fputs("%%BeginResource: ", outfp);
322 procset_resource->print_type_and_name(outfp);
324 process_file(-1, fp, path, outfp);
327 fputs("%%EndResource\n", outfp);
330 void resource_manager::import_file(const char *filename, ps_output &out)
333 string name(filename);
334 resource *r = lookup_resource(RESOURCE_FILE, name);
335 supply_resource(r, -1, out.get_file(), 1);
338 void resource_manager::supply_resource(resource *r, int rank, FILE *outfp,
341 if (r->flags & resource::BUSY) {
343 fatal("loop detected in dependency graph for %1 `%2'",
344 resource_table[r->type],
347 r->flags |= resource::BUSY;
350 char *path = 0; // pacify compiler
352 if (r->filename != 0) {
353 if (r->type == RESOURCE_FONT) {
354 fp = font::open_file(r->filename, &path);
356 error("can't find `%1'", r->filename);
357 a_delete r->filename;
363 fp = include_search_path.open_file_cautious(r->filename);
365 error("can't open `%1': %2", r->filename, strerror(errno));
366 a_delete r->filename;
375 if (r->type == RESOURCE_FILE && is_document) {
376 fputs("%%BeginDocument: ", outfp);
377 print_ps_string(r->name, outfp);
381 fputs("%%BeginResource: ", outfp);
382 r->print_type_and_name(outfp);
386 process_file(rank, fp, path, outfp);
388 if (r->type == RESOURCE_FONT)
391 if (r->type == RESOURCE_FILE && is_document)
392 fputs("%%EndDocument\n", outfp);
394 fputs("%%EndResource\n", outfp);
396 r->flags |= resource::SUPPLIED;
400 if (r->type == RESOURCE_FILE && is_document) {
401 fputs("%%IncludeDocument: ", outfp);
402 print_ps_string(r->name, outfp);
406 fputs("%%IncludeResource: ", outfp);
407 r->print_type_and_name(outfp);
411 r->flags |= resource::NEEDED;
413 r->flags &= ~resource::BUSY;
416 #define PS_MAGIC "%!PS-Adobe-"
418 static int ps_get_line(string &buf, FILE *fp)
425 while (c != '\r' && c != '\n' && c != EOF) {
426 if (!valid_input_table[c])
427 error("invalid input character code %1", int(c));
435 if (c != EOF && c != '\n')
441 static int read_text_arg(const char **pp, string &res)
444 while (white_space(**pp))
447 error("missing argument");
451 for (; **pp != '\0' && !white_space(**pp); *pp += 1)
459 if (**pp == '\0' || **pp == '\r' || **pp == '\n') {
460 error("missing ')'");
471 else if (**pp == '(') {
475 else if (**pp == '\\') {
502 int val = **pp - '0';
503 if ((*pp)[1] >= '0' && (*pp)[1] <= '7') {
505 val = val*8 + (**pp - '0');
506 if ((*pp)[1] >= '0' && (*pp)[1] <= '7') {
508 val = val*8 + (**pp - '0');
525 resource *resource_manager::read_file_arg(const char **ptr)
528 if (!read_text_arg(ptr, arg))
530 return lookup_resource(RESOURCE_FILE, arg);
533 resource *resource_manager::read_font_arg(const char **ptr)
536 if (!read_text_arg(ptr, arg))
538 return lookup_resource(RESOURCE_FONT, arg);
541 resource *resource_manager::read_procset_arg(const char **ptr)
544 if (!read_text_arg(ptr, arg))
547 if (!read_text_arg(ptr, version))
550 if (!read_uint_arg(ptr, &revision))
552 return lookup_resource(RESOURCE_PROCSET, arg, version, revision);
555 resource *resource_manager::read_resource_arg(const char **ptr)
557 while (white_space(**ptr))
559 const char *name = *ptr;
560 while (**ptr != '\0' && !white_space(**ptr))
563 error("missing resource type");
567 for (ri = 0; ri < NRESOURCES; ri++)
568 if (strlen(resource_table[ri]) == size_t(*ptr - name)
569 && memcmp(resource_table[ri], name, *ptr - name) == 0)
571 if (ri >= NRESOURCES) {
572 error("unknown resource type");
575 if (ri == RESOURCE_PROCSET)
576 return read_procset_arg(ptr);
578 if (!read_text_arg(ptr, arg))
580 return lookup_resource(resource_type(ri), arg);
583 static const char *matches_comment(string &buf, const char *comment)
585 if ((size_t)buf.length() < strlen(comment) + 3)
587 if (buf[0] != '%' || buf[1] != '%')
589 const char *bufp = buf.contents() + 2;
590 for (; *comment; comment++, bufp++)
591 if (*bufp != *comment)
593 if (comment[-1] == ':')
595 if (*bufp == '\0' || white_space(*bufp))
600 // Return 1 if the line should be copied out.
602 int resource_manager::do_begin_resource(const char *ptr, int, FILE *,
605 resource *r = read_resource_arg(&ptr);
607 r->flags |= resource::SUPPLIED;
611 int resource_manager::do_include_resource(const char *ptr, int rank, FILE *,
614 resource *r = read_resource_arg(&ptr);
616 if (r->type == RESOURCE_FONT) {
618 supply_resource(r, rank + 1, outfp);
620 r->flags |= resource::FONT_NEEDED;
623 supply_resource(r, rank, outfp);
628 int resource_manager::do_begin_document(const char *ptr, int, FILE *,
631 resource *r = read_file_arg(&ptr);
633 r->flags |= resource::SUPPLIED;
637 int resource_manager::do_include_document(const char *ptr, int rank, FILE *,
640 resource *r = read_file_arg(&ptr);
642 supply_resource(r, rank, outfp, 1);
646 int resource_manager::do_begin_procset(const char *ptr, int, FILE *,
649 resource *r = read_procset_arg(&ptr);
651 r->flags |= resource::SUPPLIED;
653 fputs("%%BeginResource: ", outfp);
654 r->print_type_and_name(outfp);
661 int resource_manager::do_include_procset(const char *ptr, int rank, FILE *,
664 resource *r = read_procset_arg(&ptr);
666 supply_resource(r, rank, outfp);
670 int resource_manager::do_begin_file(const char *ptr, int, FILE *,
673 resource *r = read_file_arg(&ptr);
675 r->flags |= resource::SUPPLIED;
677 fputs("%%BeginResource: ", outfp);
678 r->print_type_and_name(outfp);
685 int resource_manager::do_include_file(const char *ptr, int rank, FILE *,
688 resource *r = read_file_arg(&ptr);
690 supply_resource(r, rank, outfp);
694 int resource_manager::do_begin_font(const char *ptr, int, FILE *,
697 resource *r = read_font_arg(&ptr);
699 r->flags |= resource::SUPPLIED;
701 fputs("%%BeginResource: ", outfp);
702 r->print_type_and_name(outfp);
709 int resource_manager::do_include_font(const char *ptr, int rank, FILE *,
712 resource *r = read_font_arg(&ptr);
715 supply_resource(r, rank + 1, outfp);
717 r->flags |= resource::FONT_NEEDED;
722 int resource_manager::change_to_end_resource(const char *, int, FILE *,
726 fputs("%%EndResource\n", outfp);
730 int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *)
734 if (!ps_get_line(buf, fp)) {
735 error("end of file in preview section");
738 } while (!matches_comment(buf, "EndPreview"));
742 int read_one_of(const char **ptr, const char **s, int n)
744 while (white_space(**ptr))
748 const char *start = *ptr;
751 } while (**ptr != '\0' && !white_space(**ptr));
752 for (int i = 0; i < n; i++)
753 if (strlen(s[i]) == size_t(*ptr - start)
754 && memcmp(s[i], start, *ptr - start) == 0)
759 void skip_possible_newline(FILE *fp, FILE *outfp)
776 else if (c == '\n') {
785 int resource_manager::do_begin_data(const char *ptr, int, FILE *fp,
788 while (white_space(*ptr))
790 const char *start = ptr;
792 if (!read_uint_arg(&ptr, &numberof))
794 static const char *types[] = { "Binary", "Hex", "ASCII" };
795 const int Binary = 0;
797 static const char *units[] = { "Bytes", "Lines" };
800 while (white_space(*ptr))
803 type = read_one_of(&ptr, types, 3);
805 error("bad data type");
808 while (white_space(*ptr))
811 unit = read_one_of(&ptr, units, 2);
813 error("expected `Bytes' or `Lines'");
821 fputs("%%BeginData: ", outfp);
825 unsigned bytecount = 0;
826 unsigned linecount = 0;
830 error("end of file within data section");
845 else if (c == '\n') {
849 } while ((unit == Bytes ? bytecount : linecount) < numberof);
851 skip_possible_newline(fp, outfp);
853 if (!ps_get_line(buf, fp)) {
854 error("missing %%%%EndData line");
857 if (!matches_comment(buf, "EndData"))
858 error("bad %%%%EndData line");
860 fputs(buf.contents(), outfp);
864 int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp,
870 if (!read_uint_arg(&ptr, &count))
873 fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count);
877 error("end of file within binary section");
893 skip_possible_newline(fp, outfp);
895 if (!ps_get_line(buf, fp)) {
896 error("missing %%%%EndBinary line");
899 if (!matches_comment(buf, "EndBinary")) {
900 error("bad %%%%EndBinary line");
902 fputs(buf.contents(), outfp);
905 fputs("%%EndData\n", outfp);
909 static unsigned parse_extensions(const char *ptr)
913 while (white_space(*ptr))
917 const char *name = ptr;
920 } while (*ptr != '\0' && !white_space(*ptr));
922 for (i = 0; i < NEXTENSIONS; i++)
923 if (strlen(extension_table[i]) == size_t(ptr - name)
924 && memcmp(extension_table[i], name, ptr - name) == 0) {
928 if (i >= NEXTENSIONS) {
929 string s(name, ptr - name);
931 error("unknown extension `%1'", s.contents());
937 // XXX if it has not been surrounded with {Begin,End}Document need to strip
938 // out Page: Trailer {Begin,End}Prolog {Begin,End}Setup sections.
940 // XXX Perhaps the decision whether to use BeginDocument or
941 // BeginResource: file should be postponed till we have seen
942 // the first line of the file.
944 void resource_manager::process_file(int rank, FILE *fp, const char *filename,
947 // If none of these comments appear in the header section, and we are
948 // just analyzing the file (ie outfp is 0), then we can return immediately.
949 static const char *header_comment_table[] = {
950 "DocumentNeededResources:",
951 "DocumentSuppliedResources:",
952 "DocumentNeededFonts:",
953 "DocumentSuppliedFonts:",
954 "DocumentNeededProcSets:",
955 "DocumentSuppliedProcSets:",
956 "DocumentNeededFiles:",
957 "DocumentSuppliedFiles:",
960 const int NHEADER_COMMENTS = sizeof(header_comment_table)
961 / sizeof(header_comment_table[0]);
962 struct comment_info {
964 int (resource_manager::*proc)(const char *, int, FILE *, FILE *);
967 static comment_info comment_table[] = {
968 { "BeginResource:", &resource_manager::do_begin_resource },
969 { "IncludeResource:", &resource_manager::do_include_resource },
970 { "BeginDocument:", &resource_manager::do_begin_document },
971 { "IncludeDocument:", &resource_manager::do_include_document },
972 { "BeginProcSet:", &resource_manager::do_begin_procset },
973 { "IncludeProcSet:", &resource_manager::do_include_procset },
974 { "BeginFont:", &resource_manager::do_begin_font },
975 { "IncludeFont:", &resource_manager::do_include_font },
976 { "BeginFile:", &resource_manager::do_begin_file },
977 { "IncludeFile:", &resource_manager::do_include_file },
978 { "EndProcSet", &resource_manager::change_to_end_resource },
979 { "EndFont", &resource_manager::change_to_end_resource },
980 { "EndFile", &resource_manager::change_to_end_resource },
981 { "BeginPreview:", &resource_manager::do_begin_preview },
982 { "BeginData:", &resource_manager::do_begin_data },
983 { "BeginBinary:", &resource_manager::do_begin_binary },
986 const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]);
988 int saved_lineno = current_lineno;
989 const char *saved_filename = current_filename;
990 current_filename = filename;
992 if (!ps_get_line(buf, fp)) {
993 current_filename = saved_filename;
994 current_lineno = saved_lineno;
997 if ((size_t)buf.length() < sizeof(PS_MAGIC)
998 || memcmp(buf.contents(), PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) {
1001 if (!(broken_flags & STRIP_PERCENT_BANG)
1002 || buf[0] != '%' || buf[1] != '!')
1003 fputs(buf.contents(), outfp);
1004 } while (ps_get_line(buf, fp));
1008 if (!(broken_flags & STRIP_PERCENT_BANG) && outfp)
1009 fputs(buf.contents(), outfp);
1011 int interesting = 0;
1012 int had_extensions_comment = 0;
1013 int had_language_level_comment = 0;
1015 if (!ps_get_line(buf, fp))
1017 int copy_this_line = 1;
1018 if (buf[0] == '%') {
1019 if (buf[1] == '%') {
1022 for (i = 0; i < NCOMMENTS; i++)
1023 if ((ptr = matches_comment(buf, comment_table[i].name))) {
1025 = (this->*(comment_table[i].proc))(ptr, rank, fp, outfp);
1028 if (i >= NCOMMENTS && in_header) {
1029 if ((ptr = matches_comment(buf, "EndComments")))
1031 else if (!had_extensions_comment
1032 && (ptr = matches_comment(buf, "Extensions:"))) {
1033 extensions |= parse_extensions(ptr);
1034 // XXX handle possibility that next line is %%+
1035 had_extensions_comment = 1;
1037 else if (!had_language_level_comment
1038 && (ptr = matches_comment(buf, "LanguageLevel:"))) {
1040 if (read_uint_arg(&ptr, &ll) && ll > language_level)
1041 language_level = ll;
1042 had_language_level_comment = 1;
1045 for (i = 0; i < NHEADER_COMMENTS; i++)
1046 if (matches_comment(buf, header_comment_table[i])) {
1052 if ((broken_flags & STRIP_STRUCTURE_COMMENTS)
1053 && (matches_comment(buf, "EndProlog")
1054 || matches_comment(buf, "Page:")
1055 || matches_comment(buf, "Trailer")))
1058 else if (buf[1] == '!') {
1059 if (broken_flags & STRIP_PERCENT_BANG)
1065 if (!outfp && !in_header && !interesting)
1067 if (copy_this_line && outfp)
1068 fputs(buf.contents(), outfp);
1071 current_filename = saved_filename;
1072 current_lineno = saved_lineno;
1075 void resource_manager::read_download_file()
1078 FILE *fp = font::open_file("download", &path);
1080 fatal("can't find `download'");
1083 while (fgets(buf, sizeof(buf), fp)) {
1085 char *p = strtok(buf, " \t\r\n");
1086 if (p == 0 || *p == '#')
1088 char *q = strtok(0, " \t\r\n");
1090 fatal_with_file_and_line(path, lineno, "missing filename");
1091 lookup_font(p)->filename = strsave(q);
1097 // XXX Can we share some code with ps_output::put_string()?
1099 static void print_ps_string(const string &s, FILE *outfp)
1101 int len = s.length();
1102 const char *str = s.contents();
1107 for (int i = 0; i < len; i++)
1108 if (str[i] <= 040 || str[i] > 0176) {
1114 put_string(s, outfp);
1119 for (i = 0; i < len; i++)
1122 else if (str[i] == ')' && --level < 0)
1125 for (i = 0; i < len; i++)
1131 putc(str[i], outfp);
1134 fputs("\\\\", outfp);
1137 fputs("\\n", outfp);
1140 fputs("\\r", outfp);
1143 fputs("\\t", outfp);
1146 fputs("\\b", outfp);
1149 fputs("\\f", outfp);
1152 if (str[i] < 040 || str[i] > 0176)
1153 fprintf(outfp, "\\%03o", str[i] & 0377);
1155 putc(str[i], outfp);
1161 void resource_manager::print_extensions_comment(FILE *outfp)
1164 fputs("%%Extensions:", outfp);
1165 for (int i = 0; i < NEXTENSIONS; i++)
1166 if (extensions & (1 << i)) {
1168 fputs(extension_table[i], outfp);
1174 void resource_manager::print_language_level_comment(FILE *outfp)
1177 fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level);