This is simple.c in view mode; [Download] [Up]
static char rcsid[] = "$Author: cck $ $Date: 88/05/21 14:02:19 $";
static char rcsident[] = "$Header: simple.c,v 1.16 88/05/21 14:02:19 cck Rel $";
static char revision[] = "$Revision: 1.16 $";
/*
* lwsrv - UNIX AppleTalk spooling program: act as a laserwriter
* simple.c - simple spooler. Understands enough of Adobe's Document
* Structuring Conventions to work, but doesn't really abide by them.
*
* should be replaced by a conforming implementation.
*
*
* AppleTalk package for UNIX (4.2 BSD).
*
* Copyright (c) 1986, 1987, 1988 by The Trustees of Columbia University in the
* City of New York.
*
* Edit History:
*
* Sept 5, 1987 created by cck
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/param.h>
#ifndef _TYPES
/* assume included by param.h */
# include <sys/types.h>
#endif
#include <netat/appletalk.h>
#include <netat/sysvcompat.h>
#include <netat/compat.h>
#ifdef USESTRINGDOTH
# include <string.h>
#else
# include <strings.h>
#endif
#include "spmisc.h"
#include "procset.h"
#include "fontlist.h"
#include "papstream.h"
/* TOKEN types */
/* token types above: 4095 are not valid */
/* integer type should be at least 16 bits */
/* top 4 bits are used in to validate, invalidate things */
#define TOK_INVALID 0x1000 /* token shouldn't be considered */
#define TOK_VAL_MASK 0xfff /* token value mask */
#define TOK_EOF 200 /* end of file marker */
#define TOK_UNK 201 /* unknown token */
#define TOK_ADV 0 /* AppleDict Version */
#define TOK_FLS 1 /* FontList */
#define TOK_ENDOLD 2 /* End of one of above */
#define TOK_TIT 3
#define TOK_CRE 4
#define TOK_FOR 5
#define TOK_ENC 6
#define TOK_BPSQ 7
#define TOK_EPSQ 8
#define TOK_BFLQ 9
#define TOK_EFLQ 10
#define TOK_BPS 11
#define TOK_EPS 12
#define TOK_IPS 13 /* include procset */
#define TOK_BEGINR 101 /* begin of query */
#define TOK_ENDR 102 /* end queyr with response */
#define TOK_BEGIN 103 /* begin item */
#define TOK_END 104 /* end item */
#define TOK_DROP 105 /* simply drop */
/* token table */
struct atoken {
char *token;
int toklen;
int tokval;
} toktbl[] = {
#define TOKEN(token, tag) { (token), (sizeof(token)-1), (tag)}
TOKEN("%%EOF", TOK_DROP),
TOKEN("%%Title", TOK_TIT),
TOKEN("%%Creator", TOK_CRE),
TOKEN("%%For", TOK_FOR),
TOKEN("%%EndComments", TOK_ENC),
TOKEN("%%?BeginProcSetQuery", TOK_BPSQ),
TOKEN("%%?EndProcSetQuery", TOK_EPSQ),
TOKEN("%%?BeginFontListQuery", TOK_BFLQ),
TOKEN("%%?EndFontListQuery", TOK_EFLQ),
TOKEN("%%?BeginFontQuery", TOK_BEGINR),
TOKEN("%%?EndFontQuery", TOK_ENDR),
TOKEN("%%?BeginFeatureQuery", TOK_BEGINR),
TOKEN("%%?EndFeatureQuery", TOK_ENDR),
TOKEN("%%?BeginVMStatus", TOK_BEGINR),
TOKEN("%%?EndVMStatus", TOK_ENDR),
TOKEN("%%BeginExitServer", TOK_BEGIN),
TOKEN("%%EndExitServer", TOK_END),
TOKEN("%%BeginProcSet", TOK_BPS),
TOKEN("%%EndProcSet", TOK_EPS),
TOKEN("%%?BeginPrinterQuery", TOK_BEGINR),
TOKEN("%%?EndPrinterQuery", TOK_ENDR),
TOKEN("%%?BeginQuery", TOK_BEGINR),
TOKEN("%%?EndQuery", TOK_ENDR),
#ifdef ADOBE_DSC2_CONFORMANT
TOKEN("%%IncludeProcSet", TOK_IPS),
#else
TOKEN("%%IncludeProcSet", TOK_IPS|TOK_INVALID),
#endif
/* very old type of queries */
TOKEN("%?appledict version #", TOK_ADV),
TOKEN("%?fontList", TOK_FLS),
TOKEN("%?end",TOK_ENDOLD),
{NULL, TOK_UNK, 0}
};
private char *tracefile;
private char *dictdir;
private char *prtname;
private FILE *procsetfile = NULL;
private char tmpstr[MAXPATHLEN];
private FILE *outfile;
private int crtolf = FALSE;
private int needquote = FALSE;
private int nodsc = FALSE;
#ifdef ADOBE_DSC2_CONFORMANT
private int adobe_dsc2_conformant = TRUE;
#else
private int adobe_dsc2_conformant = FALSE;
#endif
export int is_simple_dsc();
export int simple_dsc_option();
export int simple_TranscriptOption();
export int spool_setup();
private void validate_token_type();
private void invalidate_token_type();
private int tokval();
private void dumpout();
private int scantoken();
int getjob();
private void SendVAck();
export int
is_simple_dsc()
{
return(adobe_dsc2_conformant);
}
export int
simple_dsc_option(ioption)
char *ioption;
{
int i;
char *p;
char option[5]; /* big enough for biggest */
for (i = 0, p = ioption; i < 4; i++, p++)
if (*p == '\0')
break;
else
option[i] = (isupper(*p)) ? tolower(*p) : *p;
option[i] = '\0'; /* tie off string */
if (strcmp(option, "on") == 0) {
fprintf(stderr, "lwsrv: simple: Turning on DSC2 compatibility, was %s\n",
adobe_dsc2_conformant ? "on" : "off");
adobe_dsc2_conformant = TRUE;
validate_token_type(TOK_IPS);
} else if (strcmp(option, "off") == 0) {
fprintf(stderr, "lwsrv: simple: Turning off DSC2 compatibility, was %s\n",
adobe_dsc2_conformant ? "on" : "off");
adobe_dsc2_conformant = FALSE;
invalidate_token_type(TOK_IPS);
} else {
fprintf(stderr,"lwsrv: simple: unknown Transcript compatiblity option: %s\n",
option);
return(-1);
}
return(0);
}
/*
* establish transcript compatibility options if any
*
*/
export int
simple_TranscriptOption(ioption)
char *ioption;
{
register char *p;
register char *q;
int i;
char option[100]; /* big enough for biggest option */
/* leave one for null (99 vs. 100) */
for (p = ioption, q = option, i = 0; i < 99; i++, p++)
if (*p == '\0') {
break;
} else if (*p == ' ' || *p == '\t' || *p == '-' || *p == '_')
continue;
else if (isupper(*p))
*q++ = tolower(*p);
else
*q++ = *p;
*q = '\0';
if (strcmp(option, "quote8bit") == 0) {
needquote = TRUE;
fprintf(stderr, "lwsrv: simple: quoting 8 bit characters\n");
} else if (strcmp(option, "crtolf") == 0) {
crtolf = TRUE;
fprintf(stderr,"lwsrv: simple: translate carrage return to line feed\n");
} else if (strcmp(option, "makenondscconformant") == 0) {
nodsc = TRUE;
fprintf(stderr,"lwsrv: simple: will make documents non DSC conformant\n");
} else {
fprintf(stderr,"lwsrv:simple: unknown Transcript compatibility option: %s\n",
ioption);
return(-1);
}
return(0);
}
/*
* establish tracefile if any
* establish fontfile name
* (prtname unused)
* establish procset/dictionary directory and scan for dictionaries
*
*/
export int
spool_setup(itracefile, fontfile, iprtname, idictdir)
char *itracefile;
char *fontfile;
char *iprtname;
char *idictdir;
{
int errs;
tracefile = itracefile;
prtname = iprtname;
dictdir = idictdir;
if (prtname == NULL)
prtname = "unknown";
if (fontfile == NULL || !LoadFontList(fontfile)) {
fprintf(stderr,"lwsrv: simple: Bad FontList\n");
return(FALSE);
}
fprintf(stderr,"lwsrv: simple: Font list from file %s\n",fontfile);
scandicts(dictdir); /* scan for dictionary files */
return(TRUE);
}
/*
* validate/invalidate a token type for use
*
*/
private void
validate_token_type(toktype)
int toktype;
{
register struct atoken *tp;
for (tp = toktbl; tp->token != NULL; tp++)
if ((tp->tokval & TOK_VAL_MASK) == toktype)
tp->tokval &= (~TOK_INVALID);
}
private void
invalidate_token_type(toktype)
int toktype;
{
register struct atoken *tp;
/* can't invalidate these */
if (toktype == TOK_UNK || toktype == TOK_EOF)
return;
for (tp = toktbl; tp->token != NULL; tp++)
if ((tp->tokval & TOK_VAL_MASK) == toktype)
tp->tokval |= TOK_INVALID;
}
/*
* scan "str" for a token and return the token type.
* set ptr to the position after the token
*
*/
private int
tokval(str,ptr)
char *str,**ptr;
{
char *p;
register struct atoken *tp;
/* all tokens start with "%?" or "%%" or "%!" */
if (str[0] != '%')
return(TOK_UNK);
if (str[1] != '?' && str[1] != '%' && str[1] != '!')
return(TOK_UNK);
for (tp = toktbl; tp->token != NULL; tp++) { /* locate token value */
if (tp->tokval & TOK_INVALID)
continue;
if (strncmp(str,tp->token,tp->toklen) == 0) {
p = &str[tp->toklen];
if (*p == ':') /* skip ':' */
p++;
/* skip leading white space */
while (*p != '\0' && (*p == ' ' || *p == '\t'))
p++;
*ptr = p; /* set tokstr */
return(tp->tokval); /* and return the value */
}
}
return(TOK_UNK);
}
/*
* dump the string to the outfile and procset file if necesary
*
*/
private void
dumpout(str,len)
char *str;
int len;
{
int i,c;
for (i=0; i < len; i++) {
c = str[i];
if (crtolf && c == '\r')
c = '\n';
if (needquote) {
if (isascii(c)) /* is it standard ascii? */
putc(c,outfile); /* yes... so echo */
else /* otherwise echo \ddd */
fprintf(outfile,"\\%03o",(unsigned char) c);
} else
putc(c,outfile);
if (procsetfile) /* never quote */
putc(c, procsetfile);
}
putc('\n',outfile);
if (procsetfile)
putc('\n', procsetfile);
}
/*
* int scantoken(PFILE *pf,int echo,char *tokstr)
*
* Read characters from the PAP connection specified by pf.
* Echo characters to stdout if echo is TRUE. Return token value
* and tokstr pointing past token characters.
*
*/
#define MAXTOKSTR 1024
/* We assume all tokens begin with "%" */
private int
scantoken(pf,echo,tptr)
PFILE *pf;
int echo;
char **tptr;
{
static char tokstr[MAXTOKSTR];
int atstart,i,c,tv,maybetoken;
i = 0;
atstart = TRUE;
maybetoken = FALSE;
while ((c = p_getc(pf)) != EOF) {
if (c == '%' && atstart)
maybetoken = TRUE;
atstart = (c == '\r' || c == '\n') ? TRUE : FALSE;
if (maybetoken) {
if (atstart) { /* last char is cr or lf */
tokstr[i] = '\0'; /* tie off token */
if ((tv = tokval(tokstr,tptr)) != TOK_UNK) {
if (tracefile != NULL)
dumpout(tokstr,i);
return(tv);
} else if ((tracefile != NULL) || echo)
dumpout(tokstr, i);
i = 0;
maybetoken = FALSE;
continue; /* skip everything else */
}
if (i < MAXTOKSTR)
tokstr[i++] = c;
continue;
}
/* papif handles it right, but others like transcript don't, so... */
if ((tracefile != NULL) || echo) { /* do we want to echo this? */
/* papif handles it right, but others like transcript don't, so... */
/* make it a compilable option */
if (crtolf && c == '\r')
c = '\n';
if (needquote) {
if (isascii(c)) /* is it standard ascii? */
putc(c,outfile); /* yes... so echo */
else /* otherwise echo \ddd */
fprintf(outfile,"\\%03o",(unsigned char) c);
} else
putc(c,outfile);
}
if (procsetfile)
putc(c, procsetfile);
}
/* found EOF */
if ((tracefile != NULL) || echo)
putc('\n',outfile); /* yes... echo eol */
if (procsetfile)
putc('\n', procsetfile);
return(TOK_EOF); /* return now */
}
/*
* handle an incoming job
*
*/
int
getjob(pf,of)
PFILE *pf;
FILE *of;
{
char *ts,adictver[80];
int ltokval,tokval,echo;
DictList *dl = NULL; /* current dictionary */
DictList *dlnew = NULL; /* new dictionary */
outfile = of;
p_clreof(pf); /* clear EOF indicator */
echo = TRUE;
if (nodsc) {
fprintf(outfile, "%%! PostScript Document, but non-conformant\n");
fprintf(outfile, "%% so psrv is not invoked\n");
}
clearstack();
while ((tokval = scantoken(pf,echo,&ts)) != TOK_EOF) {
switch (tokval) {
case TOK_DROP:
break;
case TOK_BPS:
/* really smart would install into dict */
/* remember to flush off "appledict" part */
push(tokval); /* remember where */
echo = FALSE;
stripspaces(ts); /* clear off extra spaces */
if ((dl = GetProcSet(ts)) != NULL) {
fprintf(stderr, "lwsrv: simple: procset already known\n");
break;
}
sprintf(tmpstr, "%s/FoundProcSet.%d",dictdir,time(0));
fprintf(stderr, "lwsrv: simple: Saving to %s BeginProcSet: %s\n",
tmpstr, ts);
if (procsetfile != NULL) {
fprintf(stderr, "lwsrv: simple: Already logging prep file!");
break;
}
if ((procsetfile = fopen(tmpstr, "w+")) == NULL) {
procsetfile = NULL;
perror(tmpstr);
} else {
dlnew = dl = (DictList *)malloc(sizeof(DictList));
dl->ad_ver = strdup(ts);
dl->ad_fn = strdup(tmpstr+strlen(dictdir)+1);
dl->ad_next = NULL;
fprintf(procsetfile, "%%%%BeginProcSet: %s\n", ts);
}
/* copy from BPS to end into file or memory */
/* tag given is new proc set */
break;
case TOK_EPS:
if (pop() != TOK_BPS) {
fprintf(stderr,"lwsrv: simple: Framing error on Begin/End Proc Set\n");
}
if (procsetfile) { /* if remember file */
fprintf(procsetfile, "%%%%EndProcSet\n");
fclose(procsetfile); /* close outfile */
}
procsetfile = NULL;
echo = TRUE;
if (dlnew) {
newdictionary(dlnew);
dlnew = NULL; /* close off */
}
if (dl) {
fprintf(stderr,
((adobe_dsc2_conformant) ?
"lwsrv: simple: dsc2: document supplied procset %s = %s\n" :
"lwsrv: simple: non-dsc2: Including ProcSet %s = %s\n"),
dl->ad_ver,dl->ad_fn);
fprintf(outfile,"%% ** Procset From File: %s **\n",dl->ad_fn);
ListProcSet(dl->ad_fn, dictdir, outfile);
fprintf(outfile,"%% ** End of ProcSet **\n");
}
dl = NULL; /* Close off */
break;
case TOK_BEGIN:
push(tokval);
echo = FALSE;
break;
case TOK_END:
if (pop() != TOK_BEGIN)
fprintf(stderr, "lwsrv: simple: Framing error on TOK_BEGIN/END\n");
echo = TRUE;
break;
case TOK_BEGINR:
push(tokval); /* remember last token value */
echo = FALSE;
break;
case TOK_ENDR:
if (pop() != TOK_BEGINR)
fprintf(stderr,"lwsrv: simple: Stack Frame error on TOK_BEGINR/ENDR\n");
echo = TRUE; /* we are now echoing */
p_write(pf,ts,strlen(ts),FALSE);
break;
case TOK_BPSQ:
case TOK_BFLQ:
case TOK_FLS: /* fontList */
case TOK_ADV: /* appledict version */
push(tokval);
if (tracefile == NULL) /* unless tracing there is no */
echo = FALSE; /* echoing between token and End */
if (tokval == TOK_ADV || /* is this appledict query? */
tokval == TOK_BPSQ)
strcpy(adictver,ts); /* yes, remember appledict version */
break;
case TOK_FOR: /* For: */
setusername(ts);
break;
case TOK_TIT: /* Title: */
setjobname(ts);
break;
case TOK_ENC: /* EndComments */
break;
case TOK_IPS:
if (!adobe_dsc2_conformant)
break;
stripspaces(ts); /* strip extra spaces */
if ((dl = GetProcSet(ts)) != NULL) {
fprintf(stderr,"lwsrv: simple: Including ProcSet %s = %s\n",
dl->ad_ver,dl->ad_fn);
fprintf(outfile,"%% ** Include Procset From File: %s **\n",dl->ad_fn);
ListProcSet(dl->ad_fn, dictdir, outfile);
fprintf(outfile,"%% ** End of ProcSet **\n");
dl = NULL; /* close off */
} else
fprintf(stderr,"lwsrv: simple: Unknown ProcSet file for '%s'\n",ts);
break;
case TOK_EFLQ:
case TOK_EPSQ:
case TOK_ENDOLD: /* End */
echo = TRUE; /* we are now echoing */
ltokval = pop();
switch (ltokval) { /* according to last found token */
case TOK_BPSQ:
case TOK_ADV: /* if last token was AppleDict */
SendVAck(pf,adictver); /* then handle appledict */
break;
case TOK_BFLQ:
case TOK_FLS: /* if last token was FontList */
SendFontList(pf); /* then send out the fontlist */
break;
default:
fprintf(stderr, "lwsrv: simple: Stack framing error: got %d\n",
ltokval);
break;
}
}
}
if (!isstackempty()) {
fprintf(stderr, "lwsrv: simple: EOF and tokens still on stack!\n");
dumpstack();
}
if (procsetfile) {
fclose(procsetfile);
if (dlnew) {
unlink(dlnew->ad_fn);
free(dlnew->ad_fn); /* free fn */
free(dlnew);
}
}
if (p_isopn(pf)) /* if connection is still open */
p_write(pf,"",0,TRUE); /* send EOF for this job */
return(p_isopn(pf)); /* return open state */
}
#define MD_UNK "0\n" /* Mac dictionary not loaded */
#define MD_AVOK "1\n" /* AppleDict version ok (av) */
#define MD_AVBAD "2\n" /* AppleDict version not ok */
/*
* answer a query as to whether a particular procset is known or not
*
*/
private void
SendVAck(pf,ver)
PFILE *pf;
char *ver;
{
DictList *dl;
char status[80];
stripspaces(ver); /* strip any extra spaces */
dl = GetProcSet(ver); /* find any procset */
if (tracefile != NULL || dl == (DictList *)NULL) {
p_write(pf,MD_UNK,2,FALSE); /* if tracing download the dict */
fprintf(stderr,"lwsrv: simple: Receiving AppleDict version %s\n",ver);
/* won't do much good unless single fork */
sprintf(status,"Receiving AppleDict version #%s",ver);
NewStatus(status);
return; /* by pass the prepend */
} else
p_write(pf,MD_AVOK,2,FALSE); /* otherwise we use local file */
if (!adobe_dsc2_conformant) {
if (dl != (DictList *) NULL) {
if (tracefile == NULL) {
/* won't do much good unless single fork */
sprintf(status,"prepending AppleDict version #%s",ver);
NewStatus(status);
fprintf(stderr,"lwsrv: simple: Using ProcSet %s = %s\n",ver,dl->ad_fn);
fprintf(outfile,"%% ** Prepending ProcSet from: %s **\n",dl->ad_fn);
ListProcSet(dl->ad_fn, dictdir, outfile); /* prepend appledict */
fprintf(outfile,"%% ** End of ProcSet **\n");
}
} else {
fprintf(stderr,"lwsrv: simple: Unknown ProcSet file for '%s'\n",ver);
}
}
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.