Back to index

tetex-bin  3.0
resident.c
Go to the documentation of this file.
00001 /*   For use with emTeX set FONTPATH to "TEXTFM"
00002  */
00003 #ifndef FONTPATH
00004 #define FONTPATH "TEXFONTS"
00005 #endif
00006 
00007 /*
00008  *   This code reads in and handles the defaults for the program from the
00009  *   file config.sw.  This entire file is a bit kludgy, sorry.
00010  */
00011 #include "dvips.h" /* The copyright notice in that file is included too! */
00012 #include "paths.h"
00013 #ifdef KPATHSEA
00014 #include <kpathsea/c-ctype.h>
00015 #include <kpathsea/c-pathch.h>
00016 #include <kpathsea/c-stat.h>
00017 #include <kpathsea/pathsearch.h>
00018 #include <kpathsea/tex-file.h>
00019 #include <kpathsea/variable.h>
00020 #endif
00021 /*
00022  *   This is the structure definition for resident fonts.  We use
00023  *   a small and simple hash table to handle these.  We don't need
00024  *   a big hash table.
00025  */
00026 struct resfont *reshash[RESHASHPRIME] ;
00027 /*
00028  *   These are the external routines we use.
00029  */
00030 #include "protos.h"
00031 /*
00032  *   These are the external variables we use.
00033  */
00034 extern char *realnameoffile ;
00035 #ifdef DEBUG
00036 extern integer debug_flag;
00037 #endif  /* DEBUG */
00038 extern integer pagecopies ;
00039 extern int overridemag ;
00040 extern long bytesleft ;
00041 extern quarterword *raster ;
00042 extern FILE *pkfile ;
00043 extern char *oname ;
00044 extern integer swmem, fontmem ;
00045 #ifndef KPATHSEA
00046 extern char *tfmpath, *pictpath ;
00047 extern char *pkpath ;
00048 extern char *vfpath ;
00049 extern char *figpath ;
00050 extern char *configpath ;
00051 extern char *headerpath ;
00052 #ifdef SEARCH_SUBDIRECTORIES
00053 extern char *fontsubdirpath ;
00054 #endif
00055 #endif
00056 extern Boolean noenv ;
00057 extern Boolean downloadpspk ;
00058 #ifdef FONTLIB
00059 extern char *flipath, *fliname ;
00060 #endif
00061 extern char *paperfmt ; 
00062 extern char *nextstring ;
00063 extern char *maxstring ;
00064 extern char *warningmsg ;
00065 extern Boolean disablecomments ;
00066 extern Boolean compressed ;
00067 extern Boolean partialdownload ;
00068 extern int quiet ;
00069 extern int filter ;
00070 extern Boolean reverse ;
00071 extern Boolean usesPSfonts ;
00072 extern Boolean nosmallchars ;
00073 extern Boolean removecomments ;
00074 extern Boolean safetyenclose ;
00075 extern Boolean dopprescan ;
00076 extern integer maxsecsize ;
00077 extern double mag ;
00078 extern Boolean sepfiles ;
00079 extern int actualdpi ;
00080 extern int vactualdpi ;
00081 extern int maxdrift ;
00082 extern int vmaxdrift ;
00083 extern char *printer ;
00084 extern char *mfmode, *mflandmode ;
00085 extern int mfmode_option;
00086 extern int oname_option;
00087 extern Boolean sendcontrolD ;
00088 #ifdef SHIFTLOWCHARS
00089 extern Boolean shiftlowchars ;
00090 #endif
00091 extern unsigned lastresortsizes[] ;
00092 extern integer hoff, voff ;
00093 extern struct papsiz *papsizes ;
00094 extern Boolean secure ;
00095 extern integer hpapersize, vpapersize ;
00096 extern int landscape ;
00097 /*
00098  *   To maintain a list of document fonts, we use the following
00099  *   pointer.
00100  */
00101 struct header_list *ps_fonts_used ;
00102 /*
00103  *   Our hash routine.
00104  */
00105 int
00106 hash P1C(char *, s)
00107 {
00108    int h = 12 ;
00109 
00110    while (*s != 0)
00111       h = (h + h + *s++) % RESHASHPRIME ;
00112    return(h) ;
00113 }
00114 /*
00115  *   Reverse the hash chains.
00116  */
00117 void
00118 revpslists P1H(void) {
00119    register int i ;
00120    for (i=0; i<RESHASHPRIME; i++)
00121       reshash[i] = (struct resfont *)revlist(reshash[i]) ;
00122 }
00123 /*
00124  *   cleanres() marks all resident fonts as not being yet sent, except
00125  *   those marked with 2 meaning they were downloaded as part of the
00126  *   main prolog (not section prolog).
00127  */
00128 void
00129 cleanres P1H(void) {
00130    register int i ;
00131    register struct resfont *p ;
00132    for (i=0; i<RESHASHPRIME; i++)
00133       for (p=reshash[i]; p; p=p->next)
00134          if (p->sent == 1)
00135             p->sent = 0 ;
00136 }
00137 /*
00138  *   The routine that looks up a font name.
00139  */
00140 struct resfont *
00141 lookup P1C(char *, name)
00142 {
00143    struct resfont *p ;
00144 
00145    for (p=reshash[hash(name)]; p!=NULL; p=p->next)
00146       if (strcmp(p->Keyname, name)==0)
00147          return(p) ;
00148    return(NULL) ;
00149 }
00150 
00151 struct resfont *
00152 findPSname P1C(char *, name)
00153 {
00154    register int i ;
00155    register struct resfont *p ;
00156    for (i=0; i<RESHASHPRIME; i++)
00157       for (p=reshash[i]; p; p=p->next) {
00158          if (strcmp(p->PSname, name)==0)
00159             return p;
00160       }
00161    return NULL;
00162 }
00163 
00164 /*
00165  *   This routine adds an entry.
00166  */
00167 void
00168 add_entry P6C(char *, TeXname, char *, PSname, char *, Fontfile,
00169              char *, Vectfile, char *, specinfo, char *, downloadinfo)
00170 {
00171    struct resfont *p ;
00172    int h ;
00173    if (PSname == NULL)
00174       PSname = TeXname ;
00175    p = (struct resfont *)mymalloc((integer)sizeof(struct resfont)) ;
00176    p->Keyname = TeXname ;
00177    p->PSname = PSname ;
00178    p->Fontfile = Fontfile;
00179    p->Vectfile = Vectfile;
00180    p->TeXname = TeXname ;
00181    p->specialinstructions = specinfo ;
00182    if (downloadinfo && *downloadinfo)
00183       p->downloadheader = downloadinfo ;
00184    else
00185       p->downloadheader = 0 ;
00186    h = hash(TeXname) ;
00187    p->next = reshash[h] ;
00188    p->sent = 0 ;
00189    reshash[h] = p ;
00190 }
00191 /*
00192  *   Now our residentfont routine.  Returns the number of characters in
00193  *   this font, based on the TFM file.
00194  */
00195 extern char *infont ;
00196 int
00197 residentfont P1C(register fontdesctype *, curfnt)
00198 {
00199    register shalfword i ;
00200    struct resfont *p ;
00201 
00202 /*
00203  *   First we determine if we can find this font in the resident list.
00204  */
00205    if (*curfnt->area)
00206       return 0 ; /* resident fonts never have a nonstandard font area */
00207    if ((p=lookup(curfnt->name))==NULL)
00208       return 0 ;
00209 /*
00210  *   This is not yet the correct way to do things, but it is useful as it
00211  *   is so we leave it in.  The problem:  if resident Times-Roman is
00212  *   re-encoded, then it will be downloaded as bitmaps; this is not
00213  *   right.  The solution will be to introduce two types of `<'
00214  *   directives, one that downloads fonts and one that downloads
00215  *   short headers that are innocuous.
00216  */
00217    if (p->Fontfile && downloadpspk) {
00218 #ifdef DEBUG
00219       if (dd(D_FONTS))
00220          (void)fprintf(stderr,"Using PK font %s for <%s>.\n",
00221                                      curfnt->name, p->PSname) ;
00222 #endif  /* DEBUG */
00223       return 0 ;
00224    }
00225 /*
00226  *   We clear out some pointers:
00227  */
00228 #ifdef DEBUG
00229    if (dd(D_FONTS))
00230         (void)fprintf(stderr,"Font %s <%s> is resident.\n",
00231                                      curfnt->name, p->PSname) ;
00232 #endif  /* DEBUG */
00233    curfnt->resfont = p ;
00234    curfnt->name = p->TeXname ;
00235    for (i=0; i<256; i++) {
00236       curfnt->chardesc[i].TFMwidth = 0 ;
00237       curfnt->chardesc[i].packptr = NULL ;
00238       curfnt->chardesc[i].pixelwidth = 0 ;
00239       curfnt->chardesc[i].flags = 0 ;
00240       curfnt->chardesc[i].flags2 = 0 ;
00241    }
00242    add_name(p->PSname, &ps_fonts_used) ;
00243 /*
00244  *   We include the font here.  But we only should need to include the
00245  *   font if we have a stupid spooler; smart spoolers should be able
00246  *   to supply it automatically.
00247  */
00248    if (p->downloadheader) {
00249       char *cp = p->downloadheader ;
00250       char *q ;
00251 
00252       infont = p->PSname ;
00253       while (1) {
00254          q = cp ;
00255          while (*cp && *cp != ' ')
00256             cp++ ;
00257          if (*cp) {
00258             *cp = 0 ;
00259             add_header(q) ;
00260             *cp++ = ' ' ;
00261          } else {
00262 /*          if (strstr(q,".pfa")||strstr(q,".pfb")||
00263                 strstr(q,".PFA")||strstr(q,".PFB"))
00264                break ;
00265             else */ {
00266               add_header(q) ;
00267               break;
00268             }
00269          }
00270          infont = 0 ;
00271       }
00272       infont = 0 ;
00273    }
00274    i = tfmload(curfnt) ;
00275    if (i < 0)
00276       i = 1 ;
00277    usesPSfonts = 1 ;
00278    return(i) ;
00279 }
00280 #define INLINE_SIZE (2000)
00281 static char was_inline[INLINE_SIZE] ;
00282 static unsigned c_lineno;
00283 void
00284 bad_config P1C(char *, err)
00285 {
00286    fprintf (stderr, "%s:%d:", realnameoffile, c_lineno);
00287    error (err);
00288    fprintf(stderr, " (%s)\n", was_inline) ;
00289 }
00290 
00291 #ifndef KPATHSEA
00292 /*
00293  *   Get environment variables! These override entries in ./config.h.
00294  *   We substitute everything of the form ::, ^: or :$ with default,
00295  *   so a user can easily build on to the existing paths.
00296  */
00297 static char *getpath P2C(char *, who, char *, what)
00298 {
00299    if (who) {
00300       register char *pp, *qq ;
00301       int lastsep = 1 ;
00302 
00303       for (pp=nextstring, qq=who; *qq;) {
00304          if (*qq == PATHSEP) {
00305             if (lastsep) {
00306                strcpy(pp, what) ;
00307                pp = pp + strlen(pp) ;
00308             }
00309             lastsep = 1 ;
00310          } else
00311             lastsep = 0 ;
00312          *pp++ = *qq++ ;
00313       }
00314       if (lastsep) {
00315          strcpy(pp, what) ;
00316          pp = pp + strlen(pp) ;
00317       }
00318       *pp = 0 ;
00319       qq = nextstring ;
00320       nextstring = pp + 1 ;
00321       return qq ;
00322    } else
00323       return what ;
00324 }
00325 #endif
00326 /*
00327  *   We use this function so we can support strings delimited by
00328  *   double quotes with spaces in them.  We also accept strings
00329  *   with spaces in them, but kill off any spaces at the end.
00330  */
00331 char *configstring P2C(char *, s, int, nullok)
00332 {
00333    char tstr[INLINE_SIZE] ;
00334    char *p = tstr ;
00335 
00336    while (*s && *s <= ' ')
00337       s++ ;
00338    if (*s == '"') {
00339       s++ ;
00340       while (*s != 10 && *s != 0 && *s != '"' && p < tstr+290)
00341          *p++ = *s++ ;
00342    } else {
00343       while (*s && p < tstr+290)
00344          *p++ = *s++ ;
00345       while (*(p-1) <= ' ' && p > tstr)
00346          p-- ;
00347    }
00348    *p = 0 ;
00349    if (p == tstr && ! nullok)
00350       bad_config("bad string") ;
00351    return newstring(tstr) ;
00352 }
00353 #ifdef KPATHSEA
00354 /* We use this in `getdefaults' to modify the kpathsea structure for the
00355    paths we read.  See kpathsea/tex-file.[ch].  */
00356 #define SET_CLIENT_PATH(filefmt, val) \
00357   kpse_format_info[filefmt].client_path = xstrdup (val)
00358 #endif
00359 /*
00360  *   Now we have the getdefaults routine.
00361  */
00362 char *psmapfile = PSMAPFILE ;
00363 Boolean
00364 getdefaults P1C(char *, s)
00365 {
00366    FILE *deffile ;
00367    char PSname[INLINE_SIZE] ;
00368    register char *p ;
00369    integer hsiz, vsiz ;
00370 #ifndef KPATHSEA
00371    char *d = configpath ;
00372    int i, j ;
00373 #endif
00374    int canaddtopaper = 0 ;
00375 
00376    if (printer == NULL) {
00377       if (s) {
00378          strcpy(PSname, s) ;
00379       } else {
00380 #ifdef KPATHSEA
00381          char *dvipsrc = kpse_var_value ("DVIPSRC");
00382 #ifdef WIN32
00383         if (dvipsrc && *dvipsrc) {
00384           /* $DVIPSRC was set by user */
00385           strcpy(PSname, dvipsrc);
00386         }
00387         else 
00388           /* No env var, looking into some kind of standard path. */
00389           if (SearchPath(".;%HOME%;c:\\", ".dvipsrc", NULL,
00390                        INLINE_SIZE, PSname, 
00391                        &dvipsrc) == 0) {
00392             /* search failed, we must put something into PSname. */
00393             dvipsrc = kpse_var_expand(DVIPSRC);
00394             if (dvipsrc) {
00395               strcpy(PSname, dvipsrc);
00396               free(dvipsrc);
00397             }
00398             /* Else SearchPath has filled PSname with something */
00399           }
00400         /* remove any redundant path separators. Many configurations
00401            can show  up: c:\/.dvipsrc and so on ... */         
00402         { 
00403           char *p, *q;
00404           for (p = q = PSname; *p && (p - PSname < INLINE_SIZE) ; 
00405               p++, q++) {
00406             if (IS_DIR_SEP(*p)) {
00407               *q = DIR_SEP; p++; q++;
00408               while (*p && IS_DIR_SEP(*p)) p++;
00409             }
00410             *q = *p;
00411           }
00412           *q = '\0';
00413         }
00414 #else
00415          if(!dvipsrc) dvipsrc = kpse_var_expand(DVIPSRC) ;
00416          strcpy(PSname, dvipsrc ? dvipsrc : "~/.dvipsrc") ;
00417          if(dvipsrc) free(dvipsrc) ;
00418 #endif /* WIN32 */
00419         
00420 #else /* ! KPATHSEA */
00421 #ifndef VMCMS  /* IBM: VM/CMS - don't have home directory on VMCMS */
00422 #ifndef MVSXA
00423          d = "~" ;
00424 #endif
00425 #endif  /* IBM: VM/CMS */
00426          strcpy(PSname, DVIPSRC) ;
00427 #endif /* KPATHSEA */
00428       }
00429    } else {
00430 #if defined(MSDOS) || defined(OS2)
00431       strcpy(PSname, printer) ;
00432       strcat(PSname, ".cfg") ;
00433 #else
00434       strcpy(PSname, "config.") ;
00435       strcat(PSname, printer) ;
00436 #endif
00437    }
00438 #ifdef KPATHSEA
00439    if ((deffile=search(configpath,PSname,READ))!=NULL) {
00440 #else
00441    if ((deffile=search(d,PSname,READ))!=NULL) {
00442 #endif
00443 #ifdef DEBUG
00444      if (dd (D_CONFIG)) {
00445        fprintf (stderr, "Reading dvips config file `%s':\n", realnameoffile);
00446      }
00447 #endif
00448      c_lineno = 0;
00449      while (fgets(was_inline, INLINE_SIZE, deffile)!=NULL) {
00450        c_lineno++;
00451 #ifdef DEBUG
00452        if (dd (D_CONFIG)) {
00453          fprintf (stderr, "%s:%d:%s", realnameoffile, c_lineno, was_inline);
00454        }
00455 #endif
00456 /*
00457  *   We need to get rid of the newline.
00458  */
00459        for (p=was_inline; *p; p++) ;
00460        while (p > was_inline && (*(p-1) == '\n' || *(p-1) == '\r')) {
00461           *--p = '\0' ;
00462        }
00463        if (was_inline[0] != '@')
00464           canaddtopaper = 0 ;
00465        switch (was_inline[0]) {
00466 /*
00467  *   Handling paper size information:
00468  *
00469  *      If line is empty, then we clear out the paper size information
00470  *      we have so far.
00471  *
00472  *      If it is `@+', then we add to the current paper size info.
00473  *
00474  *      If it is `name hsize vsize', then we start a new definition.
00475  */
00476 case '@' :
00477          p = was_inline + 1 ;
00478          while (*p && *p <= ' ') p++ ;
00479          if (*p == 0) {
00480             papsizes = 0 ; /* throw away memory */
00481          } else if (*p == '+') {
00482             if (canaddtopaper == 0)
00483                error(
00484       " @+ in config files must immediately following a @ lines") ;
00485             else {
00486                *(nextstring-1) = '\n' ;/* IBM: VM/CMS - changed 10 to "\n" */
00487                p++ ;
00488                while (*p && *p == ' ') p++ ;
00489                strcpy(nextstring, p) ;
00490                nextstring += strlen(p) + 1 ;
00491             }
00492          } else {
00493             struct papsiz *ps ;
00494             
00495             ps = (struct papsiz *)mymalloc((integer)sizeof(struct papsiz)) ;
00496             ps->next = papsizes ;
00497             papsizes = ps ;
00498             ps->name = p ;
00499             while (*p && *p > ' ')
00500                p++ ;
00501             *p++ = 0 ;
00502             ps->name = newstring(ps->name) ;
00503             while (*p && *p <= ' ') p++ ;
00504             handlepapersize(p, &hsiz, &vsiz) ;
00505             ps->xsize = hsiz ;
00506             ps->ysize = vsiz ;
00507             ps->specdat = nextstring++ ;
00508             *(ps->specdat) = 0 ;
00509             canaddtopaper = 1 ;
00510          }
00511          break ;
00512 case 'a' :
00513          dopprescan = (was_inline[1] != '0') ;
00514          break ;
00515 case 'b':
00516 #ifdef SHORTINT
00517          if (sscanf(was_inline+1, "%ld", &pagecopies) != 1) 
00518           bad_config("missing pagecopies to b") ;
00519 #else
00520          if (sscanf(was_inline+1, "%d", &pagecopies) != 1) 
00521           bad_config("missing pagecopies to b") ;
00522 #endif
00523          if (pagecopies < 1 || pagecopies > 1000)
00524             bad_config("pagecopies not between 1 and 1000") ;
00525          break ;
00526 case 'm' :
00527 #ifdef SHORTINT
00528          if (sscanf(was_inline+1, "%ld", &swmem) != 1) 
00529           bad_config("missing swmem to m") ;
00530 #else   /* ~SHORTINT */
00531          if (sscanf(was_inline+1, "%d", &swmem) != 1)
00532           bad_config("missing swmem to m") ;
00533 #endif  /* ~SHORTINT */
00534          swmem += fontmem ; /* grab headers we've seen already */
00535          break ;
00536 case 'M' :
00537          /* If the user specified a -mode, don't replace it.  */
00538          if (!mfmode_option)
00539           mfmode = configstring(was_inline+1, 0) ;
00540          mflandmode = 0 ;
00541          {
00542             char *pp ;
00543             for (pp=mfmode; pp && *pp>' '; pp++) ;
00544             if (pp && *pp == ' ') {
00545                *pp++ = 0 ;
00546                while (*pp && *pp <= ' ')
00547                   pp++ ;
00548                if (*pp)
00549                   mflandmode = pp ;
00550             }
00551          }
00552          break ;
00553 case 'o' :
00554         if (!oname_option) {
00555            struct stat st_buf;
00556            oname = configstring(was_inline+1, 1) ;
00557            if ((*oname && oname[strlen(oname)-1] == ':')
00558                || (stat(oname, &st_buf) == 0 && S_ISCHR(st_buf.st_mode))) {
00559               sendcontrolD = 1 ; /* if we send to a device, *we* are spooler */
00560 #if defined(MSDOS) || defined(OS2)
00561               oname[strlen(oname)-1] = 0 ;
00562 #endif
00563            }
00564         }
00565          break ;
00566 case 'F' :
00567          sendcontrolD = (was_inline[1] != '0') ;
00568          break ;
00569 case 'O' :
00570          p = was_inline + 1 ;
00571          handlepapersize(p, &hoff, &voff) ;
00572          break ;
00573 #ifdef FONTLIB
00574 case 'L' : 
00575          {
00576             char tempname[INLINE_SIZE] ;
00577             extern char *fliparse() ;
00578             if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config("missing arg to L") ;
00579             else {
00580                flipath = getpath(fliparse(PSname,tempname), flipath);
00581                fliname = newstring(tempname) ;
00582             }
00583         }
00584          break ;
00585 #endif
00586 case 'T' : 
00587          if (sscanf(was_inline+1, "%s", PSname) != 1)
00588           bad_config("missing arg to T") ;
00589          else
00590 #ifdef KPATHSEA
00591           SET_CLIENT_PATH (kpse_tfm_format, PSname);
00592 #else
00593           tfmpath = getpath(PSname, tfmpath) ;
00594 #endif
00595          break ;
00596 case 'P' :
00597          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config("missing arg to P") ;
00598          else 
00599 #ifdef KPATHSEA
00600           SET_CLIENT_PATH (kpse_pk_format, PSname);
00601 #else
00602           pkpath = getpath(PSname, pkpath) ;
00603 #endif
00604          break ;
00605 case 'p' :
00606          p = was_inline + 1 ;
00607          while (*p && *p <= ' ')
00608             p++ ;
00609          if (*p == '+') {
00610             if (sscanf(p+1, "%s", PSname) != 1)
00611               bad_config("missing arg to p") ;
00612             getpsinfo(PSname) ;
00613          } else {
00614             psmapfile = configstring(was_inline+1, 0) ;
00615          }
00616          break ;
00617 case 'v' : case 'V' :
00618          if (sscanf(was_inline+1, "%s", PSname) != 1) 
00619           bad_config("missing arg to V") ;
00620          else 
00621 #ifdef KPATHSEA
00622           SET_CLIENT_PATH (kpse_vf_format, PSname);
00623 #else
00624           vfpath = getpath(PSname, vfpath) ;
00625 #endif
00626          break ;
00627 case 'S' :
00628          if (sscanf(was_inline+1, "%s", PSname) != 1) 
00629           bad_config("missing arg to S") ;
00630          else
00631 #ifdef KPATHSEA
00632           SET_CLIENT_PATH (kpse_pict_format, PSname);
00633 #else
00634           figpath = getpath(PSname, figpath) ;
00635 #endif
00636          break ;
00637 case 's':
00638          safetyenclose = 1 ;
00639          break ;
00640 case 'H' : 
00641          if (sscanf(was_inline+1, "%s", PSname) != 1) 
00642           bad_config("missing arg to H") ;
00643          else 
00644 #ifdef KPATHSEA
00645           SET_CLIENT_PATH (headerpath, PSname);
00646 #else
00647           headerpath = getpath(PSname, headerpath) ;
00648 #endif
00649          break ;
00650 case '%': case ' ' : case '*' : case '#' : case ';' :
00651 case '=' : case 0 : case '\n' :
00652          break ;
00653 case 'r' :
00654          reverse = (was_inline[1] != '0') ;
00655          break ;
00656 /*
00657  *   This case is for last resort font scaling; I hate this, but enough
00658  *   people have in no uncertain terms demanded it that I'll go ahead and
00659  *   add it.
00660  *
00661  *   This line must have numbers on it, resolutions, to search for the
00662  *   font as a last resort, and then the font will be scaled.  These
00663  *   resolutions should be in increasing order.
00664  *
00665  *   For most machines, just `300' is sufficient here; on the NeXT,
00666  *   `300 400' may be more appropriate.
00667  */
00668 case 'R':
00669 #ifndef KPATHSEA
00670          i = 0 ;
00671          p = was_inline + 1 ;
00672          while (*p) {
00673             while (*p && *p <= ' ')
00674                p++ ;
00675             if ('0' <= *p && *p <= '9') {
00676                j = 0 ;
00677                while ('0' <= *p && *p <= '9')
00678                   j = 10 * j + (*p++ - '0') ;
00679                if (i > 0)
00680                   if (lastresortsizes[i-1] > j) {
00681                      bad_config("last resort sizes (R) must be sorted") ;
00682                   }
00683                lastresortsizes[i++] = j ;
00684             } else {
00685                if (*p == 0)
00686                   break ;
00687                bad_config("only numbers expected on `R' line") ;
00688             }
00689          }
00690          lastresortsizes[i] = 32000 ;
00691 #else /* KPATHSEA */
00692         for (p = was_inline + 1; *p; p++) {
00693           if (isblank (*p)) {
00694             *p = ':';
00695           }
00696         }
00697          kpse_fallback_resolutions_string = xstrdup (was_inline + 1);
00698 #endif
00699          break ;
00700 case 'D' :
00701          if (sscanf(was_inline+1, "%d", &actualdpi) != 1)
00702            bad_config("missing arg to D") ;
00703          if (actualdpi < 10 || actualdpi > 10000)
00704            bad_config("dpi must be between 10 and 10000") ;
00705         vactualdpi = actualdpi;
00706          break ;
00707 /*
00708  *   Execute a command.  This can be dangerous, but can also be very useful.
00709  */
00710 case 'E' :
00711 #ifdef SECURE
00712          error("dvips was compiled with SECURE, which disables E in config") ;
00713 #else
00714          if (secure) {
00715             error("dvips -R option used, which disables E in config") ;
00716             break ;
00717          }
00718          (void)system(was_inline+1) ;
00719 #endif
00720          break ;
00721 case 'K':
00722          removecomments = (was_inline[1] != '0') ;
00723          break ;
00724 case 'U':
00725          nosmallchars = (was_inline[1] != '0') ;
00726          break ;
00727 case 'W':
00728          for (p=was_inline+1; *p && *p <= ' '; p++) ;
00729          if (*p)
00730             warningmsg = newstring(p) ;
00731          else
00732             warningmsg = 0 ;
00733          break ;
00734 case 'X' :
00735          if (sscanf(was_inline+1, "%d", &actualdpi) != 1)
00736            bad_config("missing numeric arg to X") ;
00737          if (actualdpi < 10 || actualdpi > 10000)
00738            bad_config("X arg must be between 10 and 10000") ;
00739          break ;
00740 case 'Y' :
00741          if (sscanf(was_inline+1, "%d", &vactualdpi) != 1)
00742            bad_config("missing numeric arg to Y") ;
00743          if (vactualdpi < 10 || vactualdpi > 10000)
00744            bad_config("Y arg must be between 10 and 10000") ;
00745          break ;
00746 case 'x': case 'y':
00747          if (sscanf(was_inline+1, "%lg", &mag) != 1) 
00748           bad_config("missing arg to x or y") ;
00749          overridemag = (was_inline[0] == 'x') ? 1 : -1 ;
00750          break ;
00751 case 'e' :
00752          if (sscanf(was_inline+1, "%d", &maxdrift) != 1)
00753            bad_config("missing arg to e") ;
00754          if (maxdrift < 0) bad_config("bad argument to e") ;
00755         vmaxdrift = maxdrift;
00756          break ;
00757 case 'z' : 
00758          secure = (was_inline[1] != '0') ;
00759          break ;
00760 case 'q' : case 'Q' :
00761          quiet = (was_inline[1] != '0') ;
00762          break ;
00763 case 'f' :
00764          filter = (was_inline[1] != '0') ;
00765         if (filter)
00766           oname = "";
00767         /* noenv has already been tested, so no point in setting.  */
00768         sendcontrolD = 0;
00769          break ;
00770 #ifdef SHIFTLOWCHARS
00771 case 'G':
00772          shiftlowchars = (was_inline[1] != '0') ;
00773          break ;
00774 #endif
00775 case 'h' : 
00776          if (sscanf(was_inline+1, "%s", PSname) != 1)
00777            bad_config("missing arg to h") ;
00778          else (void)add_header(PSname) ;
00779          break ;
00780 case 'i' :
00781          if (sscanf(was_inline+1, "%d", &maxsecsize) != 1)
00782             maxsecsize = 0 ;
00783          sepfiles = 1 ;
00784          break ;
00785 case 'I':
00786          noenv = (was_inline[1] != '0') ;
00787          break ;
00788 case 'N' :
00789          disablecomments = (was_inline[1] != '0') ;
00790          break ;
00791 case 'Z' :
00792          compressed = (was_inline[1] != '0') ;
00793          break ;
00794 case 'j':
00795          partialdownload = (was_inline[1] != '0') ;
00796          break ;
00797 case 't' :
00798          if (sscanf(was_inline+1, "%s", PSname) != 1)
00799            bad_config("missing arg to t") ;
00800          else {
00801            if (strcmp(PSname, "landscape") == 0) {
00802                if (hpapersize || vpapersize)
00803                   error(
00804             "both landscape and papersize specified; ignoring landscape") ;
00805                else
00806                   landscape = 1 ;
00807             } else
00808                paperfmt = newstring(PSname) ;
00809          }
00810          break ;
00811 default:
00812          bad_config("strange line") ;
00813       }
00814      }
00815      (void)fclose(deffile) ;
00816    } else {
00817       if (printer)
00818         {
00819           char msg[1000];
00820           sprintf (msg, "warning: no config file for `%s'", printer);
00821           error(msg);
00822           return 0;
00823         }
00824    }
00825   
00826   return 1;
00827 }
00828 
00829 /*
00830 *   If a character pointer is passed in, use that name; else, use the
00831 *   default (possibly set) name, psfonts.map.
00832 */
00833 void getpsinfo P1C(char *, name)
00834 {
00835     FILE *deffile ;
00836     register char *p ;
00837     char *specinfo, *downloadinfo ;
00838    char downbuf[500] ;
00839    char specbuf[500] ;
00840    int slen ;
00841 
00842    if (name == 0)
00843       name = psmapfile ;
00844    if ((deffile=search(mappath, name, READ))!=NULL) {
00845       while (fgets(was_inline, INLINE_SIZE, deffile)!=NULL) {
00846          p = was_inline ;
00847          if (*p > ' ' && *p != '*' && *p != '#' && *p != ';' && *p != '%') {
00848             char *TeXname = NULL ;
00849             char *PSname = NULL ;
00850             char *Fontfile = NULL;
00851             char *Vectfile = NULL;
00852             char *hdr_name = NULL;
00853             boolean nopartial_p = false;
00854             boolean encoding_p = false;
00855             specinfo = NULL ;
00856             downloadinfo = NULL ;
00857             downbuf[0] = 0 ;
00858             specbuf[0] = 0 ;
00859             while (*p) {
00860                encoding_p = false ;
00861                while (*p && *p <= ' ')
00862                   p++ ;
00863                if (*p) {
00864                   if (*p == '"') {             /* PostScript instructions? */
00865                      if (specinfo) {
00866                         strcat(specbuf, specinfo) ;
00867                         strcat(specbuf, " ") ;
00868                      }
00869                      specinfo = p + 1 ;
00870 
00871                   } else if (*p == '<') {    /* Header to download? */
00872                      /* If had previous downloadinfo, save it.  */
00873                      if (downloadinfo) {
00874                         strcat(downbuf, downloadinfo) ;
00875                         strcat(downbuf, " ") ;
00876                         downloadinfo = NULL;
00877                      }
00878                      if (p[1] == '<') {     /* << means always full download */
00879                        p++;
00880                        nopartial_p = true;
00881                      } else if (p[1] == '[') { /* <[ means an encoding */
00882                        p++;
00883                        encoding_p = true;
00884                      }
00885                      p++ ;
00886                      /* skip whitespace after < */
00887                      while (*p && *p <= ' ')
00888                        p++;
00889                      
00890                      /* save start of header name */
00891                      hdr_name = p ;
00892 
00893                   } else if (TeXname) /* second regular word on line? */
00894                      PSname = p ;
00895 
00896                   else                /* first regular word? */
00897                      TeXname = p ;
00898 
00899                   if (*p == '"') {
00900                      p++ ;            /* find end of "..." word */
00901                      while (*p != '"' && *p)
00902                         p++ ;
00903                   } else
00904                      while (*p > ' ') /* find end of anything else */
00905                         p++ ;
00906                   if (*p)
00907                      *p++ = 0 ;
00908 
00909                   /* If we had a header we were downloading, figure
00910                      out what to do; couldn't do this above since we
00911                      want to check the suffix.  */
00912                   if (hdr_name) {
00913                      char *suffix = find_suffix (hdr_name);
00914                      if (encoding_p || STREQ (suffix, "enc")) {
00915                         /* (SPQR) if it is a reencoding, pass on to
00916                            FontPart, and download as usual */
00917                         Vectfile = downloadinfo = hdr_name;
00918                      } else if (nopartial_p) {
00919                         downloadinfo = hdr_name ;
00920                    } else if       (FILESTRCASEEQ (suffix, "pfa")
00921                              || FILESTRCASEEQ (suffix, "pfb")
00922                              || STREQ (suffix, "PFA")
00923                              || STREQ (suffix, "PFB")) {
00924                      Fontfile = hdr_name;
00925                    } else {
00926                         downloadinfo = hdr_name;
00927                      }
00928                   }
00929                }
00930             }
00931             if (specinfo)
00932                strcat(specbuf, specinfo) ;
00933             if (downloadinfo)
00934                strcat(downbuf, downloadinfo) ;
00935             slen = strlen(downbuf) - 1;
00936             if (downbuf[slen] == ' ') {
00937               downbuf[slen] = 0;
00938             }
00939             if (TeXname) {
00940                TeXname = newstring(TeXname) ;
00941                PSname = newstring(PSname) ;
00942                Fontfile = newstring(Fontfile);
00943                Vectfile = newstring(Vectfile);
00944                specinfo = newstring(specbuf) ;
00945                downloadinfo = newstring(downbuf) ;
00946                add_entry(TeXname, PSname, Fontfile, Vectfile,
00947                          specinfo, downloadinfo) ;
00948             }
00949         }
00950       }
00951       (void)fclose(deffile) ;
00952    }
00953    checkstrings() ;
00954 }
00955 #ifndef KPATHSEA
00956 /*
00957  *   Get environment variables! These override entries in ./config.h.
00958  *   We substitute everything of the form ::, ^: or :$ with default,
00959  *   so a user can easily build on to the existing paths.
00960  */
00961 static char *getenvup P2C(char *, who, char *, what)
00962 {
00963    return getpath(getenv(who), what) ;
00964 }
00965 #endif
00966 #if !defined(KPATHSEA) && defined(SEARCH_SUBDIRECTORIES)
00967 static char *concat3();
00968 #endif
00969 void checkenv P1C(int, which)
00970 {
00971 #ifndef KPATHSEA
00972    if (which) {
00973       tfmpath = getenvup(FONTPATH, tfmpath) ;
00974       vfpath = getenvup("VFFONTS", vfpath) ;
00975       pictpath = getenvup("TEXPICTS", pictpath) ;
00976       figpath = getenvup("TEXINPUTS", figpath) ;
00977       headerpath = getenvup("DVIPSHEADERS", headerpath) ;
00978       if (getenv("TEXPKS"))
00979          pkpath = getenvup("TEXPKS", pkpath) ;
00980       else if (getenv("TEXPACKED"))
00981          pkpath = getenvup("TEXPACKED", pkpath) ;
00982       else if (getenv("PKFONTS"))
00983          pkpath = getenvup("PKFONTS", pkpath) ;
00984 #ifdef SEARCH_SUBDIRECTORIES
00985       else if (getenv(FONTPATH))
00986          pkpath = getenvup(FONTPATH, pkpath) ;
00987       if (getenv ("TEXFONTS_SUBDIR"))
00988          fontsubdirpath = getenvup ("TEXFONTS_SUBDIR", fontsubdirpath);
00989       {
00990          char pathsep[2] ;
00991          char *do_subdir_path();
00992          char *dirs = do_subdir_path (fontsubdirpath);
00993          /* If the paths were in dynamic storage before, that memory is
00994             wasted now.  */
00995          pathsep[0] = PATHSEP ;
00996          pathsep[1] = '\0' ;
00997          tfmpath = concat3 (tfmpath, pathsep, dirs);
00998          pkpath = concat3 (pkpath, pathsep, dirs);
00999       }
01000 #endif
01001    } else
01002       configpath = getenvup("TEXCONFIG", configpath) ;
01003 #endif
01004 }
01005 
01006 #if !defined(KPATHSEA) && defined(SEARCH_SUBDIRECTORIES)
01007 
01008 #include <sys/types.h>
01009 #include <sys/stat.h>
01010 #include <errno.h>
01011 
01012 #ifdef SYSV
01013 #include <dirent.h>
01014 typedef struct dirent *directory_entry_type;
01015 #else
01016 #include <sys/dir.h>
01017 typedef struct direct *directory_entry_type;
01018 #endif
01019 
01020 /* Declare the routine to get the current working directory.  */
01021 
01022 #ifndef HAVE_GETCWD
01023 extern char *getwd ();
01024 #define getcwd(b, len)  ((b) ? getwd (b) : getwd (xmalloc (len)))
01025 #else
01026 #ifdef ANSI
01027 extern char *getcwd (char *, int);
01028 #else
01029 extern char *getcwd ();
01030 #endif /* not ANSI */
01031 #endif /* not HAVE_GETWD */
01032 
01033 #if defined(SYSV) || defined(VMS) || defined(MSDOS) || defined(OS2) || defined(ATARIST)
01034 #define MAXPATHLEN (256)
01035 #else   /* ~SYSV */
01036 #include <sys/param.h>          /* for MAXPATHLEN */
01037 #endif
01038 
01039 extern void exit() ;
01040 extern int chdir() ;
01041 
01042 /* Memory operations: variants of malloc(3) and realloc(3) that just
01043    give up the ghost when they fail.  */
01044 
01045 char *
01046 xmalloc P1C(unsigned, size)
01047 {
01048   char *mem = malloc (size);
01049   
01050   if (mem == NULL)
01051     {
01052       fprintf (stderr, "! Cannot allocate %u bytes.\n", size);
01053       exit (10);
01054     }
01055   
01056   return mem;
01057 }
01058 
01059 
01060 char *
01061 xrealloc P2C(char *, ptr, unsigned, size)
01062 {
01063   char *mem = realloc (ptr, size);
01064   
01065   if (mem == NULL)
01066     {
01067       fprintf (stderr, "! Cannot reallocate %u bytes at %x.\n", size, (int)ptr);
01068       exit (10);
01069     }
01070     
01071   return mem;
01072 }
01073 
01074 
01075 /* Return, in NAME, the next component of PATH, i.e., the characters up
01076    to the next PATHSEP.  */
01077    
01078 static void
01079 next_component P2C(char *, name, char **, path)
01080 {
01081   unsigned count = 0;
01082   
01083   while (**path != 0 && **path != PATHSEP)
01084     {
01085       name[count++] = **path;
01086       (*path)++; /* Move further along, even between calls.  */
01087     }
01088   
01089   name[count] = 0;
01090   if (**path == PATHSEP)
01091     (*path)++; /* Move past the delimiter.  */
01092 }
01093 
01094 
01095 #ifndef _POSIX_SOURCE
01096 #ifndef S_ISDIR
01097 #define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
01098 #endif
01099 #endif
01100 
01101 /* Return true if FN is a directory or a symlink to a directory,
01102    false if not. */
01103 
01104 int
01105 is_dir P1C(char *, fn)
01106 {
01107   struct stat stats;
01108 
01109   return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode);
01110 }
01111 
01112 
01113 static char *
01114 concat3 P3C(char *, s1, char *, s2, char *, s3)
01115 {
01116   char *r = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
01117   strcpy (r, s1);
01118   strcat (r, s2);
01119   strcat (r, s3);
01120   return r;
01121 }
01122 
01123 
01124 /* DIR_LIST is the default list of directories (colon-separated) to
01125    search.  We want to add all the subdirectories directly below each of
01126    the directories in the path.
01127      
01128    We return the list of directories found.  */
01129 
01130 char *
01131 do_subdir_path P1C(char *, dir_list)
01132 {
01133   char *cwd;
01134   unsigned len;
01135   char *result = xmalloc ((unsigned)1);
01136   char *temp = dir_list;
01137   char dirsep[2] ;
01138 
01139   dirsep[0] = DIRSEP ;
01140   dirsep[1] = '\0' ;
01141 
01142   /* Make a copy in writable memory.  */
01143   dir_list = xmalloc (strlen (temp) + 1);
01144   strcpy (dir_list, temp);
01145   
01146   *result = 0;
01147 
01148   /* Unfortunately, we can't look in the environment for the current
01149      directory, because if we are running under a program (let's say
01150      Emacs), the PWD variable might have been set by Emacs' parent
01151      to the current directory at the time Emacs was invoked.  This
01152      is not necessarily the same directory the user expects to be
01153      in.  So, we must always call getcwd(3) or getwd(3), even though
01154      they are slow and prone to hang in networked installations.  */
01155   cwd = getcwd (NULL, MAXPATHLEN + 2);
01156   if (cwd == NULL)
01157     {
01158       perror ("getcwd");
01159       exit (errno);
01160     }
01161 
01162   do
01163     {
01164       DIR *dir;
01165       directory_entry_type e;
01166       char dirname[MAXPATHLEN];
01167 
01168       next_component (dirname, &dir_list);
01169 
01170       /* All the `::'s should be gone by now, but we may as well make
01171          sure `chdir' doesn't crash.  */
01172       if (*dirname == 0) continue;
01173 
01174       /* By changing directories, we save a bunch of string
01175          concatenations (and make the pathnames the kernel looks up
01176          shorter).  */
01177       if (chdir (dirname) != 0) continue;
01178 
01179       dir = opendir (".");
01180       if (dir == NULL) continue;
01181 
01182       while ((e = readdir (dir)) != NULL)
01183         {
01184           if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0
01185               && strcmp (e->d_name, "..") != 0)
01186             {
01187               char *found = concat3 (dirname, dirsep, e->d_name);
01188 
01189               result = xrealloc (result, strlen (result) + strlen (found) + 2);
01190 
01191               len = strlen (result);
01192               if (len > 0)
01193                 {
01194                   result[len] = PATHSEP;
01195                   result[len + 1] = 0;
01196                 }
01197               strcat (result, found);
01198               free (found);
01199             }
01200         }
01201       closedir (dir);
01202 
01203       /* Change back to the current directory, in case the path
01204          contains relative directory names.  */
01205       if (chdir (cwd) != 0)
01206         {
01207           perror (cwd);
01208           exit (errno);
01209         }
01210     }
01211   while (*dir_list != 0);
01212   
01213   return result;
01214 }
01215 #endif /* SEARCH_SUBDIRECTORIES */