This is psencode.c in view mode; [Download] [Up]
/* psencode.c
Copyright (C) 1991 Bill Spitzak and Active Ingredients, Inc.
Written by Bill Spitzak.
Utility program for compressing postscript into Display
PostScript binary encoding.
Also see systemnames.c and constants.c!
Warning: this code is NOT PORTABLE to a machine that does not
use 4 byte integers, or uses low-byte-first, or does not use
IEEE standard for storing floats.
Decode option and the ability to read already encoded files is not
yet implemented.
*/
/*=======================================================================*/
#include <ansi.h>
#define TRUE 1
#define FALSE 0
typedef char flag;
/* additions to the C library (NOT PORTABLE to non-GNU libraries!) */
int _sprintf(char *s, const char *format, void *valist) {
FILE f;
f._flag = _IOSTRG+_IOWRT;
f._ptr = s;
f._cnt = 32767;
_doprnt(format,valist,&f);
*f._ptr = 0;
return(f._ptr-s);
}
#define pungetc(p) (++(p)->_cnt, --(p)->_ptr)
int hexdigit(int c) { /* convert c to a digit */
if (isdigit(c)) return(c-'0');
else if (isupper(c)) return(c-'A'+10);
else if (islower(c)) return(c-'a'+10);
else return(INT_MAX);
}
/* end of C library additions */
/*=======================================================================*/
flag cstrings,decode,eps,encodestrings;
/* PostScript parser: */
FILE *infile;
char *infilename;
int lineno;
void error(char *fmt,...) {
char buffer[1024];
_sprintf(buffer,fmt,&fmt+1);
fprintf(stderr,"%s:%d: %s\n",infilename,lineno,buffer);
}
#define MAXTOKEN 128
#include "systemnames.c"
flag issymbol; /* set true for 1-character symbols */
static int readsymbol(char *buf) {
int x;
char *p;
for (;;) {
x = fgetc(infile);
if (x < 0) return(FALSE);
if (x == '\n') lineno++;
if (x > ' ') break;
}
p = buf; *p++ = x;
issymbol = index("()<>[]{}/%#",x) || x>=128 && x<=159;
if (!issymbol) {
for (;;) {
x = fgetc(infile);
if (x<0) goto J1;
if (x <= ' ' || index("()<>[]{}/%",x) || (x>=128 && x<=159)) break;
if (p<buf+MAXTOKEN-1) *p++ = x;
}
pungetc(infile);
}
J1:
*p++ = 0;
return(TRUE);
}
/* Exactly one token is handled at a time. When you call readtoken
again, the buffer for the previous value is thrown away! */
#define BUFSIZE 8192
char buffer[BUFSIZE];
int inttoken;
double realtoken; /* NOT A FLOAT! */
/* the types of tokens, and what is put in the buffer */
#define COMMENT 1 /* text of comment with leading % or # */
#define INTEGER 2 /* inttoken is set */
#define REAL 3 /* realtoken is set */
#define STRING 4 /* inttoken is length, contents are value */
#define SYMBOL 5 /* buffer has null-terminated one character */
#define NAME 6 /* buffer has null-terminated name */
#define LITERALNAME 7 /* /foo */
#define IMMEDIATENAME 8 /* //foo */
#define BOOLEANFALSE 9
#define BOOLEANTRUE 10
void readthrueol(char *p) {
int x;
for (;;) {
x = fgetc(infile);
if (x < 0 || x == '\n' || x == '\f') break;
*p++ = x;
}
*p++ = 0;
if (x == '\n') lineno++;
}
static int readquoted() {
register c,d,x;
switch(c = fgetc(infile)) {
case '\n': lineno++; return(-1);
case 'a' : return('\a');
case 'b' : return('\b');
case 'f' : return('\f');
case 'n' : return('\n');
case 'r' : return('\r');
case 't' : return('\t');
case 'v' : return('\v');
case 'x' : /* read hex */
for (c=x=0; x<3; x++) {
d = hexdigit(fgetc(infile));
if (d > 15) {pungetc(infile); break;}
c = (c<<4)+d;
}
break;
default: /* read octal */
if (c<'0' || c>'7') break;
c -= '0';
for (x=0; x<2; x++) {
d = hexdigit(fgetc(infile));
if (d>7) {pungetc(infile); break;}
c = (c<<3)+d;
}
break;
}
return(c);
}
void readstring(char *buf) {
int x,nest=0; char *p;
for (p=buf;;) {
x = fgetc(infile);
if (x<0) {error("Missing )"); break;}
if (x == '\\') {x = readquoted(); if (x<0) continue;}
else if (x == '(') nest++;
else if (x == ')') if (nest) nest--; else break;
*p++ = x;
}
*p = 0;
inttoken = p-buf;
}
void readhexstring(char *buf) {
int x,y,n; char *p;
for (p=buf,n=y=0;;) {
x = fgetc(infile);
if (x<0) {error("Missing >"); break;}
if (x=='>') break;
if (x=='\n') lineno++;
if (x<=' ') continue;
x = hexdigit(x);
if (x>16) error("Bad hex string");
if (n) {*p++ = x+y; n = 0;}
else {y = x<<4; n = 1;}
}
if (n) *p++ = y;
*p = 0;
inttoken = p-buf;
}
int readint(char *buf,int base) {
int n=0,x; char *p;
if (!*buf) error("Bad integer %s",buf);
else for (p=buf; *p; p++) {
x = hexdigit(*p);
if (x >= base) {error("Bad integer %s",buf); break;}
n = n*base+x;
}
return(n);
}
int readtoken(void) {
char *c,*d;
if (!readsymbol(buffer)) return(FALSE);
switch (*(unsigned char *)buffer) {
case '%':
case '#':
readthrueol(buffer+1);
return(COMMENT);
case '(':
readstring(buffer);
return(STRING);
case '<':
readhexstring(buffer);
return(STRING);
case '/':
if (!readsymbol(buffer)) {error("/ at eof"); return(FALSE);}
if (*buffer=='/') {
if (!readsymbol(buffer)) {error("/ at eof"); return(FALSE);}
return(IMMEDIATENAME);
}
return(LITERALNAME);
case 'f':
if (!strcmp(buffer,"false")) return(BOOLEANFALSE);
goto DEFAULT;
case 't':
if (!strcmp(buffer,"true")) return(BOOLEANTRUE);
goto DEFAULT;
case '+':
case '-':
c = buffer+1;
goto NUM;
case 132: fread(&inttoken,1,4,infile); return(INTEGER);
case 134: inttoken = 0; fread((void *)&inttoken+2,1,2,infile); return(INTEGER);
case 136: inttoken = (signed char)fgetc(infile); return(INTEGER);
case 138: {float r; fread(&r,1,4,infile); realtoken = r; return(REAL);}
case 141: return(fgetc(infile) ? BOOLEANTRUE : BOOLEANFALSE);
case 142:
inttoken = fgetc(infile);
fread(buffer,1,inttoken,infile);
return(STRING);
case 143:
inttoken = 0; fread((void *)&inttoken+2,1,2,infile);
fread(buffer,1,inttoken,infile);
return(STRING);
case 145:
c = systemnames[fgetc(infile)];
if (!c) {error("Bad system name table index"); return(SYMBOL);}
strcpy(buffer,c);
return(LITERALNAME);
case 146:
c = systemnames[fgetc(infile)];
if (!c) {error("Bad system name table index"); return(SYMBOL);}
strcpy(buffer,c);
return(NAME);
default:
DEFAULT:
if (*(unsigned char *)buffer >= 128 && *(unsigned char *)buffer <= 159) {
error("Unknown token type %d\n",*(unsigned char *)buffer);
return(SYMBOL);
}
c = buffer;
NUM:if (*c >= '0' && *c <= '9' || *c=='.'&&(*(c+1)>='0'&&*(c+1)<='9')) {
for (d=c; *d; d++) {
if (*d == '#') {
*d = 0; inttoken=readint(d+1,readint(c,10));
if (*buffer == '-') inttoken = -inttoken;
return(INTEGER);
}
if (*d == '.' || *d=='e' || *d=='E') {
realtoken = strtod(buffer,&d);
if (*d) return(NAME); /* bug in strtod, does not work! */
return(REAL);
}
}
inttoken = readint(c,10);
if (*buffer == '-') inttoken = -inttoken;
return(INTEGER);
}
return(issymbol ? SYMBOL : NAME);
}
}
/*==============================================================*/
flag inquotes;
int quotelength;
int outline;
void outchar(unsigned x) {
if (!cstrings) {fputc(x,stdout); return;}
if (quotelength > 70) {
fputs("\"\n",stdout); outline = lineno;
quotelength = 0; inquotes = 0;
}
if (!inquotes) {fputc('"',stdout); inquotes = TRUE;}
if (x == '\n') {
fputs("\\n\"\n",stdout);
quotelength = 0; inquotes = 0;
return;
}
if (x > 126 || x < 32) {
fprintf(stdout,"\\%03o",x&255);
quotelength += 4;
return;
}
if (x == '\\' || x == '"') {fputc('\\',stdout); quotelength++;}
fputc(x,stdout); quotelength++;
}
void output(void *buf,int len) {
if (cstrings) {while(len--) outchar(*(unsigned char *)buf++);}
else fwrite((char *)buf,1,len,stdout);
}
flag neednl,needspace;
void outword(char *buf) {
if (needspace) {
if (outline < lineno) {outchar('\n'); outline = lineno;}
else outchar(' ');
}
output(buf,strlen(buf));
neednl = needspace = TRUE;
}
void writetoken(int t) {
char *c,*e,buf[48];
switch(t) {
case COMMENT:
if (eps == 2 || eps && (*buffer=='#' || *(buffer+1)=='%'
|| *(buffer+1)=='!')) {
if (neednl) outchar('\n');
output(buffer,strlen(buffer));
outchar('\n');
neednl = needspace = FALSE;
outline = lineno;
}
return;
case INTEGER:
if (decode) {
sprintf(buf,"%d",inttoken);
outword(buf);
return;
}
else if (inttoken >= -128 && inttoken < 128) {
outchar(136); outchar(inttoken);
}
else if (inttoken >= -32768 && inttoken < 32768) {
outchar(134); output((void *)&inttoken+2,2);
}
else {outchar(132); output(&inttoken,4);}
break;
case REAL:
if (decode) {
/* print it as short as possible, preserve decimal */
if (!realtoken) {outword("0."); return;}
if (realtoken < 0) {
outword("-"); needspace = FALSE; realtoken = -realtoken;}
sprintf(buf,"%g",realtoken);
for (c=buf; *c!='.' && *c!='e'; c++)
if (!*c) {*c++='.'; *c = 0; break;}
if (*buf=='0') outword(buf+1);
else outword(buf);
return;
}
{float r=realtoken; outchar(138); output(&r,4);}
break;
case STRING:
if (decode || !encodestrings) {
outchar('(');
for (c = buffer, e = c+inttoken; c<e; c++) {
if (*c=='\\' || *c=='(' || *c==')') outchar('\\');
outchar(*c);
}
outchar(')');
}
else {
if (inttoken <= 255) {outchar(142); outchar(inttoken);}
else {outchar(143); output((void *)&inttoken+2,2);}
output(buffer,inttoken);
}
break;
case SYMBOL:
outchar(buffer[0]);
break;
case NAME:
if (!decode && (t=systemindex(buffer))>=0)
{outchar(146); outchar(t);}
else {outword(buffer); return;}
break;
case LITERALNAME:
if (!decode && (t = systemindex(buffer))>=0)
{outchar(145); outchar(t); break;}
goto J0;
case IMMEDIATENAME:
outchar('/');
J0: outchar('/');
output(buffer,strlen(buffer));
neednl = needspace = TRUE;
return;
case BOOLEANFALSE:
if (decode) {outword("false"); return;}
outchar(141); outchar(0); break;
case BOOLEANTRUE:
if (decode) {outword("true"); return;}
outchar(141); outchar(1); break;
default:
error("Unknown token type!");
return;
}
needspace = FALSE;
neednl = TRUE;
}
/*==============================================================*/
void encodeit(void) {
int i;
outline = lineno;
while (i = readtoken()) writetoken(i);
}
/*==============================================================*/
int main(int argc,char **argv) {
int i; char *p;
for (i=1; i<argc; i++) {
if (argv[i][0]=='-' && argv[i][1])
for (p=argv[i]+1; *p; p++) switch(*p) {
case 'c': cstrings = TRUE; break;
case 'd': decode = TRUE; break;
case 'e': eps = TRUE; break;
case 'E': eps = 2; break;
case 's': encodestrings = TRUE; break;
default: goto ERROR;
}
else break;
}
if (i >= argc) {
ERROR: puts(
" psencode: PostScript <-> DPS Binary Encoding translator\n"
" Written by Bill Spitzak (SPITZAK@MCIMAIL.COM) June 1991\n"
" This software is distributed FREE and may not be sold.\n"
"\n"
"psencode {-xxx} name.ps : translate, send to stdout\n"
"\n"
"switches:\n"
"-c : produce C include file\n"
"-d : decode / don't encode\n"
"-e : (eps) preserve %% and # comments\n"
"-E : preserve all comments\n"
"-s : encode strings despite NeXT 2.0 bug\n"
);
exit(1);
}
for (; i<argc; i++) {
lineno = 1;
if (!strcmp(argv[i],"-")) {
infilename = "stdin";
infile = stdin;
}
else {
infilename = argv[i];
infile = fopen(infilename,"r");
}
if (!infile) {error(strerror(errno)); exit(1);}
else encodeit();
}
if (cstrings) {
if (inquotes) fputs("\"\n",stdout);
}
else if (needspace) outchar('\n');
return(0);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.