home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d7xx / d795 / pstools.lha / PSTools / PSTools1.lha / source / resident.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-14  |  18.2 KB  |  729 lines

  1. /*
  2.  *   This code reads in and handles the defaults for the program from the
  3.  *   file config.sw.  This entire file is a bit kludgy, sorry.
  4.  */
  5. #include "structures.h" /* The copyright notice in that file is included too! */
  6. #include "paths.h"
  7. /*
  8.  *   This is the structure definition for resident fonts.  We use
  9.  *   a small and simple hash table to handle these.  We don't need
  10.  *   a big hash table.
  11.  */
  12. struct resfont *reshash[RESHASHPRIME] ;
  13. /*
  14.  *   These are the external routines we use.
  15.  */
  16. extern void error() ;
  17. extern integer scalewidth() ;
  18. extern void tfmload() ;
  19. extern FILE *search() ;
  20. extern shalfword pkbyte() ;
  21. extern integer pkquad() ;
  22. extern integer pktrio() ;
  23. extern Boolean pkopen() ;
  24. extern char *newstring() ;
  25. extern int add_header() ;
  26. extern int add_name() ;
  27. extern char *get_name() ;
  28. /*
  29.  *   These are the external variables we use.
  30.  */
  31. #ifdef DEBUG
  32. extern integer debug_flag;
  33. #endif  /* DEBUG */
  34. extern long bytesleft ;
  35. extern quarterword *raster ;
  36. extern FILE *pkfile ;
  37. extern char *oname ;
  38. extern integer swmem, fontmem ;
  39. extern char *tfmpath ;
  40. extern char *pkpath ;
  41. extern char *vfpath ;
  42. extern char *figpath ;
  43. extern char *configpath ;
  44. #ifdef SEARCH_SUBDIRECTORIES
  45. extern char *fontsubdirpath ;
  46. #endif
  47. #ifdef FONTLIB
  48. extern char *flipath, *fliname ;
  49. #endif
  50. extern char *headerpath ;
  51. extern char *paperfmt ; 
  52. extern char *nextstring ;
  53. extern char *maxstring ;
  54. extern char *warningmsg ;
  55. extern Boolean disablecomments ;
  56. extern Boolean compressed ;
  57. extern int quiet ;
  58. extern int filter ;
  59. extern Boolean reverse ;
  60. extern Boolean usesPSfonts ;
  61. extern Boolean nosmallchars ;
  62. extern Boolean removecomments ;
  63. extern Boolean safetyenclose ;
  64. extern int actualdpi ;
  65. extern int vactualdpi ;
  66. extern int maxdrift ;
  67. extern int vmaxdrift ;
  68. extern char *printer ;
  69. extern char *mfmode ;
  70. extern int lastresortsizes[] ;
  71. /*
  72.  *   To maintain a list of document fonts, we use the following
  73.  *   pointer.
  74.  */
  75. struct header_list *ps_fonts_used ;
  76. /*
  77.  *   Our hash routine.
  78.  */
  79. int
  80. hash(s)
  81.    char *s ;
  82. {
  83.    int h = 12 ;
  84.  
  85.    while (*s != 0)
  86.       h = (h + h + *s++) % RESHASHPRIME ;
  87.    return(h) ;
  88. }
  89. /*
  90.  *   cleanres() marks all resident fonts as not being yet sent.
  91.  */
  92. void
  93. cleanres() {
  94.    register int i ;
  95.    register struct resfont *p ;
  96.    for (i=0; i<RESHASHPRIME; i++)
  97.       for (p=reshash[i]; p; p=p->next)
  98.          p->sent = 0 ;
  99. }
  100. /*
  101.  *   The routine that looks up a font name.
  102.  */
  103. struct resfont *
  104. lookup(name)
  105.    char *name ;
  106. {
  107.    struct resfont *p ;
  108.  
  109.    for (p=reshash[hash(name)]; p!=NULL; p=p->next)
  110.       if (strcmp(p->Keyname, name)==0)
  111.          return(p) ;
  112.    return(NULL) ;
  113. }
  114. /*
  115.  *   This routine adds an entry.
  116.  */
  117. void
  118. add_entry(Keyname, TeXname, PSname, specinfo, downloadinfo)
  119.    char *Keyname, *TeXname, *PSname, *specinfo, *downloadinfo ;
  120. {
  121.    struct resfont *p ;
  122.    int h ;
  123.  
  124.    if (PSname == NULL)
  125.       PSname = TeXname ;
  126.    else if (strcmp(PSname, TeXname) && Keyname != PSname)
  127.       add_entry(PSname, TeXname, PSname, specinfo, downloadinfo) ;
  128.    p = (struct resfont *)malloc((unsigned int)sizeof(struct resfont)) ;
  129.    if (p==NULL)
  130.       error("! out of memory") ;
  131.    p->Keyname = Keyname ;
  132.    p->PSname = PSname ;
  133.    p->TeXname = TeXname ;
  134.    p->specialinstructions = specinfo ;
  135.    p->downloadheader = downloadinfo ;
  136.    h = hash(Keyname) ;
  137.    p->next = reshash[h] ;
  138.    p->sent = 0 ;
  139.    reshash[h] = p ;
  140. }
  141. /*
  142.  *   Now our residentfont routine.
  143.  */
  144. Boolean
  145. residentfont(curfnt)
  146.         register fontdesctype *curfnt ;
  147. {
  148.    register shalfword i ;
  149.    struct resfont *p ;
  150.  
  151. /*
  152.  *   First we determine if we can find this font in the resident list.
  153.  */
  154.    if (*curfnt->area)
  155.       return 0 ; /* resident fonts never have a nonstandard font area */
  156.    if ((p=lookup(curfnt->name))==NULL)
  157.       return 0 ;
  158. /*
  159.  *   We clear out some pointers:
  160.  */
  161. #ifdef DEBUG
  162.    if (dd(D_FONTS))
  163.         (void)fprintf(stderr,"Font %s <%s> is resident.\n",
  164.                                      curfnt->name, p->PSname) ;
  165. #endif  /* DEBUG */
  166.    curfnt->resfont = p ;
  167.    curfnt->name = p->TeXname ;
  168.    for (i=0; i<256; i++) {
  169.       curfnt->chardesc[i].TFMwidth = 0 ;
  170.       curfnt->chardesc[i].packptr = NULL ;
  171.       curfnt->chardesc[i].pixelwidth = 0 ;
  172.       curfnt->chardesc[i].flags = 0 ;
  173.    }
  174.    add_name(p->PSname, &ps_fonts_used) ;
  175. /*
  176.  *   We include the font here.  But we only should need to include the
  177.  *   font if we have a stupid spooler; smart spoolers should be able
  178.  *   to supply it automatically.
  179.  */
  180.    if (p->downloadheader)
  181.       if (add_header(p->downloadheader)) {
  182.          swmem -= DNFONTCOST ;
  183.          fontmem -= DNFONTCOST ;
  184.       }
  185.    tfmload(curfnt) ;
  186.    usesPSfonts = 1 ;
  187.    return(1) ;
  188. }
  189. #define INLINE_SIZE (500)
  190. static char was_inline[INLINE_SIZE] ;
  191. void
  192. bad_config() {
  193.  
  194.    error("Error in config file:") ;
  195.    (void)fputs(was_inline, stderr) ;
  196.    exit(1) ;
  197. }
  198. /*
  199.  *   Now we have the getdefaults routine.
  200.  */
  201. static char *psmapfile = PSMAPFILE ;
  202. void
  203. getdefaults(s)
  204. char *s ;
  205. {
  206.    FILE *deffile ;
  207.    char PSname[300] ;
  208.    register char *p ;
  209.    int i, j ;
  210.    char *d = configpath ;
  211.  
  212.    if (printer == NULL) {
  213.       if (s) {
  214.          strcpy(PSname, s) ;
  215.       } else {
  216.          d = "~" ;
  217.          strcpy(PSname, DVIPSRC) ;
  218.       }
  219.    } else {
  220.       strcpy(PSname, "config.") ;
  221.       strcat(PSname, printer) ;
  222.    }
  223.    if ((deffile=search(d,PSname,READ))!=NULL) {
  224.       while (fgets(was_inline, INLINE_SIZE, deffile)!=NULL) {
  225. /*
  226.  *   We need to get rid of the newline.
  227.  */
  228.        for (p=was_inline; *p; p++) ;
  229.        if (p > was_inline) *(p-1) = 0 ;
  230.        switch (was_inline[0]) {
  231. case 'm' :
  232.          if (sscanf(was_inline+1, "%d", &swmem) != 1) bad_config() ;
  233.          break ;
  234. case 'M' :
  235.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  236.          mfmode = newstring(PSname) ;
  237.          break ;
  238. case 'o' : case 'O' :
  239.          p = was_inline + 1 ;
  240. #ifdef VMS
  241.      p[strlen(p) - 1] = '\0';
  242. #endif /* VMS */
  243.          while (*p && *p <= ' ')
  244.             p++ ;
  245.          oname = newstring(p) ;
  246.          break ;
  247. #ifdef FONTLIB
  248. case 'L' : 
  249.          {
  250.             char tempname[300] ;
  251.             extern char *fliparse() ;
  252.             if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  253.             else {
  254.                flipath = newstring(fliparse(PSname,tempname));
  255.                fliname = newstring(tempname) ;
  256.             }
  257.      }
  258.          break ;
  259. #endif
  260. case 'T' : 
  261.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  262.          else tfmpath = newstring(PSname) ;
  263.          break ;
  264. case 'P' :
  265.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  266.          else pkpath = newstring(PSname) ;
  267.          break ;
  268. case 'p' :
  269.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  270.          else psmapfile = newstring(PSname) ;
  271.          break ;
  272. case 'V' : case 'v' :
  273.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  274.          else vfpath = newstring(PSname) ;
  275.          break ;
  276. case 'S' :
  277.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  278.          else figpath = newstring(PSname) ;
  279.          break ;
  280. case 's':
  281.          safetyenclose = 1 ;
  282.          break ;
  283. case 'H' : 
  284.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  285.          else headerpath = newstring(PSname) ;
  286.          break ;
  287. case 't' : 
  288.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  289.          else paperfmt = newstring(PSname) ;
  290.          break ;
  291. case ' ' : case '*' : case '#' : case ';' : case '=' : case 0 : case '\n' :
  292.          break ;
  293. case 'r' :
  294.          reverse = (was_inline[1] != '0') ;
  295.          break ;
  296. /*
  297.  *   This case is for last resort font scaling; I hate this, but enough
  298.  *   people have in no uncertain terms demanded it that I'll go ahead and
  299.  *   add it.
  300.  *
  301.  *   This line must have numbers on it, resolutions, to search for the
  302.  *   font as a last resort, and then the font will be scaled.  These
  303.  *   resolutions should be in increasing order.
  304.  *
  305.  *   For most machines, just `300' is sufficient here; on the NeXT,
  306.  *   `300 400' may be more appropriate.
  307.  */
  308. case 'R':
  309.          i = 0 ;
  310.          p = was_inline + 1 ;
  311.          while (*p) {
  312.             while (*p && *p <= ' ')
  313.                p++ ;
  314.             if ('0' <= *p && *p <= '9') {
  315.                j = 0 ;
  316.                while ('0' <= *p && *p <= '9')
  317.                   j = 10 * j + (*p++ - '0') ;
  318.                if (i > 0)
  319.                   if (lastresortsizes[i-1] > j) {
  320.                      error("last resort sizes (R) must be sorted") ;
  321.                      bad_config() ;
  322.                   }
  323.                lastresortsizes[i++] = j ;
  324.             } else {
  325.                if (*p == 0)
  326.                   break ;
  327.                error("! only numbers expected on `R' line in config!") ;
  328.             }
  329.          }
  330.          lastresortsizes[i] = 32000 ;
  331.          break ;
  332. case 'D' :
  333.          if (sscanf(was_inline+1, "%d", &actualdpi) != 1) bad_config() ;
  334.          if (actualdpi < 10 || actualdpi > 10000) bad_config() ;
  335.      vactualdpi = actualdpi;
  336.          break ;
  337. /*
  338.  *   Execute a command.  This can be dangerous, but can also be very useful.
  339.  */
  340. case 'E' :
  341. #ifdef SECURE
  342.          error("dvips was compiled with SECURE, which disables E in config") ;
  343. #else
  344.          (void)system(was_inline+1) ;
  345. #endif
  346.          break ;
  347. case 'K':
  348.          removecomments = (was_inline[1] != '0') ;
  349.          break ;
  350. case 'U':
  351.          nosmallchars = (was_inline[1] != '0') ;
  352.          break ;
  353. case 'W':
  354.          for (p=was_inline+1; *p && *p <= ' '; p++) ;
  355.          if (*p)
  356.             warningmsg = newstring(p) ;
  357.          else
  358.             warningmsg = 0 ;
  359.          break ;
  360. case 'X' :
  361.          if (sscanf(was_inline+1, "%d", &actualdpi) != 1) bad_config() ;
  362.          if (actualdpi < 10 || actualdpi > 10000) bad_config() ;
  363.          break ;
  364. case 'Y' :
  365.          if (sscanf(was_inline+1, "%d", &vactualdpi) != 1) bad_config() ;
  366.          if (vactualdpi < 10 || vactualdpi > 10000) bad_config() ;
  367.          break ;
  368. case 'e' :
  369.          if (sscanf(was_inline+1, "%d", &maxdrift) != 1) bad_config() ;
  370.          if (maxdrift < 0) bad_config() ;
  371.      vmaxdrift = maxdrift;
  372.          break ;
  373. case 'q' : case 'Q' :
  374.          quiet = (was_inline[1] != '0') ;
  375.          break ;
  376. case 'f' : case 'F' :
  377.          filter = (was_inline[1] != '0') ;
  378.          break ;
  379. case 'h' : 
  380.          if (sscanf(was_inline+1, "%s", PSname) != 1) bad_config() ;
  381.          else (void)add_header(PSname) ;
  382.          break ;
  383. case 'N' :
  384.          disablecomments = (was_inline[1] != '0') ;
  385.          break ;
  386. case 'Z' :
  387.          compressed = (was_inline[1] != '0') ;
  388.          break ;
  389. default:
  390.          bad_config() ;
  391.       }
  392.      }
  393.      (void)fclose(deffile) ;
  394.    } else {
  395.       if (printer)
  396.          error("! no such printer (can't find corresponding config file)") ;
  397.    }
  398. }
  399.  
  400. void getpsinfo() {
  401.    FILE *deffile ;
  402.    register char *p ;
  403.    char *specinfo, *downloadinfo ;
  404.  
  405.    if ((deffile=search(configpath, psmapfile, READ))!=NULL) {
  406.      while (fgets(was_inline, INLINE_SIZE, deffile)!=NULL) {
  407.          char *TeXname = NULL ;
  408.          char *PSname = NULL ;
  409.          specinfo = NULL ;
  410.          downloadinfo = NULL ;
  411.          p = was_inline ;
  412.          while (*p) {
  413.             while (*p && *p <= ' ')
  414.                p++ ;
  415.             if (*p) {
  416.                if (*p == '"')
  417.                   specinfo = p + 1 ;
  418.                else if (*p == '<')
  419.                   downloadinfo = p + 1 ;
  420.                else if (TeXname)
  421.                   PSname = p ;
  422.                else
  423.                   TeXname = p ;
  424.                if (*p == '"') {
  425.                   p++ ;
  426.                   while (*p != '"' && *p)
  427.                      p++ ;
  428.                } else
  429.                   while (*p > ' ')
  430.                      p++ ;
  431.                if (*p)
  432.                   *p++ = 0 ;
  433.             }
  434.          }
  435.          if (TeXname) {
  436.             TeXname = newstring(TeXname) ;
  437.             specinfo = newstring(specinfo) ;
  438.             PSname = newstring(PSname) ;
  439.             downloadinfo = newstring(downloadinfo) ;
  440.             add_entry(TeXname, TeXname, PSname, specinfo, downloadinfo) ;
  441.      }
  442.       }
  443.       (void)fclose(deffile) ;
  444.    }
  445. }
  446. /*
  447.  *   Get environment variables! These override entries in ./config.h.
  448.  *   We substitute everything of the form ::, ^: or :$ with default,
  449.  *   so a user can easily build on to the existing paths.
  450.  */
  451. static char *getenvup(who, what)
  452. char *who, *what ;
  453. {
  454.    char *p  ;
  455.  
  456.    if (p=getenv(who)) {
  457.       register char *pp, *qq ;
  458.       int lastsep = 1 ;
  459.  
  460.       for (pp=nextstring, qq=p; *qq;) {
  461.          if (*qq == PATHSEP) {
  462.             if (lastsep) {
  463.                strcpy(pp, what) ;
  464.                pp = pp + strlen(pp) ;
  465.             }
  466.             lastsep = 1 ;
  467.          } else
  468.             lastsep = 0 ;
  469.          *pp++ = *qq++ ;
  470.       }
  471.       if (lastsep) {
  472.          strcpy(pp, what) ;
  473.          pp = pp + strlen(pp) ;
  474.       }
  475.       *pp = 0 ;
  476.       qq = nextstring ;
  477.       nextstring = pp + 1 ;
  478.       return qq ;
  479.    } else
  480.       return what ;
  481. }
  482. void checkenv(which)
  483. int which ;
  484. {
  485.    if (which) {
  486.       tfmpath = getenvup("TEXFONTS", tfmpath) ;
  487.       figpath = getenvup("TEXINPUTS", figpath) ;
  488.       if (getenv("TEXPKS"))
  489.          pkpath = getenvup("TEXPKS", pkpath) ;
  490.       else if (getenv("PKFONTS"))
  491.          pkpath = getenvup("PKFONTS", pkpath) ;
  492. #ifdef SEARCH_SUBDIRECTORIES
  493.       else if (getenv("TEXFONTS"))
  494.          pkpath = getenvup("TEXFONTS", pkpath) ;
  495.       if (getenv ("TEXFONTS_SUBDIR"))
  496.          fontsubdirpath = getenvup ("TEXFONTS_SUBDIR", fontsubdirpath);
  497.       {
  498.          char *do_subdir_path();
  499.          static char *concat3();
  500.          char *dirs = do_subdir_path (fontsubdirpath);
  501.          /* If the paths were in dynamic storage before, that memory is
  502.             wasted now.  */
  503.          tfmpath = concat3 (tfmpath, ":", dirs);
  504.          pkpath = concat3 (pkpath, ":", dirs);
  505.       }
  506. #endif
  507.    } else
  508.       configpath = getenvup("TEXCONFIG", configpath) ;
  509. }
  510.  
  511. #ifdef SEARCH_SUBDIRECTORIES
  512.  
  513. #include <sys/types.h>
  514. #include <sys/stat.h>
  515. #include <errno.h>
  516.  
  517. #ifdef SYSV
  518. #include <dirent.h>
  519. typedef struct dirent *directory_entry_type;
  520. #else
  521. #include <sys/dir.h>
  522. typedef struct direct *directory_entry_type;
  523. #endif
  524.  
  525. /* Declare the routine to get the current working directory.  */
  526.  
  527. #ifndef HAVE_GETCWD
  528. extern char *getwd ();
  529. #define getcwd(b, len)  ((b) ? getwd (b) : getwd (xmalloc (len)))
  530. #else
  531. #ifdef ANSI
  532. extern char *getcwd (char *, int);
  533. #else
  534. extern char *getcwd ();
  535. #endif /* not ANSI */
  536. #endif /* not HAVE_GETWD */
  537.  
  538. #ifdef SYSV
  539. #define MAXPATHLEN (256)
  540. #else
  541. #ifdef VMS
  542. #define MAXPATHLEN (256)
  543. #else   /* ~SYSV */
  544. #include <sys/param.h>          /* for MAXPATHLEN */
  545. #endif  /* ~SYSV */
  546. #endif
  547.  
  548. extern void exit(), free() ;
  549. extern int chdir() ;
  550.  
  551. /* Memory operations: variants of malloc(3) and realloc(3) that just
  552.    give up the ghost when they fail.  */
  553.  
  554. extern char *realloc ();
  555.  
  556. char *
  557. xmalloc (size)
  558.   unsigned size;
  559. {
  560.   char *mem = malloc (size);
  561.   
  562.   if (mem == NULL)
  563.     {
  564.       fprintf (stderr, "! Cannot allocate %u bytes.\n", size);
  565.       exit (10);
  566.     }
  567.   
  568.   return mem;
  569. }
  570.  
  571.  
  572. char *
  573. xrealloc (ptr, size)
  574.   char *ptr;
  575.   unsigned size;
  576. {
  577.   char *mem = realloc (ptr, size);
  578.   
  579.   if (mem == NULL)
  580.     {
  581.       fprintf (stderr, "! Cannot reallocate %u bytes at %x.\n", size, ptr);
  582.       exit (10);
  583.     }
  584.     
  585.   return mem;
  586. }
  587.  
  588.  
  589. /* Return, in NAME, the next component of PATH, i.e., the characters up
  590.    to the next PATHSEP.  */
  591.    
  592. static void
  593. next_component (name, path)
  594.   char name[];
  595.   char **path;
  596. {
  597.   unsigned count = 0;
  598.   
  599.   while (**path != 0 && **path != PATHSEP)
  600.     {
  601.       name[count++] = **path;
  602.       (*path)++; /* Move further along, even between calls.  */
  603.     }
  604.   
  605.   name[count] = 0;
  606.   if (**path == PATHSEP)
  607.     (*path)++; /* Move past the delimiter.  */
  608. }
  609.  
  610.  
  611. #ifndef _POSIX_SOURCE
  612. #define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
  613. #endif
  614.  
  615. /* Return true if FN is a directory or a symlink to a directory,
  616.    false if not. */
  617.  
  618. int
  619. is_dir (fn)
  620.   char *fn;
  621. {
  622.   struct stat stats;
  623.  
  624.   return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode);
  625. }
  626.  
  627.  
  628. static char *
  629. concat3 (s1, s2, s3)
  630.   char *s1, *s2, *s3;
  631. {
  632.   char *r = xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1);
  633.   strcpy (r, s1);
  634.   strcat (r, s2);
  635.   strcat (r, s3);
  636.   return r;
  637. }
  638.  
  639.  
  640. /* DIR_LIST is the default list of directories (colon-separated) to
  641.    search.  We want to add all the subdirectories directly below each of
  642.    the directories in the path.
  643.      
  644.    We return the list of directories found.  */
  645.  
  646. char *
  647. do_subdir_path (dir_list)
  648.   char *dir_list;
  649. {
  650.   char *cwd;
  651.   unsigned len;
  652.   char *result = xmalloc (1);
  653.   char *temp = dir_list;
  654.  
  655.   /* Make a copy in writable memory.  */
  656.   dir_list = xmalloc (strlen (temp) + 1);
  657.   strcpy (dir_list, temp);
  658.   
  659.   *result = 0;
  660.  
  661.   /* Unfortunately, we can't look in the environment for the current
  662.      directory, because if we are running under a program (let's say
  663.      Emacs), the PWD variable might have been set by Emacs' parent
  664.      to the current directory at the time Emacs was invoked.  This
  665.      is not necessarily the same directory the user expects to be
  666.      in.  So, we must always call getcwd(3) or getwd(3), even though
  667.      they are slow and prone to hang in networked installations.  */
  668.   cwd = getcwd (NULL, MAXPATHLEN + 2);
  669.   if (cwd == NULL)
  670.     {
  671.       perror ("getcwd");
  672.       exit (errno);
  673.     }
  674.  
  675.   do
  676.     {
  677.       DIR *dir;
  678.       directory_entry_type e;
  679.       char dirname[MAXPATHLEN];
  680.  
  681.       next_component (dirname, &dir_list);
  682.  
  683.       /* All the `::'s should be gone by now, but we may as well make
  684.          sure `chdir' doesn't crash.  */
  685.       if (*dirname == 0) continue;
  686.  
  687.       /* By changing directories, we save a bunch of string
  688.          concatenations (and make the pathnames the kernel looks up
  689.          shorter).  */
  690.       if (chdir (dirname) != 0) continue;
  691.  
  692.       dir = opendir (".");
  693.       if (dir == NULL) continue;
  694.  
  695.       while ((e = readdir (dir)) != NULL)
  696.         {
  697.           if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0
  698.               && strcmp (e->d_name, "..") != 0)
  699.             {
  700.               char *found = concat3 (dirname, "/", e->d_name);
  701.  
  702.               result = xrealloc (result, strlen (result) + strlen (found) + 2);
  703.  
  704.               len = strlen (result);
  705.               if (len > 0)
  706.                 {
  707.                   result[len] = PATHSEP;
  708.                   result[len + 1] = 0;
  709.                 }
  710.               strcat (result, found);
  711.               free (found);
  712.             }
  713.         }
  714.       closedir (dir);
  715.  
  716.       /* Change back to the current directory, in case the path
  717.          contains relative directory names.  */
  718.       if (chdir (cwd) != 0)
  719.         {
  720.           perror (cwd);
  721.           exit (errno);
  722.         }
  723.     }
  724.   while (*dir_list != 0);
  725.   
  726.   return result;
  727. }
  728. #endif /* SEARCH_SUBDIRECTORIES */
  729.