Back to index

tetex-bin  3.0
dospecial.c
Go to the documentation of this file.
00001 /*
00002  *   This routine handles special commands;
00003  *   predospecial() is for the prescan, dospecial() for the real thing.
00004  */
00005 #include "dvips.h" /* The copyright notice in that file is included too! */
00006 
00007 #ifdef KPATHSEA
00008 #include <kpathsea/c-ctype.h>
00009 #include <kpathsea/tex-hush.h>
00010 #else /* ! KPATHSEA */
00011 #include <ctype.h>
00012 #include <stdlib.h>
00013 #ifndef WIN32
00014 extern int atoi();
00015 extern int system();
00016 #endif /* WIN32*/
00017 #endif
00018 /*
00019  *   These are the external routines called:
00020  */
00021 
00022 #include "protos.h"
00023 
00024 /* IBM: color - end */
00025 #ifdef HPS
00026 extern Boolean PAGEUS_INTERUPPTUS ;
00027 extern integer HREF_COUNT ;
00028 extern Boolean NEED_NEW_BOX ;
00029 extern Boolean HPS_FLAG ;
00030 #endif
00031 extern char errbuf[] ;
00032 extern shalfword linepos;
00033 extern Boolean usesspecial ;
00034 extern Boolean usescolor ;   /* IBM: color */
00035 extern int landscape ;
00036 extern char *paperfmt ;
00037 extern char *nextstring;
00038 extern char *maxstring;
00039 extern char *oname;
00040 extern FILE *bitfile;
00041 extern int quiet;
00042 extern fontdesctype *curfnt ;
00043 extern int actualdpi ;
00044 extern int vactualdpi ;
00045 extern integer hh, vv;
00046 extern int lastfont ;
00047 extern real conv ;
00048 extern real vconv ;
00049 extern integer hpapersize, vpapersize ;
00050 extern Boolean pprescan ;
00051 #ifndef KPATHSEA
00052 extern char *figpath ;
00053 #endif
00054 extern int prettycolumn ;
00055 extern Boolean disablecomments ;
00056 
00057 #ifdef DEBUG
00058 extern integer debug_flag;
00059 #endif
00060 
00061 static int specialerrors = 20 ;
00062 
00063 struct bangspecial {
00064    struct bangspecial *next ;
00065    char actualstuff[1] ; /* more space will actually be allocated */
00066 } *bangspecials = NULL ;
00067 
00068 void specerror P1C(char *, s)
00069 {
00070    if (specialerrors > 0 
00071 #ifdef KPATHSEA
00072        && !kpse_tex_hush ("special")
00073 #endif
00074        ) {
00075       error(s) ;
00076       specialerrors-- ;
00077    } else if (specialerrors == 0 
00078 #ifdef KPATHSEA
00079              && !kpse_tex_hush ("special")
00080 #endif
00081              ) {
00082       error("more errors in special, being ignored . . .") ;
00083       error("(perhaps dvips doesn't support your macro package?)");
00084       specialerrors-- ;
00085    }
00086 }
00087 
00088 static void trytobreakout P1C(register char *, p)
00089 {
00090    register int i ;
00091    register int instring = 0 ;
00092    int lastc = 0 ;
00093 
00094    i = 0 ;
00095    (void)putc('\n', bitfile) ;
00096    while (*p) {
00097       if (i > 65 && *p == ' ' && instring == 0) {
00098          (void)putc('\n', bitfile) ;
00099          i = 0 ;
00100       } else {
00101          (void)putc(*p, bitfile) ;
00102          i++ ;
00103       }
00104       if (*p == '(' && lastc != '\\')
00105          instring = 1 ;
00106       else if (*p == ')' && lastc != '\\')
00107          instring = 0 ;
00108       lastc = *p ;
00109       p++ ;
00110    }
00111    (void)putc('\n', bitfile) ;
00112 }
00113 
00114 static void dobs P1C(register struct bangspecial *, q)
00115 {
00116    if (q) {
00117       dobs(q->next) ;
00118       trytobreakout(q->actualstuff) ;
00119    }
00120 }
00121 
00122 void
00123 outbangspecials P1H(void) {
00124    if (bangspecials) {
00125       cmdout("TeXDict") ;
00126       cmdout("begin") ;
00127       cmdout("@defspecial\n") ;
00128       dobs(bangspecials) ;
00129       cmdout("\n@fedspecial") ;
00130       cmdout("end") ;
00131    }
00132 }
00133 
00134 /* We recommend that new specials be handled by the following general
00135  * (and extensible) scheme, in which the user specifies one or more
00136  * `key=value' pairs separated by spaces.
00137  * The known keys are given in KeyTab; they take values
00138  * of one of the following types:
00139  *
00140  * None: no value, just a keyword (in which case the = sign is omitted)
00141  * String: the value should be "<string without double-quotes"
00142  *                          or '<string without single-quotes'
00143  * Integer: the value should be a decimal integer (%d format)
00144  * Number: the value should be a decimal integer or real (%f format)
00145  * Dimension: like Number, but will be multiplied by the scaledsize
00146  *       of the current font and converted to default PostScript units
00147  * (Actually, strings are allowed in all cases; the delimiting quotes
00148  *  are simply stripped off if present.)
00149  *
00150  */
00151 
00152 typedef enum {None, String, Integer, Number, Dimension} ValTyp;
00153 typedef struct {
00154    char    *Entry;
00155    ValTyp  Type;
00156 } KeyDesc;
00157 
00158 #define NKEYS    (sizeof(KeyTab)/sizeof(KeyTab[0]))
00159 
00160 KeyDesc KeyTab[] = {{"psfile",  String}, /* j==0 in the routine below */
00161                     {"ifffile", String}, /* j==1 */
00162                     {"tekfile", String}, /* j==2 */
00163                     {"hsize",   Number},
00164                     {"vsize",   Number},
00165                     {"hoffset", Number},
00166                     {"voffset", Number},
00167                     {"hscale",  Number},
00168                     {"vscale",  Number},
00169                     {"angle",   Number},
00170                     {"llx", Number},
00171                     {"lly", Number},
00172                     {"urx", Number},
00173                     {"ury", Number},
00174                     {"rwi", Number},
00175                     {"rhi", Number},
00176                     {"clip", None}};
00177 
00178 #ifndef KPATHSEA
00179 #define TOLOWER Tolower
00180 #ifdef VMS
00181 #ifndef __GNUC__     /* GNUC tolower is too simple */
00182 #define Tolower tolower
00183 #endif
00184 #else
00185 #ifdef VMCMS    /* IBM: VM/CMS */
00186 #define Tolower __tolower
00187 #else
00188 #ifdef MVSXA    /* IBM: MVS/XA */
00189 #define Tolower __tolower
00190 #else
00191 /*
00192  * compare strings, ignore case
00193  */
00194 char Tolower P1C(register char, c)
00195 {
00196    if ('A' <= c && c <= 'Z')
00197       return(c+32) ;
00198    else
00199       return(c) ;
00200 }
00201 #endif
00202 #endif  /* IBM: VM/CMS */
00203 #endif
00204 #endif /* !KPATHSEA */
00205 int IsSame P2C(char *, a, char *, b)
00206 {
00207    for( ; *a != '\0'; ) {
00208       if( TOLOWER(*a) != TOLOWER(*b) ) 
00209          return( 0 );
00210       a++ ;
00211       b++ ;
00212    }
00213    return( *b == '\0' );
00214 }
00215 
00216 char *KeyStr, *ValStr ; /* Key and String values found */
00217 long ValInt ; /* Integer value found */
00218 float ValNum ; /* Number or Dimension value found */
00219 
00220 char  *GetKeyVal P2C(char *, str, int *, tno) /* returns NULL if none found, else next scan point */
00221      /* str : starting point for scan */
00222      /* tno : table entry number of keyword, or -1 if keyword not found */
00223 {
00224    register char *s ;
00225    register int i ;
00226    register char t ;
00227 
00228    for (s=str; *s <= ' ' && *s; s++) ; /* skip over blanks */
00229    if (*s == '\0')
00230       return (NULL) ;
00231    KeyStr = s ;
00232    while (*s>' ' && *s!='=') s++ ;
00233    if (0 != (t = *s))
00234       *s++ = 0 ;
00235 
00236    for(i=0; i<NKEYS; i++)
00237       if( IsSame(KeyStr, KeyTab[i].Entry) )
00238          goto found ;
00239    *tno = -1;
00240    return (s) ;
00241 
00242 found: *tno = i ;
00243    if (KeyTab[i].Type == None)
00244       return (s) ;
00245 
00246    if (t && t <= ' ') {
00247       for (; *s <= ' ' && *s; s++) ; /* now look for the value part */
00248       if ((t = *s)=='=')
00249          s++ ;
00250    }
00251    ValStr = "" ;
00252    if ( t == '=' ) {
00253       while (*s <= ' ' && *s)
00254          s++ ;
00255       if (*s=='\'' || *s=='\"')
00256          t = *s++ ;               /* get string delimiter */
00257       else t = ' ' ;
00258       ValStr = s ;
00259       while (*s!=t && *s)
00260          s++ ;
00261       if (*s)
00262          *s++ = 0 ;
00263    }
00264    switch (KeyTab[i].Type) {
00265  case Integer:
00266       if(sscanf(ValStr,"%ld",&ValInt)!=1) {
00267           sprintf(errbuf,"Non-integer value (%s) given for keyword %s",
00268               ValStr, KeyStr) ;
00269           specerror(errbuf) ;
00270           ValInt = 0 ;
00271       }
00272       break ;
00273  case Number:
00274  case Dimension:
00275       if(sscanf(ValStr,"%f",&ValNum)!=1) {  
00276           sprintf(errbuf,"Non-numeric value (%s) given for keyword %s",
00277               ValStr, KeyStr) ;
00278           specerror(errbuf) ;
00279           ValNum = 0.0 ;
00280       }
00281       if (KeyTab[i].Type==Dimension) {
00282          if (curfnt==NULL)
00283             error("! No font selected") ;
00284          ValNum = ValNum * ((double)curfnt->scaledsize) * conv * 72 / DPI ;
00285       }
00286       break ;
00287  default: break ;
00288    }
00289    return (s) ;
00290 }
00291 
00292 /*
00293  *   Now our routines.  We get the number of bytes specified and place them
00294  *   into the string buffer, and then parse it. Numerous conventions are
00295  *   supported here for historical reasons.
00296  *
00297  *   To support GNUplot's horribly long specials, we go ahead and malloc a
00298  *   new string buffer if necessary.
00299  */
00300 
00301 void predospecial P2C(integer, numbytes, Boolean, scanning)
00302 {
00303    register char *p = nextstring ;
00304    register int i = 0 ;
00305    int j ;
00306    static int omega_specials = 0;
00307 
00308    if (nextstring + numbytes > maxstring) {
00309       p = nextstring = mymalloc(1000 + 2 * numbytes) ;
00310       maxstring = nextstring + 2 * numbytes + 700 ;
00311    }
00312    for (i=numbytes; i>0; i--)
00313 #ifdef VMCMS /* IBM: VM/CMS */
00314       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00315 #else
00316 #ifdef MVSXA /* IBM: MVS/XA */
00317       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00318 #else
00319       *p++ = (char)dvibyte() ;
00320 #endif /* IBM: VM/CMS */
00321 #endif
00322    if (pprescan)
00323       return ;
00324    while (p[-1] <= ' ' && p > nextstring)
00325       p-- ; /* trim trailing blanks */
00326    if (p==nextstring) return ; /* all blank is no-op */
00327    *p = 0 ;
00328    p = nextstring ;
00329    while (*p <= ' ')
00330       p++ ;
00331 #ifdef DEBUG
00332    if (dd(D_SPECIAL))
00333       (void)fprintf(stderr, "Preprocessing special: %s\n", p) ;
00334 #endif
00335 
00336 /*
00337  *   We use strncmp() here to also pass things like landscape()
00338  *   or landscape: or such.
00339  */
00340 
00341    switch (*p) {
00342 case 'o':
00343    if (strncmp(p, "om:", 3)==0) {       /* Omega specials ignored */
00344         if (omega_specials==0) {
00345                 fprintf(stderr, "Omega specials are currently ignored\n");
00346                 omega_specials++;
00347         }
00348         return;
00349    }
00350    break ;
00351 case 'l':
00352    if (strncmp(p, "landscape", 9)==0) {
00353       if (hpapersize || vpapersize)
00354          error(
00355              "both landscape and papersize specified:  ignoring landscape") ;
00356       else
00357          landscape = 1 ;
00358       return ;
00359    }
00360    break ;
00361 case 'p':
00362    if (strncmp(p, "pos:", 4)==0) return ; /* positional specials */
00363    if (strncmp(p, "papersize", 9)==0) {
00364       p += 9 ;
00365       while (*p == '=' || *p == ' ')
00366          p++ ;
00367       if (hpapersize == 0 || vpapersize == 0) {
00368          if (landscape) {
00369             error(
00370              "both landscape and papersize specified:  ignoring landscape") ;
00371             landscape = 0 ;
00372          }
00373          handlepapersize(p, &hpapersize, &vpapersize) ;
00374       }
00375       return ;
00376    }
00377    break ;
00378 case 'x':
00379    if (strncmp(p, "xtex:", 5)==0) return ;
00380    break ;
00381 case 's':
00382    if (strncmp(p, "src:", 4)==0) return ; /* source specials */
00383    break ;
00384 
00385 case 'h':
00386    if (strncmp(p, "header", 6)==0) {
00387       char *q ;
00388       p += 6 ;
00389       while ((*p <= ' ' || *p == '=' || *p == '(') && *p != 0)
00390          p++ ;
00391       q = p ;  /* we will remove enclosing parentheses */
00392       p = p + strlen(p) - 1 ;
00393       while ((*p <= ' ' || *p == ')') && p >= q)
00394          p-- ;
00395       p[1] = 0 ;
00396       if (p >= q)
00397          (void)add_header(q) ;
00398    }
00399    break ;
00400 /* IBM: color - added section here for color header and color history */
00401 /* using strncmp in this fashion isn't perfect; if later someone wants
00402    to introduce a verb like colorspace, well, just checking
00403    strcmp(p, "color", 5) will not do.  But we leave it alone for the moment.
00404    --tgr */
00405 case 'b':
00406    if (strncmp(p, "background", 10) == 0) {
00407       usescolor = 1 ;
00408       p += 10 ;
00409       while ( *p && *p <= ' ' ) p++ ;
00410       background(p) ;
00411       return ;
00412    }
00413    break ;
00414 case 'c':
00415    if (strncmp(p, "color", 5) == 0) {
00416       usescolor = 1 ;
00417       p += 5 ;
00418       while ( *p && *p <= ' ' ) p++ ;
00419       if (strncmp(p, "push", 4) == 0 ) {
00420          p += 4 ;
00421          while ( *p && *p <= ' ' ) p++ ;
00422          pushcolor(p, 0) ;
00423       } else if (strncmp(p, "pop", 3) == 0 ) {
00424          popcolor(0) ;
00425       } else {
00426          resetcolorstack(p,0) ;
00427       }
00428    }   /* IBM: color - end changes */
00429    break ;
00430 case '!':
00431    {
00432       register struct bangspecial *q ;
00433       p++ ;
00434       q = (struct bangspecial *)mymalloc((integer)
00435                          (sizeof(struct bangspecial) + strlen(p))) ;
00436       (void)strcpy(q->actualstuff, p) ;
00437       q->next = bangspecials ;
00438       bangspecials = q ;
00439       usesspecial = 1 ;
00440       return ;
00441    }
00442    break ;
00443 default:
00444 #if 0
00445    {
00446       /* Unknown special, must return */
00447       return;
00448    }
00449 #endif
00450    break ;
00451    }
00452    usesspecial = 1 ;  /* now the special prolog will be sent */
00453    if (scanning && *p != '"' && (p=GetKeyVal(p, &j)) != NULL && j==0
00454        && *ValStr != '`') /* Don't bother to scan compressed files.  */
00455       scanfontcomments(ValStr) ;
00456 }
00457 
00458 int maccess P1C(char *, s)
00459 {
00460    FILE *f = search(figpath, s, "r") ;
00461    if (f)
00462       (*close_file) (f) ;
00463    return (f != 0) ;
00464 }
00465 
00466 char *tasks[] = { 0, "iff2ps", "tek2ps" } ;
00467 
00468 static char psfile[511] ; 
00469 void dospecial P1C(integer, numbytes)
00470 {
00471    register char *p = nextstring ;
00472    register int i = 0 ;
00473    int j, systemtype = 0 ;
00474    register char *q ;
00475    Boolean psfilewanted = 1 ;
00476    char *task = 0 ;
00477    char cmdbuf[111] ; 
00478 #ifdef HPS
00479 if (HPS_FLAG && PAGEUS_INTERUPPTUS) {
00480      HREF_COUNT-- ;
00481      start_new_box() ;
00482      PAGEUS_INTERUPPTUS = 0 ;
00483      }
00484 if (HPS_FLAG && NEED_NEW_BOX) {
00485        vertical_in_hps();
00486        NEED_NEW_BOX = 0;
00487        }
00488 #endif
00489    if (nextstring + numbytes > maxstring)
00490       error("! out of string space in dospecial") ;
00491    for (i=numbytes; i>0; i--)
00492 #ifdef VMCMS /* IBM: VM/CMS */
00493       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00494 #else
00495 #ifdef MVSXA /* IBM: MVS/XA */
00496       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00497 #else
00498       *p++ = (char)dvibyte() ;
00499 #endif  /* IBM: VM/CMS */
00500 #endif
00501    while (p[-1] <= ' ' && p > nextstring)
00502       p-- ; /* trim trailing blanks */
00503    if (p==nextstring) return ; /* all blank is no-op */
00504    *p = 0 ;
00505    p = nextstring ;
00506    while (*p <= ' ')
00507       p++ ;
00508 #ifdef DEBUG
00509    if (dd(D_SPECIAL))
00510       (void)fprintf(stderr, "Processing special: %s\n", p) ;
00511 #endif
00512 
00513    switch (*p) {
00514 case 'o':
00515    if (strncmp(p, "om:", 3)==0) {       /* Omega specials ignored */
00516         return;
00517    }
00518    break ;
00519 case 'e':
00520    if (strncmp(p, "em:", 3)==0) {  /* emTeX specials in emspecial.c */
00521        emspecial(p);
00522        return;
00523    }
00524    break ;
00525 case 'p':
00526    if (strncmp(p, "pos:", 4)==0) return ; /* positional specials */
00527    if (strncmp(p, "ps:", 3)==0) {
00528         psflush() ; /* now anything can happen. */
00529         if (p[3]==':') {
00530            if (strncmp(p+4, "[begin]", 7) == 0) {
00531               hvpos() ;
00532               trytobreakout(&p[11]);
00533            } else if (strncmp(p+4, "[end]", 5) == 0)
00534               trytobreakout(&p[9]);
00535            else trytobreakout(&p[4]);
00536         } else if (strncmp(p+3, " plotfile ", 10) == 0) {
00537              char *sfp ;
00538              hvpos() ;
00539              p += 13;
00540            /*
00541             *  Fixed to allow popen input for plotfile
00542             *  TJD 10/20/91
00543             */
00544            while (*p == ' ') p++;
00545            if (*p == '"') {
00546              p++;
00547              for (sfp = p; *sfp && *sfp != '"'; sfp++) ;
00548            } else {
00549              for (sfp = p; *sfp && *sfp != ' '; sfp++) ;
00550            }
00551            *sfp = '\0';
00552            if (*p == '`') 
00553              figcopyfile(p+1, 1);
00554            else
00555              figcopyfile (p, 0);
00556            /* End TJD changes */
00557         } else {
00558            hvpos() ;
00559            trytobreakout(&p[3]);
00560            psflush() ;
00561            hvpos() ;
00562         }
00563         return;
00564    }
00565    if (strncmp(p, "papersize", 9) == 0)
00566       return ;
00567 #ifdef TPIC
00568    if (strncmp(p, "pn ", 3) == 0) {setPenSize(p+2); return;}
00569    if (strncmp(p, "pa ", 3) == 0) {addPath(p+2); return;}
00570 #endif
00571    break ;
00572 case 'l':
00573    if (strncmp(p, "landscape", 9)==0) return ;
00574    break ;
00575 case '!':
00576    return ;
00577 case 'h':
00578    if (strncmp(p, "header", 6)==0) return ;
00579 #ifdef HPS
00580    if (strncmp(p, "html:", 5)==0) {
00581      if (! HPS_FLAG) return;
00582                      p += 5;
00583                      while (isspace(*p))
00584               p++;
00585                      if (*p == '<') {
00586                      char               *sp = p;
00587                      char               *str;
00588                      int                 ii=0;int len;int lower_len;
00589 
00590                      while ((*p) && (*p != '>')) {
00591                                           ii++;
00592                                           p++;
00593                       }
00594               str = (char *)mymalloc(ii+2);
00595                      strncpy(str,sp+1,ii-1);
00596               str[ii-1] = 0;len=strlen(str);
00597                             if(len>6) lower_len=6; else lower_len=len;
00598                             for(ii=0;ii<lower_len;ii++) str[ii]=tolower(str[ii]);
00599                             do_html(str);
00600                      free(str);
00601                             } else 
00602 #ifdef KPATHSEA
00603                               if (!kpse_tex_hush ("special")) 
00604 #endif
00605                                 {
00606 
00607                      printf("Error in html special\n");
00608                      return;
00609                             }
00610        return;
00611    }
00612 #else
00613    if (strncmp(p, "html:", 5)==0) return;
00614 #endif
00615 case 'w':
00616 case 'W':
00617    if (strncmp(p+1, "arning", 6) == 0) {
00618       static int maxwarns = 50 ;
00619       if (maxwarns > 0) {
00620          error(p) ;
00621          maxwarns-- ;
00622       } else if (maxwarns == 0) {
00623          error(". . . rest of warnings suppressed") ;
00624          maxwarns-- ;
00625       }
00626       return ;
00627    }
00628 #ifdef TPIC
00629    if (strcmp(p, "wh") == 0) {whitenLast(); return;}
00630 #endif
00631    break ;
00632 case 'b':
00633    if ( strncmp(p, "background", 10) == 0 )
00634       return ; /* already handled in prescan */
00635 #ifdef TPIC
00636    if (strcmp(p, "bk") == 0) {blackenLast(); return;}
00637 #endif
00638    break ;
00639 case 'c':
00640    if (strncmp(p, "color", 5) == 0) {
00641       p += 5 ;
00642       while ( *p && *p <= ' ' ) p++ ;
00643       if (strncmp(p, "push", 4) == 0 ) {
00644          p += 4 ;
00645          while ( *p && *p <= ' ' ) p++ ;
00646          pushcolor(p,1);
00647       } else if (strncmp(p, "pop", 3) == 0 ) {
00648          popcolor(1) ;
00649       } else {
00650          resetcolorstack(p,1) ;
00651       }
00652       return ;
00653    } /* IBM: color - end changes*/
00654    break ;
00655 case 'f':
00656 #ifdef TPIC
00657    if (strcmp(p, "fp") == 0) {flushPath(0); return;}
00658 #endif
00659    break ;
00660 case 'i':
00661 #ifdef TPIC
00662    if (strcmp(p, "ip") == 0) {flushPath(1); return;} /* tpic 2.0 */
00663    if (strncmp(p, "ia ", 3) == 0) {arc(p+2, 1); return;} /* tpic 2.0 */
00664 #endif
00665    break ;
00666 case 'd':
00667 #ifdef TPIC
00668    if (strncmp(p, "da ", 3) == 0) {flushDashed(p+2, 0); return;}
00669    if (strncmp(p, "dt ", 3) == 0) {flushDashed(p+2, 1); return;}
00670 #endif
00671    break ;
00672 case 's':
00673    if (strncmp(p, "src:", 4) == 0) return; /* source specials */
00674 #ifdef TPIC
00675    if (strcmp(p, "sp") == 0) {flushSpline(p+2); return;} /* tpic 2.0 */
00676    if (strncmp(p, "sp ", 3) == 0) {flushSpline(p+3); return;} /* tpic 2.0 */
00677    if (strcmp(p, "sh") == 0) {shadeLast(p+2); return;} /* tpic 2.0 */
00678    if (strncmp(p, "sh ", 3) == 0) {shadeLast(p+3); return;} /* tpic 2.0 */
00679 #endif
00680    break ;
00681 case 'a':
00682 #ifdef TPIC
00683    if (strncmp(p, "ar ", 3) == 0) {arc(p+2, 0); return;} /* tpic 2.0 */
00684 #endif
00685    break ;
00686 case 't':
00687 #ifdef TPIC
00688    if (strncmp(p, "tx ", 3) == 0) {SetShade(p+3); return;}
00689 #endif
00690    break ;
00691 case '"':
00692    hvpos() ;
00693    cmdout("@beginspecial") ;
00694    cmdout("@setspecial") ;
00695    trytobreakout(p+1) ;
00696    cmdout("\n@endspecial") ;
00697    return ;
00698    break ;
00699 default:
00700 #if 0
00701    {
00702       /* Unknown special, must return */
00703       sprintf(errbuf,"Unrecognized special (first 10 chars: %.10s)", p);
00704       specerror(errbuf);
00705       return;
00706    }
00707 #endif
00708    break ;
00709    }
00710 /* At last we get to the key/value conventions */
00711    psfile[0] = '\0';
00712    hvpos();
00713    cmdout("@beginspecial");
00714 
00715    while( (p=GetKeyVal(p,&j)) != NULL )
00716       switch (j) {
00717  case -1: /* for compatability with old conventions, we allow a file name
00718            * to be given without the 'psfile=' keyword */
00719          if (!psfile[0] && maccess(KeyStr)==0) /* yes we can read it */
00720              (void)strcpy(psfile,KeyStr) ;
00721          else {
00722            if (strlen(KeyStr) < 40) {
00723               sprintf(errbuf,
00724                       "Unknown keyword (%s) in \\special will be ignored",
00725                               KeyStr) ;
00726            } else {
00727               sprintf(errbuf,
00728                       "Unknown keyword (%.40s...) in \\special will be ignored",
00729                               KeyStr) ;
00730            }
00731            specerror(errbuf) ;
00732          }
00733          break ;
00734  case 0: case 1: case 2: /* psfile */
00735          if (psfile[0]) {
00736            sprintf(errbuf, "More than one \\special %s given; %s ignored", 
00737                     "psfile",  ValStr) ;
00738            specerror(errbuf) ;
00739          }
00740          else (void)strcpy(psfile,ValStr) ;
00741          task = tasks[j] ;
00742          break ;
00743  default: /* most keywords are output as PostScript procedure calls */
00744          if (KeyTab[j].Type == Integer)
00745             numout((integer)ValInt);
00746          else if (KeyTab[j].Type == String)
00747             for (q=ValStr; *q; q++)
00748                scout(*q) ;
00749          else if (KeyTab[j].Type == None) ;
00750          else { /* Number or Dimension */
00751             ValInt = (integer)(ValNum<0? ValNum-0.5 : ValNum+0.5) ;
00752             if (ValInt-ValNum < 0.001 && ValInt-ValNum > -0.001)
00753                 numout((integer)ValInt) ;
00754             else {
00755                (void)sprintf(cmdbuf, "%f", ValNum) ;
00756                cmdout(cmdbuf) ;
00757             }
00758          }
00759       (void)sprintf(cmdbuf, "@%s", KeyStr);
00760       cmdout(cmdbuf) ;
00761       }
00762 
00763    cmdout("@setspecial");
00764 
00765    if(psfile[0]) {
00766       if (task == 0) {
00767          systemtype = (psfile[0]=='`') ;
00768          figcopyfile(psfile+systemtype, systemtype);
00769       } else {
00770          fil2ps(task, psfile) ;
00771       }
00772    } else if (psfilewanted 
00773 #ifdef KPATHSEA
00774              && !kpse_tex_hush ("special")
00775 #endif
00776              )
00777       specerror("No \\special psfile was given; figure will be blank") ;
00778 
00779    cmdout("@endspecial");
00780 }
00781 
00782 #ifdef KPATHSEA
00783 extern char *realnameoffile;
00784 #else
00785 extern char realnameoffile[] ;
00786 extern char *pictpath ;
00787 #endif
00788 void fil2ps P2C(char *, task, char *, iname)
00789 {
00790    char cmd[400] ;
00791    FILE *f ;
00792    if (0 != (f=search(pictpath, iname, "r"))) {
00793       close_file(f) ;
00794    } else {
00795       fprintf(stderr, " couldn't open %s\n", iname) ;
00796       return ;
00797    }
00798    if (!quiet) {
00799       fprintf(stderr, " [%s", realnameoffile) ;
00800       fflush(stderr) ;
00801    }
00802    if (oname && oname[0] && oname[0] != '-') {
00803       putc(10, bitfile) ;
00804       close_file(bitfile) ;
00805       sprintf(cmd, "%s -f %s %s", task, realnameoffile, oname) ;
00806       system(cmd) ;
00807       if ((bitfile=fopen(oname, FOPEN_ABIN_MODE))==NULL)
00808          error_with_perror ("! couldn't reopen PostScript file", oname) ;
00809       linepos = 0 ;
00810    } else {
00811       sprintf(cmd, "%s -f %s", task, realnameoffile) ;
00812       system(cmd) ;
00813    }
00814    if (!quiet)
00815       fprintf(stderr, "]") ;
00816 }
00817 
00818 /*
00819  *   Handles specials encountered during bounding box calculations.
00820  *   Currently we only deal with psfile's or PSfiles and only those
00821  *   that do not use rotations.
00822  */
00823 static float rbbox[4] ;
00824 float *bbdospecial P1C(int, nbytes)
00825 {
00826    char *p = nextstring ;
00827    int i, j ;
00828    char seen[NKEYS] ;
00829    float valseen[NKEYS] ;
00830 
00831    if (nextstring + nbytes > maxstring) {
00832       p = nextstring = mymalloc(1000 + 2 * nbytes) ;
00833       maxstring = nextstring + 2 * nbytes + 700 ;
00834    }
00835    if (nextstring + nbytes > maxstring)
00836       error("! out of string space in bbdospecial") ;
00837    for (i=nbytes; i>0; i--)
00838 #ifdef VMCMS /* IBM: VM/CMS */
00839       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00840 #else
00841 #ifdef MVSXA /* IBM: MVS/XA */
00842       *p++ = ascii2ebcdic[(char)dvibyte()] ;
00843 #else
00844       *p++ = (char)dvibyte() ;
00845 #endif  /* IBM: VM/CMS */
00846 #endif
00847    while (p[-1] <= ' ' && p > nextstring)
00848       p-- ; /* trim trailing blanks */
00849    if (p==nextstring) return NULL ; /* all blank is no-op */
00850    *p = 0 ;
00851    p = nextstring ;
00852    while (*p && *p <= ' ')
00853       p++ ;
00854    if (strncmp(p, "psfile", 6)==0 || strncmp(p, "PSfile", 6)==0) {
00855       float originx = 0, originy = 0, hscale = 1, vscale = 1,
00856             hsize = 0, vsize = 0 ;
00857       for (j=0; j<NKEYS; j++)
00858          seen[j] = 0 ;
00859       j = 0 ;
00860       while ((p=GetKeyVal(p, &j))) {
00861          if (j >= 0 && j < NKEYS && KeyTab[j].Type == Number) {
00862            seen[j]++ ;
00863            valseen[j] = ValNum ;
00864          }
00865       }
00866       /*
00867        *   This code mimics what happens in @setspecial.
00868        */
00869       if (seen[3])
00870          hsize = valseen[3] ;
00871       if (seen[4])
00872          vsize = valseen[4] ;
00873       if (seen[5])
00874          originx = valseen[5] ;
00875       if (seen[6])
00876          originy = valseen[6] ;
00877       if (seen[7])
00878          hscale = valseen[7] / 100.0 ;
00879       if (seen[8])
00880          vscale = valseen[8] / 100.0 ;
00881       if (seen[10] && seen[12])
00882          hsize = valseen[12] - valseen[10] ;
00883       if (seen[11] && seen[13])
00884          vsize = valseen[13] - valseen[11] ;
00885       if (seen[14] || seen[15]) {
00886          if (seen[14] && seen[15] == 0) {
00887            hscale = vscale = valseen[14] / (10.0 * hsize) ;
00888          } else if (seen[15] && seen[14] == 0) {
00889            hscale = vscale = valseen[15] / (10.0 * vsize) ;
00890          } else {
00891             hscale = valseen[14] / (10.0 * hsize) ;
00892             vscale = valseen[15] / (10.0 * vsize) ;
00893          }
00894       }
00895       /* at this point, the bounding box in PostScript units relative to
00896          the current dvi point is
00897            originx originy originx+hsize*hscale originy+vsize*vscale
00898          We'll let the bbox routine handle the remaining math.
00899        */
00900       rbbox[0] = originx ;
00901       rbbox[1] = originy ;
00902       rbbox[2] = originx+hsize*hscale ;
00903       rbbox[3] = originy+vsize*vscale ;
00904       return rbbox ;
00905    }
00906    return 0 ;
00907 }