DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦8690d45f2⟧ TextFile

    Length: 19530 (0x4c4a)
    Types: TextFile
    Names: »dospecial.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦8d3183c2b⟧ »utils/dvips541.tar.Z« 
        └─⟦008d6ff64⟧ 
            └─⟦this⟧ »./dvips/dospecial.c« 

TextFile

/*
 *   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 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");
}