📄 psrm.cc
字号:
// -*- C++ -*-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com)This file is part of groff.groff is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING. If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "driver.h"#include "stringclass.h"#include "cset.h"#include "ps.h"#define PROLOGUE "prologue"static void print_ps_string(const string &s, FILE *outfp);cset white_space("\n\r \t");string an_empty_string;const char *extension_table[] = { "DPS", "CMYK", "Composite", "FileSystem",};const int NEXTENSIONS = sizeof(extension_table)/sizeof(extension_table[0]);const char *resource_table[] = { "font", "procset", "file", "encoding", "form", "pattern",};const int NRESOURCES = sizeof(resource_table)/sizeof(resource_table[0]);struct resource { resource *next; resource_type type; string name; enum { NEEDED = 01, SUPPLIED = 02, FONT_NEEDED = 04, BUSY = 010 }; unsigned flags; string version; unsigned revision; char *filename; int rank; resource(resource_type, string &, string & = an_empty_string, unsigned = 0); ~resource(); void print_type_and_name(FILE *outfp);};resource::resource(resource_type t, string &n, string &v, unsigned r): type(t), revision(r), flags (0), filename(0), rank(-1), next(0){ name.move(n); version.move(v); if (type == RESOURCE_FILE) { if (name.search('\0') >= 0) error("filename contains a character with code 0"); filename = name.extract(); }}resource::~resource(){ a_delete filename;}void resource::print_type_and_name(FILE *outfp){ fputs(resource_table[type], outfp); putc(' ', outfp); print_ps_string(name, outfp); if (type == RESOURCE_PROCSET) { putc(' ', outfp); print_ps_string(version, outfp); fprintf(outfp, " %u", revision); }}resource_manager::resource_manager(): resource_list(0), extensions(0), language_level(0){ read_download_file(); string procset_name("grops"); extern const char *version_string; string procset_version(version_string); procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name, procset_version, 0); procset_resource->flags |= resource::SUPPLIED;}resource_manager::~resource_manager(){ while (resource_list) { resource *tem = resource_list; resource_list = resource_list->next; delete tem; }}resource *resource_manager::lookup_resource(resource_type type, string &name, string &version, unsigned revision){ for (resource *r = resource_list; r; r = r->next) if (r->type == type && r->name == name && r->version == version && r->revision == revision) return r; r = new resource(type, name, version, revision); r->next = resource_list; resource_list = r; return r;}// Just a specialized version of lookup_resource().resource *resource_manager::lookup_font(const char *name){ for (resource *r = resource_list; r; r = r->next) if (r->type == RESOURCE_FONT && strlen(name) == r->name.length() && memcmp(name, r->name.contents(), r->name.length()) == 0) return r; string s(name); r = new resource(RESOURCE_FONT, s); r->next = resource_list; resource_list = r; return r;}void resource_manager::need_font(const char *name){ lookup_font(name)->flags |= resource::FONT_NEEDED;}typedef resource *Presource; // Work around g++ bug.void resource_manager::document_setup(ps_output &out){ int nranks = 0; for (resource *r = resource_list; r; r = r->next) if (r->rank >= nranks) nranks = r->rank + 1; if (nranks > 0) { // Sort resource_list in reverse order of rank. Presource *head = new Presource[nranks + 1]; Presource **tail = new Presource *[nranks + 1]; for (int i = 0; i < nranks + 1; i++) { head[i] = 0; tail[i] = &head[i]; } for (r = resource_list; r; r = r->next) { i = r->rank < 0 ? 0 : r->rank + 1; *tail[i] = r; tail[i] = &(*tail[i])->next; } resource_list = 0; for (i = 0; i < nranks + 1; i++) if (head[i]) { *tail[i] = resource_list; resource_list = head[i]; } a_delete head; a_delete tail; // check it for (r = resource_list; r; r = r->next) if (r->next) assert(r->rank >= r->next->rank); for (r = resource_list; r; r = r->next) if (r->type == RESOURCE_FONT && r->rank >= 0) supply_resource(r, -1, out.get_file()); }}void resource_manager::print_resources_comment(unsigned flag, FILE *outfp){ int continued = 0; for (resource *r = resource_list; r; r = r->next) if (r->flags & flag) { if (continued) fputs("%%+ ", outfp); else { fputs(flag == resource::NEEDED ? "%%DocumentNeededResources: " : "%%DocumentSuppliedResources: ", outfp); continued = 1; } r->print_type_and_name(outfp); putc('\n', outfp); }}void resource_manager::print_header_comments(ps_output &out){ for (resource *r = resource_list; r; r = r->next) if (r->type == RESOURCE_FONT && (r->flags & resource::FONT_NEEDED)) supply_resource(r, 0, 0); print_resources_comment(resource::NEEDED, out.get_file()); print_resources_comment(resource::SUPPLIED, out.get_file()); print_language_level_comment(out.get_file()); print_extensions_comment(out.get_file());}void resource_manager::output_prolog(ps_output &out){ FILE *outfp = out.get_file(); out.end_line(); char *path; FILE *fp = font::open_file(PROLOGUE, &path); if (!fp) fatal("can't find `%1'", PROLOGUE); fputs("%%BeginResource: ", outfp); procset_resource->print_type_and_name(outfp); putc('\n', outfp); process_file(-1, fp, path, outfp); fclose(fp); a_delete path; fputs("%%EndResource\n", outfp);}void resource_manager::import_file(const char *filename, ps_output &out){ out.end_line(); string name(filename); resource *r = lookup_resource(RESOURCE_FILE, name); supply_resource(r, -1, out.get_file(), 1);}void resource_manager::supply_resource(resource *r, int rank, FILE *outfp, int is_document){ if (r->flags & resource::BUSY) { r->name += '\0'; fatal("loop detected in dependency graph for %1 `%2'", resource_table[r->type], r->name.contents()); } r->flags |= resource::BUSY; if (rank > r->rank) r->rank = rank; char *path; FILE *fp = 0; if (r->filename != 0) { if (r->type == RESOURCE_FONT) { fp = font::open_file(r->filename, &path); if (!fp) { error("can't find `%1'", r->filename); a_delete r->filename; r->filename = 0; } } else { errno = 0; fp = fopen(r->filename, "r"); if (!fp) { error("can't open `%1': %2", r->filename, strerror(errno)); a_delete r->filename; r->filename = 0; } else path = r->filename; } } if (fp) { if (outfp) { if (r->type == RESOURCE_FILE && is_document) { fputs("%%BeginDocument: ", outfp); print_ps_string(r->name, outfp); putc('\n', outfp); } else { fputs("%%BeginResource: ", outfp); r->print_type_and_name(outfp); putc('\n', outfp); } } process_file(rank, fp, path, outfp); fclose(fp); if (r->type == RESOURCE_FONT) a_delete path; if (outfp) { if (r->type == RESOURCE_FILE && is_document) fputs("%%EndDocument\n", outfp); else fputs("%%EndResource\n", outfp); } r->flags |= resource::SUPPLIED; } else { if (outfp) { if (r->type == RESOURCE_FILE && is_document) { fputs("%%IncludeDocument: ", outfp); print_ps_string(r->name, outfp); putc('\n', outfp); } else { fputs("%%IncludeResource: ", outfp); r->print_type_and_name(outfp); putc('\n', outfp); } } r->flags |= resource::NEEDED; } r->flags &= ~resource::BUSY;}#define PS_LINE_MAX 255#define PS_MAGIC "%!PS-Adobe-"static int ps_get_line(char *buf, FILE *fp){ int c = getc(fp); if (c == EOF) { buf[0] = '\0'; return 0; } current_lineno++; int i = 0; int err = 0; while (c != '\r' && c != '\n' && c != EOF) { if ((c < 0x1b && !white_space(c)) || c == 0x7f) error("illegal input character code %1", int(c)); else if (i < PS_LINE_MAX) buf[i++] = c; else if (!err) { err = 1; error("PostScript file non-conforming " "because length of line exceeds 255"); } c = getc(fp); } buf[i++] = '\n'; buf[i] = '\0'; if (c == '\r') { c = getc(fp); if (c != EOF && c != '\n') ungetc(c, fp); } return 1;}static int read_text_arg(const char **pp, string &res){ res.clear(); while (white_space(**pp)) *pp += 1; if (**pp == '\0') { error("missing argument"); return 0; } if (**pp != '(') { for (; **pp != '\0' && !white_space(**pp); *pp += 1) res += **pp; return 1; } *pp += 1; res.clear(); int level = 0; for (;;) { if (**pp == '\0' || **pp == '\r' || **pp == '\n') { error("missing ')'"); return 0; } if (**pp == ')') { if (level == 0) { *pp += 1; break; } res += **pp; level--; } else if (**pp == '(') { level++; res += **pp; } else if (**pp == '\\') { *pp += 1; switch (**pp) { case 'n': res += '\n'; break; case 'r': res += '\n'; break; case 't': res += '\t'; break; case 'b': res += '\b'; break; case 'f': res += '\f'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int val = **pp - '0'; if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { *pp += 1; val = val*8 + (**pp - '0'); if ((*pp)[1] >= '0' && (*pp)[1] <= '7') { *pp += 1; val = val*8 + (**pp - '0'); } } } break; default: res += **pp; break; } } else res += **pp; *pp += 1; } return 1;}static int read_uint_arg(const char **pp, unsigned *res){ while (white_space(**pp)) *pp += 1; if (**pp == '\0') { error("missing argument"); return 0; } const char *start = *pp; // XXX use strtoul long n = strtol(start, (char **)pp, 10); if (n == 0 && *pp == start) { error("not an integer"); return 0; } if (n < 0) { error("argument must not be negative"); return 0; } *res = unsigned(n); return 1;}resource *resource_manager::read_file_arg(const char **ptr){ string arg; if (!read_text_arg(ptr, arg)) return 0; return lookup_resource(RESOURCE_FILE, arg);}resource *resource_manager::read_font_arg(const char **ptr){ string arg; if (!read_text_arg(ptr, arg)) return 0; return lookup_resource(RESOURCE_FONT, arg);}resource *resource_manager::read_procset_arg(const char **ptr){ string arg; if (!read_text_arg(ptr, arg)) return 0; string version; if (!read_text_arg(ptr, version)) return 0; unsigned revision; if (!read_uint_arg(ptr, &revision)) return 0; return lookup_resource(RESOURCE_PROCSET, arg, version, revision);}resource *resource_manager::read_resource_arg(const char **ptr){ while (white_space(**ptr)) *ptr += 1; const char *name = *ptr; while (**ptr != '\0' && !white_space(**ptr)) *ptr += 1; if (name == *ptr) { error("missing resource type"); return 0; } for (int ri = 0; ri < NRESOURCES; ri++) if (strlen(resource_table[ri]) == *ptr - name && memcmp(resource_table[ri], name, *ptr - name) == 0) break; if (ri >= NRESOURCES) { error("unknown resource type"); return 0; } if (ri == RESOURCE_PROCSET) return read_procset_arg(ptr); string arg; if (!read_text_arg(ptr, arg)) return 0; return lookup_resource(resource_type(ri), arg);}static const char *matches_comment(const char *buf, const char *comment){ if (buf[0] != '%' || buf[1] != '%') return 0; for (buf += 2; *comment; comment++, buf++) if (*buf != *comment) return 0; if (comment[-1] == ':') return buf; if (*buf == '\0' || white_space(*buf)) return buf; return 0;}// Return 1 if the line should be copied out.int resource_manager::do_begin_resource(const char *ptr, int, FILE *, FILE *)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -