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