#include "driver.h"
#include "stringclass.h"
#include "cset.h"
#include "ps.h"
#ifdef NEED_DECLARATION_PUTENV
extern "C" {
int putenv(const char *);
}
#endif
#define GROPS_PROLOGUE "prologue"
static void print_ps_string(const string &s, FILE *outfp);
cset white_space("\n\r \t\f");
string an_empty_string;
char valid_input_table[256]= {
#ifndef IS_EBCDIC_HOST
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
#else
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
#endif
};
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]);
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;
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;
}
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)
: next(0), type(t), flags(0), revision(r), filename(0), rank(-1)
{
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()
: extensions(0), language_level(0), resource_list(0)
{
read_download_file();
string procset_name("grops");
extern const char *version_string;
extern const char *revision_string;
unsigned revision_uint;
if (!read_uint_arg(&revision_string, &revision_uint))
revision_uint = 0;
string procset_version(version_string);
procset_resource = lookup_resource(RESOURCE_PROCSET, procset_name,
procset_version, revision_uint);
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)
{
resource *r;
for (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;
}
resource *resource_manager::lookup_font(const char *name)
{
resource *r;
for (r = resource_list; r; r = r->next)
if (r->type == RESOURCE_FONT
&& strlen(name) == (size_t)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;
void resource_manager::document_setup(ps_output &out)
{
int nranks = 0;
resource *r;
for (r = resource_list; r; r = r->next)
if (r->rank >= nranks)
nranks = r->rank + 1;
if (nranks > 0) {
Presource *head = new Presource[nranks + 1];
Presource **tail = new Presource *[nranks + 1];
int i;
for (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;
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;
if (!getenv("GROPS_PROLOGUE")) {
string e = "GROPS_PROLOGUE";
e += '=';
e += GROPS_PROLOGUE;
e += '\0';
if (putenv(strsave(e.contents())))
fatal("putenv failed");
}
char *prologue = getenv("GROPS_PROLOGUE");
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 = 0; 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 = include_search_path.open_file_cautious(r->filename);
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_MAGIC "%!PS-Adobe-"
static int ps_get_line(string &buf, FILE *fp)
{
buf.clear();
int c = getc(fp);
if (c == EOF)
return 0;
current_lineno++;
while (c != '\r' && c != '\n' && c != EOF) {
if (!valid_input_table[c])
error("invalid input character code %1", int(c));
buf += c;
c = getc(fp);
}
buf += '\n';
buf += '\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;
}
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;
}
int ri;
for (ri = 0; ri < NRESOURCES; ri++)
if (strlen(resource_table[ri]) == size_t(*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(string &buf, const char *comment)
{
if ((size_t)buf.length() < strlen(comment) + 3)
return 0;
if (buf[0] != '%' || buf[1] != '%')
return 0;
const char *bufp = buf.contents() + 2;
for (; *comment; comment++, bufp++)
if (*bufp != *comment)
return 0;
if (comment[-1] == ':')
return bufp;
if (*bufp == '\0' || white_space(*bufp))
return bufp;
return 0;
}
int resource_manager::do_begin_resource(const char *ptr, int, FILE *,
FILE *)
{
resource *r = read_resource_arg(&ptr);
if (r)
r->flags |= resource::SUPPLIED;
return 1;
}
int resource_manager::do_include_resource(const char *ptr, int rank, FILE *,
FILE *outfp)
{
resource *r = read_resource_arg(&ptr);
if (r) {
if (r->type == RESOURCE_FONT) {
if (rank >= 0)
supply_resource(r, rank + 1, outfp);
else
r->flags |= resource::FONT_NEEDED;
}
else
supply_resource(r, rank, outfp);
}
return 0;
}
int resource_manager::do_begin_document(const char *ptr, int, FILE *,
FILE *)
{
resource *r = read_file_arg(&ptr);
if (r)
r->flags |= resource::SUPPLIED;
return 1;
}
int resource_manager::do_include_document(const char *ptr, int rank, FILE *,
FILE *outfp)
{
resource *r = read_file_arg(&ptr);
if (r)
supply_resource(r, rank, outfp, 1);
return 0;
}
int resource_manager::do_begin_procset(const char *ptr, int, FILE *,
FILE *outfp)
{
resource *r = read_procset_arg(&ptr);
if (r) {
r->flags |= resource::SUPPLIED;
if (outfp) {
fputs("%%BeginResource: ", outfp);
r->print_type_and_name(outfp);
putc('\n', outfp);
}
}
return 0;
}
int resource_manager::do_include_procset(const char *ptr, int rank, FILE *,
FILE *outfp)
{
resource *r = read_procset_arg(&ptr);
if (r)
supply_resource(r, rank, outfp);
return 0;
}
int resource_manager::do_begin_file(const char *ptr, int, FILE *,
FILE *outfp)
{
resource *r = read_file_arg(&ptr);
if (r) {
r->flags |= resource::SUPPLIED;
if (outfp) {
fputs("%%BeginResource: ", outfp);
r->print_type_and_name(outfp);
putc('\n', outfp);
}
}
return 0;
}
int resource_manager::do_include_file(const char *ptr, int rank, FILE *,
FILE *outfp)
{
resource *r = read_file_arg(&ptr);
if (r)
supply_resource(r, rank, outfp);
return 0;
}
int resource_manager::do_begin_font(const char *ptr, int, FILE *,
FILE *outfp)
{
resource *r = read_font_arg(&ptr);
if (r) {
r->flags |= resource::SUPPLIED;
if (outfp) {
fputs("%%BeginResource: ", outfp);
r->print_type_and_name(outfp);
putc('\n', outfp);
}
}
return 0;
}
int resource_manager::do_include_font(const char *ptr, int rank, FILE *,
FILE *outfp)
{
resource *r = read_font_arg(&ptr);
if (r) {
if (rank >= 0)
supply_resource(r, rank + 1, outfp);
else
r->flags |= resource::FONT_NEEDED;
}
return 0;
}
int resource_manager::change_to_end_resource(const char *, int, FILE *,
FILE *outfp)
{
if (outfp)
fputs("%%EndResource\n", outfp);
return 0;
}
int resource_manager::do_begin_preview(const char *, int, FILE *fp, FILE *)
{
string buf;
do {
if (!ps_get_line(buf, fp)) {
error("end of file in preview section");
break;
}
} while (!matches_comment(buf, "EndPreview"));
return 0;
}
int read_one_of(const char **ptr, const char **s, int n)
{
while (white_space(**ptr))
*ptr += 1;
if (**ptr == '\0')
return -1;
const char *start = *ptr;
do {
++(*ptr);
} while (**ptr != '\0' && !white_space(**ptr));
for (int i = 0; i < n; i++)
if (strlen(s[i]) == size_t(*ptr - start)
&& memcmp(s[i], start, *ptr - start) == 0)
return i;
return -1;
}
void skip_possible_newline(FILE *fp, FILE *outfp)
{
int c = getc(fp);
if (c == '\r') {
current_lineno++;
if (outfp)
putc(c, outfp);
int cc = getc(fp);
if (cc != '\n') {
if (cc != EOF)
ungetc(cc, fp);
}
else {
if (outfp)
putc(cc, outfp);
}
}
else if (c == '\n') {
current_lineno++;
if (outfp)
putc(c, outfp);
}
else if (c != EOF)
ungetc(c, fp);
}
int resource_manager::do_begin_data(const char *ptr, int, FILE *fp,
FILE *outfp)
{
while (white_space(*ptr))
ptr++;
const char *start = ptr;
unsigned numberof;
if (!read_uint_arg(&ptr, &numberof))
return 0;
static const char *types[] = { "Binary", "Hex", "ASCII" };
const int Binary = 0;
int type = 0;
static const char *units[] = { "Bytes", "Lines" };
const int Bytes = 0;
int unit = Bytes;
while (white_space(*ptr))
ptr++;
if (*ptr != '\0') {
type = read_one_of(&ptr, types, 3);
if (type < 0) {
error("bad data type");
return 0;
}
while (white_space(*ptr))
ptr++;
if (*ptr != '\0') {
unit = read_one_of(&ptr, units, 2);
if (unit < 0) {
error("expected `Bytes' or `Lines'");
return 0;
}
}
}
if (type != Binary)
return 1;
if (outfp) {
fputs("%%BeginData: ", outfp);
fputs(start, outfp);
}
if (numberof > 0) {
unsigned bytecount = 0;
unsigned linecount = 0;
do {
int c = getc(fp);
if (c == EOF) {
error("end of file within data section");
return 0;
}
if (outfp)
putc(c, outfp);
bytecount++;
if (c == '\r') {
int cc = getc(fp);
if (cc != '\n') {
linecount++;
current_lineno++;
}
if (cc != EOF)
ungetc(c, fp);
}
else if (c == '\n') {
linecount++;
current_lineno++;
}
} while ((unit == Bytes ? bytecount : linecount) < numberof);
}
skip_possible_newline(fp, outfp);
string buf;
if (!ps_get_line(buf, fp)) {
error("missing %%%%EndData line");
return 0;
}
if (!matches_comment(buf, "EndData"))
error("bad %%%%EndData line");
if (outfp)
fputs(buf.contents(), outfp);
return 0;
}
int resource_manager::do_begin_binary(const char *ptr, int, FILE *fp,
FILE *outfp)
{
if (!outfp)
return 0;
unsigned count;
if (!read_uint_arg(&ptr, &count))
return 0;
if (outfp)
fprintf(outfp, "%%%%BeginData: %u Binary Bytes\n", count);
while (count != 0) {
int c = getc(fp);
if (c == EOF) {
error("end of file within binary section");
return 0;
}
if (outfp)
putc(c, outfp);
--count;
if (c == '\r') {
int cc = getc(fp);
if (cc != '\n')
current_lineno++;
if (cc != EOF)
ungetc(cc, fp);
}
else if (c == '\n')
current_lineno++;
}
skip_possible_newline(fp, outfp);
string buf;
if (!ps_get_line(buf, fp)) {
error("missing %%%%EndBinary line");
return 0;
}
if (!matches_comment(buf, "EndBinary")) {
error("bad %%%%EndBinary line");
if (outfp)
fputs(buf.contents(), outfp);
}
else if (outfp)
fputs("%%EndData\n", outfp);
return 0;
}
static unsigned parse_extensions(const char *ptr)
{
unsigned flags = 0;
for (;;) {
while (white_space(*ptr))
ptr++;
if (*ptr == '\0')
break;
const char *name = ptr;
do {
++ptr;
} while (*ptr != '\0' && !white_space(*ptr));
int i;
for (i = 0; i < NEXTENSIONS; i++)
if (strlen(extension_table[i]) == size_t(ptr - name)
&& memcmp(extension_table[i], name, ptr - name) == 0) {
flags |= (1 << i);
break;
}
if (i >= NEXTENSIONS) {
string s(name, ptr - name);
s += '\0';
error("unknown extension `%1'", s.contents());
}
}
return flags;
}
void resource_manager::process_file(int rank, FILE *fp, const char *filename,
FILE *outfp)
{
static const char *header_comment_table[] = {
"DocumentNeededResources:",
"DocumentSuppliedResources:",
"DocumentNeededFonts:",
"DocumentSuppliedFonts:",
"DocumentNeededProcSets:",
"DocumentSuppliedProcSets:",
"DocumentNeededFiles:",
"DocumentSuppliedFiles:",
};
const int NHEADER_COMMENTS = sizeof(header_comment_table)
/ sizeof(header_comment_table[0]);
struct comment_info {
const char *name;
int (resource_manager::*proc)(const char *, int, FILE *, FILE *);
};
static comment_info comment_table[] = {
{ "BeginResource:", &resource_manager::do_begin_resource },
{ "IncludeResource:", &resource_manager::do_include_resource },
{ "BeginDocument:", &resource_manager::do_begin_document },
{ "IncludeDocument:", &resource_manager::do_include_document },
{ "BeginProcSet:", &resource_manager::do_begin_procset },
{ "IncludeProcSet:", &resource_manager::do_include_procset },
{ "BeginFont:", &resource_manager::do_begin_font },
{ "IncludeFont:", &resource_manager::do_include_font },
{ "BeginFile:", &resource_manager::do_begin_file },
{ "IncludeFile:", &resource_manager::do_include_file },
{ "EndProcSet", &resource_manager::change_to_end_resource },
{ "EndFont", &resource_manager::change_to_end_resource },
{ "EndFile", &resource_manager::change_to_end_resource },
{ "BeginPreview:", &resource_manager::do_begin_preview },
{ "BeginData:", &resource_manager::do_begin_data },
{ "BeginBinary:", &resource_manager::do_begin_binary },
};
const int NCOMMENTS = sizeof(comment_table)/sizeof(comment_table[0]);
string buf;
int saved_lineno = current_lineno;
const char *saved_filename = current_filename;
current_filename = filename;
current_lineno = 0;
if (!ps_get_line(buf, fp)) {
current_filename = saved_filename;
current_lineno = saved_lineno;
return;
}
if ((size_t)buf.length() < sizeof(PS_MAGIC)
|| memcmp(buf.contents(), PS_MAGIC, sizeof(PS_MAGIC) - 1) != 0) {
if (outfp) {
do {
if (!(broken_flags & STRIP_PERCENT_BANG)
|| buf[0] != '%' || buf[1] != '!')
fputs(buf.contents(), outfp);
} while (ps_get_line(buf, fp));
}
}
else {
if (!(broken_flags & STRIP_PERCENT_BANG) && outfp)
fputs(buf.contents(), outfp);
int in_header = 1;
int interesting = 0;
int had_extensions_comment = 0;
int had_language_level_comment = 0;
for (;;) {
if (!ps_get_line(buf, fp))
break;
int copy_this_line = 1;
if (buf[0] == '%') {
if (buf[1] == '%') {
const char *ptr;
int i;
for (i = 0; i < NCOMMENTS; i++)
if ((ptr = matches_comment(buf, comment_table[i].name))) {
copy_this_line
= (this->*(comment_table[i].proc))(ptr, rank, fp, outfp);
break;
}
if (i >= NCOMMENTS && in_header) {
if ((ptr = matches_comment(buf, "EndComments")))
in_header = 0;
else if (!had_extensions_comment
&& (ptr = matches_comment(buf, "Extensions:"))) {
extensions |= parse_extensions(ptr);
had_extensions_comment = 1;
}
else if (!had_language_level_comment
&& (ptr = matches_comment(buf, "LanguageLevel:"))) {
unsigned ll;
if (read_uint_arg(&ptr, &ll) && ll > language_level)
language_level = ll;
had_language_level_comment = 1;
}
else {
for (i = 0; i < NHEADER_COMMENTS; i++)
if (matches_comment(buf, header_comment_table[i])) {
interesting = 1;
break;
}
}
}
if ((broken_flags & STRIP_STRUCTURE_COMMENTS)
&& (matches_comment(buf, "EndProlog")
|| matches_comment(buf, "Page:")
|| matches_comment(buf, "Trailer")))
copy_this_line = 0;
}
else if (buf[1] == '!') {
if (broken_flags & STRIP_PERCENT_BANG)
copy_this_line = 0;
}
}
else
in_header = 0;
if (!outfp && !in_header && !interesting)
break;
if (copy_this_line && outfp)
fputs(buf.contents(), outfp);
}
}
current_filename = saved_filename;
current_lineno = saved_lineno;
}
void resource_manager::read_download_file()
{
char *path = 0;
FILE *fp = font::open_file("download", &path);
if (!fp)
fatal("can't find `download'");
char buf[512];
int lineno = 0;
while (fgets(buf, sizeof(buf), fp)) {
lineno++;
char *p = strtok(buf, " \t\r\n");
if (p == 0 || *p == '#')
continue;
char *q = strtok(0, " \t\r\n");
if (!q)
fatal_with_file_and_line(path, lineno, "missing filename");
lookup_font(p)->filename = strsave(q);
}
a_delete path;
fclose(fp);
}
static void print_ps_string(const string &s, FILE *outfp)
{
int len = s.length();
const char *str = s.contents();
int funny = 0;
if (str[0] == '(')
funny = 1;
else {
for (int i = 0; i < len; i++)
if (str[i] <= 040 || str[i] > 0176) {
funny = 1;
break;
}
}
if (!funny) {
put_string(s, outfp);
return;
}
int level = 0;
int i;
for (i = 0; i < len; i++)
if (str[i] == '(')
level++;
else if (str[i] == ')' && --level < 0)
break;
putc('(', outfp);
for (i = 0; i < len; i++)
switch (str[i]) {
case '(':
case ')':
if (level != 0)
putc('\\', outfp);
putc(str[i], outfp);
break;
case '\\':
fputs("\\\\", outfp);
break;
case '\n':
fputs("\\n", outfp);
break;
case '\r':
fputs("\\r", outfp);
break;
case '\t':
fputs("\\t", outfp);
break;
case '\b':
fputs("\\b", outfp);
break;
case '\f':
fputs("\\f", outfp);
break;
default:
if (str[i] < 040 || str[i] > 0176)
fprintf(outfp, "\\%03o", str[i] & 0377);
else
putc(str[i], outfp);
break;
}
putc(')', outfp);
}
void resource_manager::print_extensions_comment(FILE *outfp)
{
if (extensions) {
fputs("%%Extensions:", outfp);
for (int i = 0; i < NEXTENSIONS; i++)
if (extensions & (1 << i)) {
putc(' ', outfp);
fputs(extension_table[i], outfp);
}
putc('\n', outfp);
}
}
void resource_manager::print_language_level_comment(FILE *outfp)
{
if (language_level)
fprintf(outfp, "%%%%LanguageLevel: %u\n", language_level);
}