home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / unixtex-6.1b-src.tgz / tar.out / contrib / unixtex / dvipsk / dospecial.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  19KB  |  710 lines

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