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