ftp.nice.ch/pub/next/unix/network/system/cap.5.0.s.tar.gz#/cap_5.0/applications/lwsrv/simple.c

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.