ftp.nice.ch/pub/next/unix/hack/hackkit.2.N.bs.tar.gz#/freebies/source/psencode.c

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.