home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d7xx / d795 / pstools.lha / PSTools / PSTools1.lha / source / dospecial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-14  |  19.1 KB  |  724 lines

  1. /*
  2.  *   This routine handles special commands;
  3.  *   predospecial() is for the prescan, dospecial() for the real thing.
  4.  */
  5. #include "structures.h" /* The copyright notice in that file is included too! */
  6.  
  7. #include <ctype.h>
  8. #ifndef _DCC
  9. extern int atoi();
  10. #endif
  11.  
  12. /*
  13.  *   These are the external routines called:
  14.  */
  15. /**/
  16. #ifdef TPIC
  17. /*
  18.  * Fri Mar  9 1990  jourdan@minos.inria.fr (MJ)
  19.  * Upgraded to accommodate tpic release 2.0 extended output language.
  20.  * Should prove upward compatible!
  21.  */
  22. extern void setPenSize();
  23. extern void flushPath();
  24. extern void flushDashed();
  25. extern void flushDashed();
  26. extern void addPath();
  27. extern void arc();
  28. extern void flushSpline();
  29. extern void shadeLast();
  30. extern void whitenLast();
  31. extern void blackenLast();
  32. extern void SetShade() ;
  33. #endif
  34. extern shalfword dvibyte() ;
  35. extern int add_header() ;
  36. extern void hvpos() ;
  37. extern void figcopyfile() ;
  38. #ifndef _DCC
  39. extern char *malloc() ;
  40. #endif
  41. extern void nlcmdout() ;
  42. extern void cmdout() ;
  43. extern void numout() ;
  44. extern void scout() ;
  45. extern void stringend() ;
  46. extern void error() ;
  47. extern void psflush() ;
  48. extern char errbuf[] ;
  49. extern shalfword linepos;
  50. extern Boolean usesspecial ;
  51. extern int landscape ;
  52. extern char *paperfmt ;
  53. extern char *nextstring;
  54. extern char *maxstring;
  55. extern char *oname;
  56. extern FILE *bitfile;
  57. extern int quiet;
  58. extern fontdesctype *curfnt ;
  59. extern int actualdpi ;
  60. extern int vactualdpi ;
  61. extern integer hh, vv;
  62. extern int lastfont ;
  63. extern real conv ;
  64. extern real vconv ;
  65.  
  66. #ifdef DEBUG
  67. extern integer debug_flag;
  68. #endif
  69. extern void scanfontcomments() ;
  70.  
  71. struct bangspecial {
  72.    struct bangspecial *next ;
  73.    char actualstuff[1] ; /* more space will actually be allocated */
  74. } *bangspecials = NULL ;
  75.  
  76. #ifdef EMTEX
  77. /* subset of emtex specials */
  78.  
  79. #define EMMAX 1613 /* maximum number of emtex special points */
  80. #define TRUE 1
  81. #define FALSE 0
  82.  
  83. struct empt {
  84.    shalfword point;
  85.    integer x, y;
  86. };
  87.  
  88. struct empt *empoints = NULL;
  89. boolean emused = FALSE;  /* true if em points used on this page */
  90. integer emx, emy;
  91.  
  92. struct emunit {
  93.    char *unit;
  94.    float factor;
  95. };
  96. struct emunit emtable[] = {
  97.   {"pt",72.27},
  98.   {"pc",72.27/12},
  99.   {"in",1.0},
  100.   {"bp",72.0},
  101.   {"cm",2.54},
  102.   {"mm",25.4},
  103.   {"dd",72.27/(1238/1157)},
  104.   {"cc",72.27/12/(1238/1157)},
  105.   {"sp",72.27*65536},
  106.   {"",0.0}
  107. };
  108.  
  109.  
  110. /* clear the empoints array if necessary */
  111. void
  112. emclear()
  113. {
  114. int i;
  115.    if (emused && empoints)
  116.       for (i=0; i<EMMAX; i++)
  117.          empoints[i].point = 0;
  118.    emused = FALSE ;
  119. }
  120.  
  121. /* put an empoint into the empoints array */
  122. struct empt *emptput(point, x, y)
  123. shalfword point;
  124. integer x, y;
  125. {
  126. int i, start;
  127.  
  128.    emused = TRUE;
  129.    start = point % EMMAX;
  130.    i = start;
  131.    while ( empoints[i].point != 0 ) {
  132.       if ( empoints[i].point == point )
  133.          break;
  134.       i++;
  135.       if (i >= EMMAX)
  136.          i = 0;
  137.       if (i == start) {
  138.      sprintf(errbuf,"!Too many em: special points");
  139.      error(errbuf);
  140.       }
  141.    }
  142.  
  143.    empoints[i].point = point;
  144.    empoints[i].x = x;
  145.    empoints[i].y = y;
  146.    return(&empoints[i]);
  147. }
  148.  
  149. /* get an empoint from the empoints array */
  150. struct empt *emptget(point)
  151. shalfword point;
  152. {
  153. int i, start;
  154.  
  155.    start = point % EMMAX;
  156.    i = start;
  157.    if (emused == TRUE)
  158.       while ( empoints[i].point != 0 ) {
  159.          if (empoints[i].point == point)
  160.             return(&empoints[i]);
  161.          i++;
  162.          if (i >= EMMAX)
  163.             i = 0;
  164.          if (i == start)
  165.             break;
  166.       }
  167.    sprintf(errbuf,"!em: point %d not defined",point);
  168.    error(errbuf);
  169.    return(NULL); /* never returns due to error */
  170. }
  171.  
  172.  
  173. /* convert width into dpi units */
  174. float emunits(width,unit)
  175. float width;
  176. char *unit;
  177. {
  178. struct emunit *p;
  179.     for (p=emtable; *(p->unit)!='\0'; p++) {
  180.        if (strcmp(p->unit,unit)==0)
  181.         return( width * actualdpi / p->factor );
  182.     }
  183.     return (-1.0); /* invalid unit */
  184. }
  185. #endif /* EMTEX */
  186.  
  187.  
  188. static void trytobreakout(p)
  189. register char *p ;
  190. {
  191.    register int i ;
  192.    register int instring = 0 ;
  193.    int lastc = 0 ;
  194.  
  195.    i = 0 ;
  196.    while (*p) {
  197.       if (i > 65 && *p == ' ' && instring == 0) {
  198.          (void)putc('\n', bitfile) ;
  199.          i = 0 ;
  200.       } else {
  201.          (void)putc(*p, bitfile) ;
  202.          i++ ;
  203.       }
  204.       if (*p == '(' && lastc != '\\')
  205.          instring = 1 ;
  206.       else if (*p == ')' && lastc != '\\')
  207.          instring = 0 ;
  208.       lastc = *p ;
  209.       p++ ;
  210.    }
  211. }
  212.  
  213. static void dobs(q)
  214. register struct bangspecial *q ;
  215. {
  216.    if (q) {
  217.       dobs(q->next) ;
  218.       trytobreakout(q->actualstuff) ;
  219.    }
  220. }
  221.  
  222. void
  223. outbangspecials() {
  224.    if (bangspecials) {
  225.       cmdout("TeXDict") ;
  226.       cmdout("begin") ;
  227.       cmdout("@defspecial\n") ;
  228.       dobs(bangspecials) ;
  229.       cmdout("\n@fedspecial") ;
  230.       cmdout("end") ;
  231.    }
  232. }
  233.  
  234. /* We recommend that new specials be handled by the following general
  235.  * (and extensible) scheme, in which the user specifies one or more
  236.  * `key=value' pairs separated by spaces.
  237.  * The known keys are given in KeyTab; they take values
  238.  * of one of the following types:
  239.  *
  240.  * None: no value, just a keyword (in which case the = sign is omitted)
  241.  * String: the value should be "<string without double-quotes"
  242.  *                          or '<string without single-quotes'
  243.  * Integer: the value should be a decimal integer (%d format)
  244.  * Number: the value should be a decimal integer or real (%f format)
  245.  * Dimension: like Number, but will be multiplied by the scaledsize
  246.  *       of the current font and converted to default PostScript units
  247.  * (Actually, strings are allowed in all cases; the delimiting quotes
  248.  *  are simply stripped off if present.)
  249.  *
  250.  */
  251.  
  252. typedef enum {None, String, Integer, Number, Dimension} ValTyp;
  253. typedef struct {
  254.    char    *Entry;
  255.    ValTyp  Type;
  256. } KeyDesc;
  257.  
  258. #define NKEYS    (sizeof(KeyTab)/sizeof(KeyTab[0]))
  259.  
  260. KeyDesc KeyTab[] = {{"psfile",  String}, /* j==0 in the routine below */
  261.                     {"ifffile", String}, /* j==1 */
  262.                     {"tekfile", String}, /* j==2 */
  263.                     {"hsize",   Number},
  264.                     {"vsize",   Number},
  265.                     {"hoffset", Number},
  266.                     {"voffset", Number},
  267.                     {"hscale",  Number},
  268.                     {"vscale",  Number},
  269.                     {"angle",   Number},
  270.                     {"llx", Number},
  271.                     {"lly", Number},
  272.                     {"urx", Number},
  273.                     {"ury", Number},
  274.                     {"rwi", Number}};
  275.  
  276. #ifdef VMS
  277. #define Tolower _tolower
  278. #else
  279. /*
  280.  * compare strings, ignore case
  281.  */
  282. char Tolower(c)
  283. register char c ;
  284. {
  285.    if ('A' <= c && c <= 'Z')
  286.       return(c+32) ;
  287.    else
  288.       return(c) ;
  289. }
  290. #endif
  291. int IsSame(a, b)
  292. char *a, *b;
  293. {
  294.    for( ; *a != '\0'; )
  295.       if( Tolower(*a++) != Tolower(*b++) ) 
  296.          return( 0 );
  297.       return( *b == '\0' );
  298. }
  299.  
  300. char *KeyStr, *ValStr ; /* Key and String values found */
  301. int ValInt ; /* Integer value found */
  302. double ValNum ; /* Number or Dimension value found */
  303.  
  304. char  *GetKeyVal(str,tno) /* returns NULL if none found, else next scan point */
  305.    char *str ; /* starting point for scan */
  306.    int  *tno ; /* table entry number of keyword, or -1 if keyword not found */
  307. {
  308.    register char *s ;
  309.    register int i ;
  310.    register char t ;
  311.  
  312.    for (s=str; *s <= ' ' && *s; s++) ; /* skip over blanks */
  313.    if (*s == '\0')
  314.       return (NULL) ;
  315.    KeyStr = s ;
  316.    while (*s>' ' && *s!='=') s++ ;
  317.    if (t = *s)
  318.       *s++ = 0 ;
  319.  
  320.    for(i=0; i<NKEYS; i++)
  321.       if( IsSame(KeyStr, KeyTab[i].Entry) )
  322.          goto found ;
  323.    *tno = -1;
  324.    return (s) ;
  325.  
  326. found: *tno = i ;
  327.    if (KeyTab[i].Type == None)
  328.       return (s) ;
  329.  
  330.    if (t && t <= ' ') {
  331.       for (; *s <= ' ' && *s; s++) ; /* now look for the value part */
  332.       if ((t = *s)=='=')
  333.          s++ ;
  334.    }
  335.    ValStr = "" ;
  336.    if ( t == '=' ) {
  337.       while (*s <= ' ' && *s)
  338.          s++ ;
  339.       if (*s=='\'' || *s=='\"')
  340.          t = *s++ ;               /* get string delimiter */
  341.       else t = ' ' ;
  342.       ValStr = s ;
  343.       while (*s!=t && *s)
  344.          s++ ;
  345.       if (*s)
  346.          *s++ = 0 ;
  347.    }
  348.    switch (KeyTab[i].Type) {
  349.  case Integer:
  350.       if(sscanf(ValStr,"%d",&ValInt)!=1) {
  351.           sprintf(errbuf,"Non-integer value (%s) given for keyword %s",
  352.               ValStr, KeyStr) ;
  353.           error(errbuf) ;
  354.           ValInt = 0 ;
  355.       }
  356.       break ;
  357.  case Number:
  358.  case Dimension:
  359.       if(sscanf(ValStr,"%lf",&ValNum)!=1) {  
  360.           sprintf(errbuf,"Non-numeric value (%s) given for keyword %s",
  361.               ValStr, KeyStr) ;
  362.           error(errbuf) ;
  363.           ValNum = 0.0 ;
  364.       }
  365.       if (KeyTab[i].Type==Dimension) {
  366.          if (curfnt==NULL)
  367.             error("! No font selected") ;
  368.          ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI ;
  369.       }
  370.       break ;
  371.  default: break ;
  372.    }
  373.    return (s) ;
  374. }
  375.  
  376. /*
  377.  *   Now our routines.  We get the number of bytes specified and place them
  378.  *   into the string buffer, and then parse it. Numerous conventions are
  379.  *   supported here for historical reasons.
  380.  */
  381.  
  382. void predospecial(numbytes, scanning)
  383. integer numbytes ;
  384. Boolean scanning ;
  385. {
  386.    register char *p = nextstring ;
  387.    register int i = 0 ;
  388.    int j ;
  389.  
  390.    if (nextstring + numbytes > maxstring)
  391.       error("! out of string space in predospecial") ;
  392.    for (i=numbytes; i>0; i--)
  393.       *p++ = (char)dvibyte() ;
  394.    while (p[-1] <= ' ' && p > nextstring)
  395.       p-- ; /* trim trailing blanks */
  396.    if (p==nextstring) return ; /* all blank is no-op */
  397.    *p = 0 ;
  398.    p = nextstring ;
  399.    while (*p <= ' ')
  400.       p++ ;
  401. #ifdef DEBUG
  402.    if (dd(D_SPECIAL))
  403.       (void)fprintf(stderr, "Preprocessing special: %s\n", p) ;
  404. #endif
  405.  
  406. /*
  407.  *   We use strncmp() here to also pass things like landscape()
  408.  *   or landscape: or such.
  409.  */
  410.  
  411.    if (strncmp(p, "landscape", 9)==0) {
  412.       landscape = 1 ;
  413.       return ;
  414.    }
  415.    if (strncmp(p, "xtex:", 5)==0) return ;
  416.    usesspecial = 1 ;  /* now the special prolog will be sent */
  417.    if (strncmp(p, "header", 6)==0) {
  418.       char *q ;
  419.       p += 6 ;
  420.       while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
  421.          p++ ;
  422.       q = p ;  /* we will remove enclosing parentheses */
  423.       p = p + strlen(p) - 1 ;
  424.       while ((*p <= ' ' || *p == ')') && p >= q)
  425.          p-- ;
  426.       p[1] = 0 ;
  427.       if (p >= q)
  428.          (void)add_header(q) ;
  429.    }
  430.    else if (*p == '!') {
  431.       register struct bangspecial *q ;
  432.       p++ ;
  433.       q = (struct bangspecial *)malloc((unsigned)
  434.                          (sizeof(struct bangspecial) + strlen(p))) ;
  435.       if (q == NULL)
  436.          error("! out of memory in predospecial") ;
  437.       (void)strcpy(q->actualstuff, p) ;
  438.       q->next = bangspecials ;
  439.       bangspecials = q ;
  440.    } else if (scanning && *p != '"' &&
  441.           (p=GetKeyVal(p, &j)) != NULL && j==0)
  442.       scanfontcomments(ValStr) ;
  443. }
  444.  
  445. void dospecial(numbytes)
  446. integer numbytes ;
  447. {
  448.    register char *p = nextstring ;
  449.    register int i = 0 ;
  450.    int j, systemtype = 0 ;
  451.    char psfile[100] ; 
  452.    char cmdbuf[100] ; 
  453.    register char *q ;
  454.    Boolean psfilewanted = 1 ;
  455.    extern int access() ;
  456. #ifdef EMTEX
  457. /* specials for emtex */
  458. double emwidth;
  459. shalfword empoint1, empoint2;
  460. struct empt *empoint;
  461. char emunit[3];
  462. char emstr[80];
  463. char *emp;
  464. #endif /* EMTEX */
  465.  
  466.    if (nextstring + i > maxstring)
  467.       error("! out of string space in dospecial") ;
  468.    for (i=numbytes; i>0; i--)
  469.       *p++ = (char)dvibyte() ;
  470.    while (p[-1] <= ' ' && p > nextstring)
  471.       p-- ; /* trim trailing blanks */
  472.    if (p==nextstring) return ; /* all blank is no-op */
  473.    *p = 0 ;
  474.    p = nextstring ;
  475.    while (*p <= ' ')
  476.       p++ ;
  477. #ifdef DEBUG
  478.    if (dd(D_SPECIAL))
  479.       (void)fprintf(stderr, "Processing special: %s\n", p) ;
  480. #endif
  481.  
  482. #ifdef EMTEX
  483. /* specials for emtex, added by rjl */
  484. /* at present,
  485.  * the line cut parameter is not supported (and is ignored)
  486.  * em:graph is not supported
  487.  */ 
  488.    if (strncmp(p, "em:", 3)==0) {
  489.         hvpos() ;
  490.     for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
  491.     if (strncmp(emp, "linewidth", 9) == 0) {
  492.        /* code for linewidth */
  493.        for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
  494.        sscanf(emp, "%lf%2s", &emwidth, emunit);
  495.        emwidth = emunits(emwidth,emunit);
  496.        if (emwidth!=-1.0) {
  497.           sprintf(emstr,"%.1f setlinewidth", emwidth);
  498.           cmdout(emstr);
  499. #ifdef DEBUG
  500.    if (dd(D_SPECIAL))
  501.       (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n", 
  502.         emwidth) ;
  503. #endif
  504.        } else {
  505.           sprintf(errbuf,"Unknown em: special width");
  506.           error(errbuf);
  507.        }
  508.     }
  509.         else if (strncmp(emp, "moveto", 6) == 0) {
  510. #ifdef DEBUG
  511.    if (dd(D_SPECIAL))
  512.       (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
  513. #endif
  514.            emx = hh;
  515.            emy = vv;
  516.         }
  517.         else if (strncmp(emp, "lineto", 6) == 0) {
  518. #ifdef DEBUG
  519.    if (dd(D_SPECIAL))
  520.       (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
  521. #endif
  522.        cmdout("np");
  523.        numout(emx);
  524.        numout(emy);
  525.        cmdout("a");
  526.        numout(hh);
  527.        numout(vv);
  528.        cmdout("li");
  529.        cmdout("st");
  530.            emx = hh;
  531.            emy = vv;
  532.         }
  533.     else if (strncmp(emp, "point", 5) == 0) {
  534.            if (empoints == NULL) {
  535.               if (( empoints = 
  536.                   (struct empt *)malloc(EMMAX * sizeof(struct empt)) )
  537.                   == (struct empt *)NULL)
  538.                    error("! can't allocate em: points space") ;
  539.               emused = TRUE;
  540.               emclear();
  541.            }
  542.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  543.            empoint1 = (shalfword)atoi(emp);
  544.            empoint = emptput(empoint1,hh,vv);
  545. #ifdef DEBUG
  546.    if (dd(D_SPECIAL))
  547.       (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
  548.         empoint->point, empoint->x, empoint->y) ;
  549. #endif
  550.     }
  551.     else if (strncmp(emp, "line", 4) == 0) {
  552.        for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
  553.            empoint1 = (shalfword)atoi(emp);
  554.        for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
  555.        if ( *emp && strchr("hvp",*emp)!=0 )
  556.           emp++;  /* skip line cut */
  557.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  558.        if ( *emp && ispunct(*emp) )
  559.           emp++; /*  skip comma separator */
  560.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  561.            empoint2 = (shalfword)atoi(emp);
  562.        for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
  563.        if ( *emp && strchr("hvp",*emp)!=0 )
  564.           emp++;  /* skip line cut */
  565.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  566.        if ( *emp && ispunct(*emp) )
  567.           emp++; /*  skip comma separator */
  568.        emwidth = -1.0;
  569.        emunit[0]='\0';
  570.        sscanf(emp, "%lf%2s", &emwidth, emunit);
  571.        emwidth = emunits(emwidth,emunit);
  572. #ifdef DEBUG
  573.    if (dd(D_SPECIAL))
  574.       (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
  575.         empoint1, empoint2) ;
  576. #endif
  577.        cmdout("np");
  578.        if (emwidth!=-1.0) {
  579. #ifdef DEBUG
  580.    if (dd(D_SPECIAL))
  581.    (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
  582.         emwidth) ;
  583. #endif
  584.            strcpy(emstr,"currentlinewidth");
  585.            cmdout(emstr);
  586.             sprintf(emstr,"%.1f setlinewidth", emwidth);
  587.             cmdout(emstr);
  588.        }
  589.            empoint = emptget(empoint1);
  590.        numout(empoint->x);
  591.        numout(empoint->y);
  592.        cmdout("a");
  593.            empoint = emptget(empoint2);
  594.        numout(empoint->x);
  595.        numout(empoint->y);
  596.        cmdout("li");
  597.        cmdout("st");
  598.        if (emwidth!=-1.0) {
  599.            strcpy(emstr,"setlinewidth");
  600.            cmdout(emstr);
  601.        }
  602.     }
  603.     else if (strncmp(emp, "message", 7) == 0) {
  604.            (void)fprintf(stderr, "em message: %s\n", emp+7) ;
  605.     }
  606.     else {
  607.            sprintf(errbuf, 
  608.           "Unknown em: command (%s) in \\special will be ignored", p);
  609.            error(errbuf) ;
  610.     }
  611.     return;
  612.    }
  613. #endif /* EMTEX */
  614.  
  615.    if (strncmp(p, "ps:", 3)==0) {
  616.         hvpos() ;
  617.         psflush() ; /* now anything can happen. */
  618.         if (p[3]==':') {
  619.            if (strncmp(p+4, "[begin]", 7) == 0)
  620.               nlcmdout(&p[11]);
  621.            else if (strncmp(p+4, "[end]", 5) == 0)
  622.               nlcmdout(&p[9]);
  623.            else nlcmdout(&p[4]);
  624.         } else if (strncmp(p+3, " plotfile ", 10) == 0) {
  625.            char *sfp ;
  626.            p += 13;
  627.            for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
  628.            *sfp = '\0';
  629.            figcopyfile (p, 0);
  630.         } else
  631.            nlcmdout(&p[3]);
  632.         return;
  633.    }
  634.    if (strncmp(p, "landscape", 9)==0 || strncmp(p, "header", 6)==0 || *p=='!')
  635.       return ; /* already handled in prescan */
  636. #ifdef TPIC
  637. /* ordered as in tpic 2.0 documentation for ease of cross-referencing */
  638.    if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
  639.    if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
  640.    if (strcmp(p, "fp") == 0) {flushPath(0); return;}
  641.    if (strcmp(p, "ip") == 0) {flushPath(1); return;} /* tpic 2.0 */
  642.    if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
  643.    if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
  644.    if (strcmp(p, "sp") == 0) {flushSpline(p+2); return;} /* tpic 2.0 */
  645.    if (strncmp(p, "sp ", 3) == 0) {flushSpline(p+3); return;} /* tpic 2.0 */
  646.    if (strncmp(p, "ar ", 3) == 0) {arc(p+2, 0); return;} /* tpic 2.0 */
  647.    if (strncmp(p, "ia ", 3) == 0) {arc(p+2, 1); return;} /* tpic 2.0 */
  648.    if (strcmp(p, "sh") == 0) {shadeLast(p+2); return;} /* tpic 2.0 */
  649.    if (strncmp(p, "sh ", 3) == 0) {shadeLast(p+3); return;} /* tpic 2.0 */
  650.    if (strcmp(p, "wh") == 0) {whitenLast(); return;}
  651.    if (strcmp(p, "bk") == 0) {blackenLast(); return;}
  652.    if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
  653. #endif
  654.    if (*p == '"') {
  655.       hvpos();
  656.       cmdout("@beginspecial") ;
  657.       cmdout("@setspecial\n") ;
  658.       trytobreakout(p+1) ;
  659.       cmdout("\n@endspecial") ;
  660.       return ;
  661.    }
  662.  
  663. /* At last we get to the key/value conventions */
  664.    psfile[0] = '\0';
  665.    hvpos();
  666.    cmdout("@beginspecial");
  667.  
  668.    while( (p=GetKeyVal(p,&j)) != NULL )
  669.       switch (j) {
  670.  case -1: /* for compatability with old conventions, we allow a file name
  671.            * to be given without the 'psfile=' keyword */
  672.          if (!psfile[0] && access(KeyStr,4)==0) /* yes we can read it */
  673.              (void)strcpy(psfile,KeyStr) ;
  674.          else {
  675.            sprintf(errbuf, "Unknown keyword (%s) in \\special will be ignored",
  676.                               KeyStr) ;
  677.            error(errbuf) ;
  678.          }
  679.          break ;
  680.  case 0: /* psfile */
  681.          if (psfile[0]) {
  682.            sprintf(errbuf, "More than one \\special %s given; %s ignored", 
  683.                     j ? "system" : "psfile",  ValStr) ;
  684.            error(errbuf) ;
  685.          }
  686.          else (void)strcpy(psfile,ValStr) ;
  687.          break ;
  688.  case 1: case 2:
  689.          sprintf(errbuf, 
  690.             "Sorry, there's presently no \\special support for %s", KeyStr) ;
  691.          error(errbuf) ;
  692.          psfilewanted = 0 ;
  693.          break ;
  694.  default: /* most keywords are output as PostScript procedure calls */
  695.          if (KeyTab[j].Type == Integer)
  696.             numout(ValInt);
  697.          else if (KeyTab[j].Type == String)
  698.             for (q=ValStr; *q; q++)
  699.                scout(*q) ;
  700.          else if (KeyTab[j].Type == None) ;
  701.          else { /* Number or Dimension */
  702.             ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5) ;
  703.             if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
  704.                 numout(ValInt) ;
  705.             else {
  706.                (void)sprintf(cmdbuf, "%f", ValNum) ;
  707.                cmdout(cmdbuf) ;
  708.             }
  709.          }
  710.       (void)sprintf(cmdbuf, "@%s", KeyStr);
  711.       cmdout(cmdbuf) ;
  712.       }
  713.  
  714.    cmdout("@setspecial");
  715.  
  716.    if(psfile[0]) {
  717.       systemtype = (psfile[0]=='`') ;
  718.       figcopyfile(psfile+systemtype, systemtype);
  719.    } else if (psfilewanted)
  720.       error("No \\special psfile was given; figure will be blank") ;
  721.  
  722.    cmdout("@endspecial");
  723. }
  724.