home *** CD-ROM | disk | FTP | other *** search
- /*
- * This routine handles special commands;
- * predospecial() is for the prescan, dospecial() for the real thing.
- */
- #include "structures.h" /* The copyright notice in that file is included too! */
-
- #include <ctype.h>
- extern int atoi();
-
- /*
- * These are the external routines called:
- */
- /**/
- #ifdef TPIC
- /*
- * Fri Mar 9 1990 jourdan@minos.inria.fr (MJ)
- * Upgraded to accommodate tpic release 2.0 extended output language.
- * Should prove upward compatible!
- */
- extern void setPenSize();
- extern void flushPath();
- extern void flushDashed();
- extern void flushDashed();
- extern void addPath();
- extern void arc();
- extern void flushSpline();
- extern void shadeLast();
- extern void whitenLast();
- extern void blackenLast();
- extern void SetShade() ;
- #endif
- extern shalfword dvibyte() ;
- extern int add_header() ;
- extern void hvpos() ;
- extern void figcopyfile() ;
- /* extern char *malloc() ; */
- extern void* malloc(unsigned) ;
- extern void nlcmdout() ;
- extern void cmdout() ;
- extern void numout() ;
- extern void scout() ;
- extern void stringend() ;
- extern void error() ;
- extern void psflush() ;
- extern char errbuf[] ;
- extern shalfword linepos;
- extern Boolean usesspecial ;
- extern int landscape ;
- extern char *paperfmt ;
- extern char *nextstring;
- extern char *maxstring;
- extern char *oname;
- extern FILE *bitfile;
- extern int quiet;
- extern fontdesctype *curfnt ;
- extern int actualdpi ;
- extern int vactualdpi ;
- extern integer hh, vv;
- extern int lastfont ;
- extern real conv ;
- extern real vconv ;
-
- #ifdef DEBUG
- extern integer debug_flag;
- #endif
- extern void scanfontcomments() ;
-
- struct bangspecial {
- struct bangspecial *next ;
- char actualstuff[1] ; /* more space will actually be allocated */
- } *bangspecials = NULL ;
-
- #ifdef EMTEX
- /* subset of emtex specials */
-
- #define EMMAX 1613 /* maximum number of emtex special points */
- #define TRUE 1
- #define FALSE 0
-
- struct empt {
- shalfword point;
- integer x, y;
- };
-
- struct empt *empoints = NULL;
- boolean emused = FALSE; /* true if em points used on this page */
- integer emx, emy;
-
- struct emunit {
- char *unit;
- float factor;
- };
- struct emunit emtable[] = {
- {"pt",72.27},
- {"pc",72.27/12},
- {"in",1.0},
- {"bp",72.0},
- {"cm",2.54},
- {"mm",25.4},
- {"dd",72.27/(1238/1157)},
- {"cc",72.27/12/(1238/1157)},
- {"sp",72.27*65536},
- {"",0.0}
- };
-
-
- /* clear the empoints array if necessary */
- void
- emclear()
- {
- int i;
- if (emused && empoints)
- for (i=0; i<EMMAX; i++)
- empoints[i].point = 0;
- emused = FALSE ;
- }
-
- /* put an empoint into the empoints array */
- struct empt *emptput(point, x, y)
- shalfword point;
- integer x, y;
- {
- int i, start;
-
- emused = TRUE;
- start = point % EMMAX;
- i = start;
- while ( empoints[i].point != 0 ) {
- if ( empoints[i].point == point )
- break;
- i++;
- if (i >= EMMAX)
- i = 0;
- if (i == start) {
- sprintf(errbuf,"!Too many em: special points");
- error(errbuf);
- }
- }
-
- empoints[i].point = point;
- empoints[i].x = x;
- empoints[i].y = y;
- return(&empoints[i]);
- }
-
- /* get an empoint from the empoints array */
- struct empt *emptget(point)
- shalfword point;
- {
- int i, start;
-
- start = point % EMMAX;
- i = start;
- if (emused == TRUE)
- while ( empoints[i].point != 0 ) {
- if (empoints[i].point == point)
- return(&empoints[i]);
- i++;
- if (i >= EMMAX)
- i = 0;
- if (i == start)
- break;
- }
- sprintf(errbuf,"!em: point %d not defined",point);
- error(errbuf);
- return(NULL); /* never returns due to error */
- }
-
-
- /* convert width into dpi units */
- float emunits(width,unit)
- float width;
- char *unit;
- {
- struct emunit *p;
- for (p=emtable; *(p->unit)!='\0'; p++) {
- if (strcmp(p->unit,unit)==0)
- return( width * actualdpi / p->factor );
- }
- return (-1.0); /* invalid unit */
- }
- #endif /* EMTEX */
-
-
- static void trytobreakout(p)
- register char *p ;
- {
- register int i ;
- register int instring = 0 ;
- int lastc = 0 ;
-
- i = 0 ;
- while (*p) {
- if (i > 65 && *p == ' ' && instring == 0) {
- (void)putc('\n', bitfile) ;
- i = 0 ;
- } else {
- (void)putc(*p, bitfile) ;
- i++ ;
- }
- if (*p == '(' && lastc != '\\')
- instring = 1 ;
- else if (*p == ')' && lastc != '\\')
- instring = 0 ;
- lastc = *p ;
- p++ ;
- }
- }
-
- static void dobs(q)
- register struct bangspecial *q ;
- {
- if (q) {
- dobs(q->next) ;
- trytobreakout(q->actualstuff) ;
- }
- }
-
- void
- outbangspecials() {
- if (bangspecials) {
- cmdout("TeXDict") ;
- cmdout("begin") ;
- cmdout("@defspecial\n") ;
- dobs(bangspecials) ;
- cmdout("\n@fedspecial") ;
- cmdout("end") ;
- }
- }
-
- /* We recommend that new specials be handled by the following general
- * (and extensible) scheme, in which the user specifies one or more
- * `key=value' pairs separated by spaces.
- * The known keys are given in KeyTab; they take values
- * of one of the following types:
- *
- * None: no value, just a keyword (in which case the = sign is omitted)
- * String: the value should be "<string without double-quotes"
- * or '<string without single-quotes'
- * Integer: the value should be a decimal integer (%d format)
- * Number: the value should be a decimal integer or real (%f format)
- * Dimension: like Number, but will be multiplied by the scaledsize
- * of the current font and converted to default PostScript units
- * (Actually, strings are allowed in all cases; the delimiting quotes
- * are simply stripped off if present.)
- *
- */
-
- typedef enum {None, String, Integer, Number, Dimension} ValTyp;
- typedef struct {
- char *Entry;
- ValTyp Type;
- } KeyDesc;
-
- #define NKEYS (sizeof(KeyTab)/sizeof(KeyTab[0]))
-
- KeyDesc KeyTab[] = {{"psfile", String}, /* j==0 in the routine below */
- {"ifffile", String}, /* j==1 */
- {"tekfile", String}, /* j==2 */
- {"hsize", Number},
- {"vsize", Number},
- {"hoffset", Number},
- {"voffset", Number},
- {"hscale", Number},
- {"vscale", Number},
- {"angle", Number},
- {"llx", Number},
- {"lly", Number},
- {"urx", Number},
- {"ury", Number},
- {"rwi", Number}};
-
- #ifndef VMS
- /*
- * compare strings, ignore case
- */
- char Tolower(c)
- register char c ;
- {
- if ('A' <= c && c <= 'Z')
- return(c+32) ;
- else
- return(c) ;
- }
- #endif
- int IsSame(a, b)
- char *a, *b;
- {
- for( ; *a != '\0'; )
- if( Tolower(*a++) != Tolower(*b++) )
- return( 0 );
- return( *b == '\0' );
- }
-
- char *KeyStr, *ValStr ; /* Key and String values found */
- long ValInt ; /* Integer value found */
- float ValNum ; /* Number or Dimension value found */
-
- char *GetKeyVal(str,tno) /* returns NULL if none found, else next scan point */
- char *str ; /* starting point for scan */
- int *tno ; /* table entry number of keyword, or -1 if keyword not found */
- {
- register char *s ;
- register int i ;
- register char t ;
-
- for (s=str; *s <= ' ' && *s; s++) ; /* skip over blanks */
- if (*s == '\0')
- return (NULL) ;
- KeyStr = s ;
- while (*s>' ' && *s!='=') s++ ;
- if (t = *s)
- *s++ = 0 ;
-
- for(i=0; i<NKEYS; i++)
- if( IsSame(KeyStr, KeyTab[i].Entry) )
- goto found ;
- *tno = -1;
- return (s) ;
-
- found: *tno = i ;
- if (KeyTab[i].Type == None)
- return (s) ;
-
- if (t && t <= ' ') {
- for (; *s <= ' ' && *s; s++) ; /* now look for the value part */
- if ((t = *s)=='=')
- s++ ;
- }
- ValStr = "" ;
- if ( t == '=' ) {
- while (*s <= ' ' && *s)
- s++ ;
- if (*s=='\'' || *s=='\"')
- t = *s++ ; /* get string delimiter */
- else t = ' ' ;
- ValStr = s ;
- while (*s!=t && *s)
- s++ ;
- if (*s)
- *s++ = 0 ;
- }
- switch (KeyTab[i].Type) {
- case Integer:
- if(sscanf(ValStr,"%ld",&ValInt)!=1) {
- sprintf(errbuf,"Non-integer value (%s) given for keyword %s",
- ValStr, KeyStr) ;
- error(errbuf) ;
- ValInt = 0 ;
- }
- break ;
- case Number:
- case Dimension:
- if(sscanf(ValStr,"%f",&ValNum)!=1) {
- sprintf(errbuf,"Non-numeric value (%s) given for keyword %s",
- ValStr, KeyStr) ;
- error(errbuf) ;
- ValNum = 0 ;
- }
- if (KeyTab[i].Type==Dimension) {
- if (curfnt==NULL)
- error("! No font selected") ;
- ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI ;
- }
- break ;
- default: break ;
- }
- return (s) ;
- }
-
- /*
- * Now our routines. We get the number of bytes specified and place them
- * into the string buffer, and then parse it. Numerous conventions are
- * supported here for historical reasons.
- */
-
- void predospecial(numbytes, scanning)
- integer numbytes ;
- Boolean scanning ;
- {
- register char *p = nextstring ;
- register int i = 0 ;
- int j ;
-
- if (nextstring + numbytes > maxstring)
- error("! out of string space in predospecial") ;
- for (i=numbytes; i>0; i--)
- *p++ = (char)dvibyte() ;
- while (p[-1] <= ' ' && p > nextstring)
- p-- ; /* trim trailing blanks */
- if (p==nextstring) return ; /* all blank is no-op */
- *p = 0 ;
- p = nextstring ;
- while (*p <= ' ')
- p++ ;
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "Preprocessing special: %s\n", p) ;
- #endif
-
- /*
- * We use strncmp() here to also pass things like landscape()
- * or landscape: or such.
- */
-
- if (strncmp(p, "landscape", 9)==0) {
- landscape = 1 ;
- return ;
- }
- if (strncmp(p, "xtex:", 5)==0) return ;
- usesspecial = 1 ; /* now the special prolog will be sent */
- if (strncmp(p, "header", 6)==0) {
- char *q ;
- p += 6 ;
- while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
- p++ ;
- q = p ; /* we will remove enclosing parentheses */
- p = p + strlen(p) - 1 ;
- while ((*p <= ' ' || *p == ')') && p >= q)
- p-- ;
- p[1] = 0 ;
- if (p >= q)
- (void)add_header(q) ;
- }
- else if (*p == '!') {
- register struct bangspecial *q ;
- p++ ;
- q = (struct bangspecial *)malloc((unsigned)
- (sizeof(struct bangspecial) + strlen(p))) ;
- if (q == NULL)
- error("! out of memory in predospecial") ;
- (void)strcpy(q->actualstuff, p) ;
- q->next = bangspecials ;
- bangspecials = q ;
- } else if (scanning && *p != '"' &&
- (p=GetKeyVal(p, &j)) != NULL && j==0)
- scanfontcomments(ValStr) ;
- }
-
- void dospecial(numbytes)
- integer numbytes ;
- {
- register char *p = nextstring ;
- register int i = 0 ;
- int j, systemtype = 0 ;
- char psfile[100] ;
- char cmdbuf[100] ;
- register char *q ;
- Boolean psfilewanted = 1 ;
- extern int access() ;
- #ifdef EMTEX
- /* specials for emtex */
- float emwidth;
- shalfword empoint1, empoint2;
- struct empt *empoint;
- char emunit[3];
- char emstr[80];
- char *emp;
- #endif /* EMTEX */
-
- if (nextstring + i > maxstring)
- error("! out of string space in dospecial") ;
- for (i=numbytes; i>0; i--)
- *p++ = (char)dvibyte() ;
- while (p[-1] <= ' ' && p > nextstring)
- p-- ; /* trim trailing blanks */
- if (p==nextstring) return ; /* all blank is no-op */
- *p = 0 ;
- p = nextstring ;
- while (*p <= ' ')
- p++ ;
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "Processing special: %s\n", p) ;
- #endif
-
- #ifdef EMTEX
- /* specials for emtex, added by rjl */
- /* at present,
- * the line cut parameter is not supported (and is ignored)
- * em:graph is not supported
- */
- if (strncmp(p, "em:", 3)==0) {
- hvpos() ;
- for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
- if (strncmp(emp, "linewidth", 9) == 0) {
- /* code for linewidth */
- for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
- sscanf(emp, "%f%2s", &emwidth, emunit);
- emwidth = emunits(emwidth,emunit);
- if (emwidth!=-1.0) {
- sprintf(emstr,"%.1f setlinewidth", emwidth);
- cmdout(emstr);
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n",
- emwidth) ;
- #endif
- } else {
- sprintf(errbuf,"Unknown em: special width");
- error(errbuf);
- }
- }
- else if (strncmp(emp, "moveto", 6) == 0) {
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
- #endif
- emx = hh;
- emy = vv;
- }
- else if (strncmp(emp, "lineto", 6) == 0) {
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
- #endif
- cmdout("np");
- numout(emx);
- numout(emy);
- cmdout("a");
- numout(hh);
- numout(vv);
- cmdout("li");
- cmdout("st");
- emx = hh;
- emy = vv;
- }
- else if (strncmp(emp, "point", 5) == 0) {
- if (empoints == NULL) {
- if (( empoints =
- (struct empt *)malloc(EMMAX * sizeof(struct empt)) )
- == (struct empt *)NULL)
- error("! can't allocate em: points space") ;
- emused = TRUE;
- emclear();
- }
- for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
- empoint1 = (shalfword)atoi(emp);
- empoint = emptput(empoint1,hh,vv);
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
- empoint->point, empoint->x, empoint->y) ;
- #endif
- }
- else if (strncmp(emp, "line", 4) == 0) {
- for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
- empoint1 = (shalfword)atoi(emp);
- for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
- if ( *emp && strchr("hvp",*emp)!=0 )
- emp++; /* skip line cut */
- for (; *emp && isspace(*emp); emp++); /* skip blanks */
- if ( *emp && ispunct(*emp) )
- emp++; /* skip comma separator */
- for (; *emp && isspace(*emp); emp++); /* skip blanks */
- empoint2 = (shalfword)atoi(emp);
- for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
- if ( *emp && strchr("hvp",*emp)!=0 )
- emp++; /* skip line cut */
- for (; *emp && isspace(*emp); emp++); /* skip blanks */
- if ( *emp && ispunct(*emp) )
- emp++; /* skip comma separator */
- emwidth = -1.0;
- emunit[0]='\0';
- sscanf(emp, "%f%2s", &emwidth, emunit);
- emwidth = emunits(emwidth,emunit);
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
- empoint1, empoint2) ;
- #endif
- cmdout("np");
- if (emwidth!=-1.0) {
- #ifdef DEBUG
- if (dd(D_SPECIAL))
- (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n",
- emwidth) ;
- #endif
- strcpy(emstr,"currentlinewidth");
- cmdout(emstr);
- sprintf(emstr,"%.1f setlinewidth", emwidth);
- cmdout(emstr);
- }
- empoint = emptget(empoint1);
- numout(empoint->x);
- numout(empoint->y);
- cmdout("a");
- empoint = emptget(empoint2);
- numout(empoint->x);
- numout(empoint->y);
- cmdout("li");
- cmdout("st");
- if (emwidth!=-1.0) {
- strcpy(emstr,"setlinewidth");
- cmdout(emstr);
- }
- }
- else if (strncmp(emp, "message", 7) == 0) {
- (void)fprintf(stderr, "em message: %s\n", emp+7) ;
- }
- else {
- sprintf(errbuf,
- "Unknown em: command (%s) in \\special will be ignored", p);
- error(errbuf) ;
- }
- return;
- }
- #endif /* EMTEX */
-
- if (strncmp(p, "ps:", 3)==0) {
- hvpos() ;
- psflush() ; /* now anything can happen. */
- if (p[3]==':') {
- if (strncmp(p+4, "[begin]", 7) == 0)
- nlcmdout(&p[11]);
- else if (strncmp(p+4, "[end]", 5) == 0)
- nlcmdout(&p[9]);
- else nlcmdout(&p[4]);
- } else if (strncmp(p+3, " plotfile ", 10) == 0) {
- char *sfp ;
- p += 13;
- for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
- *sfp = '\0';
- figcopyfile (p, 0);
- } else
- nlcmdout(&p[3]);
- return;
- }
- if (strncmp(p, "landscape", 9)==0 || strncmp(p, "header", 6)==0 || *p=='!')
- return ; /* already handled in prescan */
- #ifdef TPIC
- /* ordered as in tpic 2.0 documentation for ease of cross-referencing */
- if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
- if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
- if (strcmp(p, "fp") == 0) {flushPath(0); return;}
- if (strcmp(p, "ip") == 0) {flushPath(1); return;} /* tpic 2.0 */
- if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
- if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
- if (strcmp(p, "sp") == 0) {flushSpline(p+2); return;} /* tpic 2.0 */
- if (strncmp(p, "sp ", 3) == 0) {flushSpline(p+3); return;} /* tpic 2.0 */
- if (strncmp(p, "ar ", 3) == 0) {arc(p+2, 0); return;} /* tpic 2.0 */
- if (strncmp(p, "ia ", 3) == 0) {arc(p+2, 1); return;} /* tpic 2.0 */
- if (strcmp(p, "sh") == 0) {shadeLast(p+2); return;} /* tpic 2.0 */
- if (strncmp(p, "sh ", 3) == 0) {shadeLast(p+3); return;} /* tpic 2.0 */
- if (strcmp(p, "wh") == 0) {whitenLast(); return;}
- if (strcmp(p, "bk") == 0) {blackenLast(); return;}
- if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
- #endif
- if (*p == '"') {
- hvpos();
- cmdout("@beginspecial") ;
- cmdout("@setspecial\n") ;
- trytobreakout(p+1) ;
- cmdout("\n@endspecial") ;
- return ;
- }
-
- /* At last we get to the key/value conventions */
- psfile[0] = '\0';
- hvpos();
- cmdout("@beginspecial");
-
- while( (p=GetKeyVal(p,&j)) != NULL )
- switch (j) {
- case -1: /* for compatability with old conventions, we allow a file name
- * to be given without the 'psfile=' keyword */
- if (!psfile[0] && access(KeyStr,4)==0) /* yes we can read it */
- (void)strcpy(psfile,KeyStr) ;
- else {
- sprintf(errbuf, "Unknown keyword (%s) in \\special will be ignored",
- KeyStr) ;
- error(errbuf) ;
- }
- break ;
- case 0: /* psfile */
- if (psfile[0]) {
- sprintf(errbuf, "More than one \\special %s given; %s ignored",
- j ? "system" : "psfile", ValStr) ;
- error(errbuf) ;
- }
- else (void)strcpy(psfile,ValStr) ;
- break ;
- case 1: case 2:
- sprintf(errbuf,
- "Sorry, there's presently no \\special support for %s", KeyStr) ;
- error(errbuf) ;
- psfilewanted = 0 ;
- break ;
- default: /* most keywords are output as PostScript procedure calls */
- if (KeyTab[j].Type == Integer)
- numout(ValInt);
- else if (KeyTab[j].Type == String)
- for (q=ValStr; *q; q++)
- scout(*q) ;
- else if (KeyTab[j].Type == None) ;
- else { /* Number or Dimension */
- ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5) ;
- if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
- numout(ValInt) ;
- else {
- (void)sprintf(cmdbuf, "%f", ValNum) ;
- cmdout(cmdbuf) ;
- }
- }
- (void)sprintf(cmdbuf, "@%s", KeyStr);
- cmdout(cmdbuf) ;
- }
-
- cmdout("@setspecial");
-
- if(psfile[0]) {
- systemtype = (psfile[0]=='`') ;
- figcopyfile(psfile+systemtype, systemtype);
- } else if (psfilewanted)
- error("No \\special psfile was given; figure will be blank") ;
-
- cmdout("@endspecial");
- }
-