Home | History | Annotate | Line # | Download | only in dist
      1  1.1  christos /* Implementation of pattern-matching file search paths for GNU Make.
      2  1.1  christos Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
      3  1.1  christos 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
      4  1.1  christos Foundation, Inc.
      5  1.1  christos This file is part of GNU Make.
      6  1.1  christos 
      7  1.1  christos GNU Make is free software; you can redistribute it and/or modify it under the
      8  1.1  christos terms of the GNU General Public License as published by the Free Software
      9  1.1  christos Foundation; either version 2, or (at your option) any later version.
     10  1.1  christos 
     11  1.1  christos GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
     12  1.1  christos WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     13  1.1  christos A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     14  1.1  christos 
     15  1.1  christos You should have received a copy of the GNU General Public License along with
     16  1.1  christos GNU Make; see the file COPYING.  If not, write to the Free Software
     17  1.1  christos Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.  */
     18  1.1  christos 
     19  1.1  christos #include "make.h"
     20  1.1  christos #include "filedef.h"
     21  1.1  christos #include "variable.h"
     22  1.1  christos #ifdef WINDOWS32
     23  1.1  christos #include "pathstuff.h"
     24  1.1  christos #endif
     25  1.1  christos 
     26  1.1  christos 
     27  1.1  christos /* Structure used to represent a selective VPATH searchpath.  */
     28  1.1  christos 
     29  1.1  christos struct vpath
     30  1.1  christos   {
     31  1.1  christos     struct vpath *next;	/* Pointer to next struct in the linked list.  */
     32  1.1  christos     char *pattern;	/* The pattern to match.  */
     33  1.1  christos     char *percent;	/* Pointer into `pattern' where the `%' is.  */
     34  1.1  christos     unsigned int patlen;/* Length of the pattern.  */
     35  1.1  christos     char **searchpath;	/* Null-terminated list of directories.  */
     36  1.1  christos     unsigned int maxlen;/* Maximum length of any entry in the list.  */
     37  1.1  christos   };
     38  1.1  christos 
     39  1.1  christos /* Linked-list of all selective VPATHs.  */
     40  1.1  christos 
     41  1.1  christos static struct vpath *vpaths;
     42  1.1  christos 
     43  1.1  christos /* Structure for the general VPATH given in the variable.  */
     44  1.1  christos 
     45  1.1  christos static struct vpath *general_vpath;
     46  1.1  christos 
     47  1.1  christos /* Structure for GPATH given in the variable.  */
     48  1.1  christos 
     49  1.1  christos static struct vpath *gpaths;
     50  1.1  christos 
     51  1.1  christos static int selective_vpath_search PARAMS ((struct vpath *path, char **file, FILE_TIMESTAMP *mtime_ptr));
     53  1.1  christos 
     54  1.1  christos /* Reverse the chain of selective VPATH lists so they
     55  1.1  christos    will be searched in the order given in the makefiles
     56  1.1  christos    and construct the list from the VPATH variable.  */
     57  1.1  christos 
     58  1.1  christos void
     59  1.1  christos build_vpath_lists ()
     60  1.1  christos {
     61  1.1  christos   register struct vpath *new = 0;
     62  1.1  christos   register struct vpath *old, *nexto;
     63  1.1  christos   register char *p;
     64  1.1  christos 
     65  1.1  christos   /* Reverse the chain.  */
     66  1.1  christos   for (old = vpaths; old != 0; old = nexto)
     67  1.1  christos     {
     68  1.1  christos       nexto = old->next;
     69  1.1  christos       old->next = new;
     70  1.1  christos       new = old;
     71  1.1  christos     }
     72  1.1  christos 
     73  1.1  christos   vpaths = new;
     74  1.1  christos 
     75  1.1  christos   /* If there is a VPATH variable with a nonnull value, construct the
     76  1.1  christos      general VPATH list from it.  We use variable_expand rather than just
     77  1.1  christos      calling lookup_variable so that it will be recursively expanded.  */
     78  1.1  christos 
     79  1.1  christos   {
     80  1.1  christos     /* Turn off --warn-undefined-variables while we expand SHELL and IFS.  */
     81  1.1  christos     int save = warn_undefined_variables_flag;
     82  1.1  christos     warn_undefined_variables_flag = 0;
     83  1.1  christos 
     84  1.1  christos     p = variable_expand ("$(strip $(VPATH))");
     85  1.1  christos 
     86  1.1  christos     warn_undefined_variables_flag = save;
     87  1.1  christos   }
     88  1.1  christos 
     89  1.1  christos   if (*p != '\0')
     90  1.1  christos     {
     91  1.1  christos       /* Save the list of vpaths.  */
     92  1.1  christos       struct vpath *save_vpaths = vpaths;
     93  1.1  christos 
     94  1.1  christos       /* Empty `vpaths' so the new one will have no next, and `vpaths'
     95  1.1  christos 	 will still be nil if P contains no existing directories.  */
     96  1.1  christos       vpaths = 0;
     97  1.1  christos 
     98  1.1  christos       /* Parse P.  */
     99  1.1  christos       construct_vpath_list ("%", p);
    100  1.1  christos 
    101  1.1  christos       /* Store the created path as the general path,
    102  1.1  christos 	 and restore the old list of vpaths.  */
    103  1.1  christos       general_vpath = vpaths;
    104  1.1  christos       vpaths = save_vpaths;
    105  1.1  christos     }
    106  1.1  christos 
    107  1.1  christos   /* If there is a GPATH variable with a nonnull value, construct the
    108  1.1  christos      GPATH list from it.  We use variable_expand rather than just
    109  1.1  christos      calling lookup_variable so that it will be recursively expanded.  */
    110  1.1  christos 
    111  1.1  christos   {
    112  1.1  christos     /* Turn off --warn-undefined-variables while we expand SHELL and IFS.  */
    113  1.1  christos     int save = warn_undefined_variables_flag;
    114  1.1  christos     warn_undefined_variables_flag = 0;
    115  1.1  christos 
    116  1.1  christos     p = variable_expand ("$(strip $(GPATH))");
    117  1.1  christos 
    118  1.1  christos     warn_undefined_variables_flag = save;
    119  1.1  christos   }
    120  1.1  christos 
    121  1.1  christos   if (*p != '\0')
    122  1.1  christos     {
    123  1.1  christos       /* Save the list of vpaths.  */
    124  1.1  christos       struct vpath *save_vpaths = vpaths;
    125  1.1  christos 
    126  1.1  christos       /* Empty `vpaths' so the new one will have no next, and `vpaths'
    127  1.1  christos 	 will still be nil if P contains no existing directories.  */
    128  1.1  christos       vpaths = 0;
    129  1.1  christos 
    130  1.1  christos       /* Parse P.  */
    131  1.1  christos       construct_vpath_list ("%", p);
    132  1.1  christos 
    133  1.1  christos       /* Store the created path as the GPATH,
    134  1.1  christos 	 and restore the old list of vpaths.  */
    135  1.1  christos       gpaths = vpaths;
    136  1.1  christos       vpaths = save_vpaths;
    137  1.1  christos     }
    138  1.1  christos }
    139  1.1  christos 
    140  1.1  christos /* Construct the VPATH listing for the pattern and searchpath given.
    142  1.1  christos 
    143  1.1  christos    This function is called to generate selective VPATH lists and also for
    144  1.1  christos    the general VPATH list (which is in fact just a selective VPATH that
    145  1.1  christos    is applied to everything).  The returned pointer is either put in the
    146  1.1  christos    linked list of all selective VPATH lists or in the GENERAL_VPATH
    147  1.1  christos    variable.
    148  1.1  christos 
    149  1.1  christos    If SEARCHPATH is nil, remove all previous listings with the same
    150  1.1  christos    pattern.  If PATTERN is nil, remove all VPATH listings.  Existing
    151  1.1  christos    and readable directories that are not "." given in the searchpath
    152  1.1  christos    separated by the path element separator (defined in make.h) are
    153  1.1  christos    loaded into the directory hash table if they are not there already
    154  1.1  christos    and put in the VPATH searchpath for the given pattern with trailing
    155  1.1  christos    slashes stripped off if present (and if the directory is not the
    156  1.1  christos    root, "/").  The length of the longest entry in the list is put in
    157  1.1  christos    the structure as well.  The new entry will be at the head of the
    158  1.1  christos    VPATHS chain.  */
    159  1.1  christos 
    160  1.1  christos void
    161  1.1  christos construct_vpath_list (char *pattern, char *dirpath)
    162  1.1  christos {
    163  1.1  christos   register unsigned int elem;
    164  1.1  christos   register char *p;
    165  1.1  christos   register char **vpath;
    166  1.1  christos   register unsigned int maxvpath;
    167  1.1  christos   unsigned int maxelem;
    168  1.1  christos   char *percent = NULL;
    169  1.1  christos 
    170  1.1  christos   if (pattern != 0)
    171  1.1  christos     {
    172  1.1  christos       pattern = xstrdup (pattern);
    173  1.1  christos       percent = find_percent (pattern);
    174  1.1  christos     }
    175  1.1  christos 
    176  1.1  christos   if (dirpath == 0)
    177  1.1  christos     {
    178  1.1  christos       /* Remove matching listings.  */
    179  1.1  christos       register struct vpath *path, *lastpath;
    180  1.1  christos 
    181  1.1  christos       lastpath = 0;
    182  1.1  christos       path = vpaths;
    183  1.1  christos       while (path != 0)
    184  1.1  christos 	{
    185  1.1  christos 	  struct vpath *next = path->next;
    186  1.1  christos 
    187  1.1  christos 	  if (pattern == 0
    188  1.1  christos 	      || (((percent == 0 && path->percent == 0)
    189  1.1  christos 		   || (percent - pattern == path->percent - path->pattern))
    190  1.1  christos 		  && streq (pattern, path->pattern)))
    191  1.1  christos 	    {
    192  1.1  christos 	      /* Remove it from the linked list.  */
    193  1.1  christos 	      if (lastpath == 0)
    194  1.1  christos 		vpaths = path->next;
    195  1.1  christos 	      else
    196  1.1  christos 		lastpath->next = next;
    197  1.1  christos 
    198  1.1  christos 	      /* Free its unused storage.  */
    199  1.1  christos 	      free (path->pattern);
    200  1.1  christos 	      free ((char *) path->searchpath);
    201  1.1  christos 	      free ((char *) path);
    202  1.1  christos 	    }
    203  1.1  christos 	  else
    204  1.1  christos 	    lastpath = path;
    205  1.1  christos 
    206  1.1  christos 	  path = next;
    207  1.1  christos 	}
    208  1.1  christos 
    209  1.1  christos       if (pattern != 0)
    210  1.1  christos 	free (pattern);
    211  1.1  christos       return;
    212  1.1  christos     }
    213  1.1  christos 
    214  1.1  christos #ifdef WINDOWS32
    215  1.1  christos     convert_vpath_to_windows32(dirpath, ';');
    216  1.1  christos #endif
    217  1.1  christos 
    218  1.1  christos   /* Figure out the maximum number of VPATH entries and put it in
    219  1.1  christos      MAXELEM.  We start with 2, one before the first separator and one
    220  1.1  christos      nil (the list terminator) and increment our estimated number for
    221  1.1  christos      each separator or blank we find.  */
    222  1.1  christos   maxelem = 2;
    223  1.1  christos   p = dirpath;
    224  1.1  christos   while (*p != '\0')
    225  1.1  christos     if (*p++ == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
    226  1.1  christos       ++maxelem;
    227  1.1  christos 
    228  1.1  christos   vpath = (char **) xmalloc (maxelem * sizeof (char *));
    229  1.1  christos   maxvpath = 0;
    230  1.1  christos 
    231  1.1  christos   /* Skip over any initial separators and blanks.  */
    232  1.1  christos   p = dirpath;
    233  1.1  christos   while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
    234  1.1  christos     ++p;
    235  1.1  christos 
    236  1.1  christos   elem = 0;
    237  1.1  christos   while (*p != '\0')
    238  1.1  christos     {
    239  1.1  christos       char *v;
    240  1.1  christos       unsigned int len;
    241  1.1  christos 
    242  1.1  christos       /* Find the end of this entry.  */
    243  1.1  christos       v = p;
    244  1.1  christos       while (*p != '\0' && *p != PATH_SEPARATOR_CHAR
    245  1.1  christos 	     && !isblank ((unsigned char)*p))
    246  1.1  christos 	++p;
    247  1.1  christos 
    248  1.1  christos       len = p - v;
    249  1.1  christos       /* Make sure there's no trailing slash,
    250  1.1  christos 	 but still allow "/" as a directory.  */
    251  1.1  christos #if defined(__MSDOS__) || defined(__EMX__)
    252  1.1  christos       /* We need also to leave alone a trailing slash in "d:/".  */
    253  1.1  christos       if (len > 3 || (len > 1 && v[1] != ':'))
    254  1.1  christos #endif
    255  1.1  christos       if (len > 1 && p[-1] == '/')
    256  1.1  christos 	--len;
    257  1.1  christos 
    258  1.1  christos       if (len > 1 || *v != '.')
    259  1.1  christos 	{
    260  1.1  christos 	  v = savestring (v, len);
    261  1.1  christos 
    262  1.1  christos 	  /* Verify that the directory actually exists.  */
    263  1.1  christos 
    264  1.1  christos 	  if (dir_file_exists_p (v, ""))
    265  1.1  christos 	    {
    266  1.1  christos 	      /* It does.  Put it in the list.  */
    267  1.1  christos 	      vpath[elem++] = dir_name (v);
    268  1.1  christos 	      free (v);
    269  1.1  christos 	      if (len > maxvpath)
    270  1.1  christos 		maxvpath = len;
    271  1.1  christos 	    }
    272  1.1  christos 	  else
    273  1.1  christos 	    /* The directory does not exist.  Omit from the list.  */
    274  1.1  christos 	    free (v);
    275  1.1  christos 	}
    276  1.1  christos 
    277  1.1  christos       /* Skip over separators and blanks between entries.  */
    278  1.1  christos       while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
    279  1.1  christos 	++p;
    280  1.1  christos     }
    281  1.1  christos 
    282  1.1  christos   if (elem > 0)
    283  1.1  christos     {
    284  1.1  christos       struct vpath *path;
    285  1.1  christos       /* ELEM is now incremented one element past the last
    286  1.1  christos 	 entry, to where the nil-pointer terminator goes.
    287  1.1  christos 	 Usually this is maxelem - 1.  If not, shrink down.  */
    288  1.1  christos       if (elem < (maxelem - 1))
    289  1.1  christos 	vpath = (char **) xrealloc ((char *) vpath,
    290  1.1  christos 				    (elem + 1) * sizeof (char *));
    291  1.1  christos 
    292  1.1  christos       /* Put the nil-pointer terminator on the end of the VPATH list.  */
    293  1.1  christos       vpath[elem] = 0;
    294  1.1  christos 
    295  1.1  christos       /* Construct the vpath structure and put it into the linked list.  */
    296  1.1  christos       path = (struct vpath *) xmalloc (sizeof (struct vpath));
    297  1.1  christos       path->searchpath = vpath;
    298  1.1  christos       path->maxlen = maxvpath;
    299  1.1  christos       path->next = vpaths;
    300  1.1  christos       vpaths = path;
    301  1.1  christos 
    302  1.1  christos       /* Set up the members.  */
    303  1.1  christos       path->pattern = pattern;
    304  1.1  christos       path->percent = percent;
    305  1.1  christos       path->patlen = strlen (pattern);
    306  1.1  christos     }
    307  1.1  christos   else
    308  1.1  christos     {
    309  1.1  christos       /* There were no entries, so free whatever space we allocated.  */
    310  1.1  christos       free ((char *) vpath);
    311  1.1  christos       if (pattern != 0)
    312  1.1  christos 	free (pattern);
    313  1.1  christos     }
    314  1.1  christos }
    315  1.1  christos 
    316  1.1  christos /* Search the GPATH list for a pathname string that matches the one passed
    318  1.1  christos    in.  If it is found, return 1.  Otherwise we return 0.  */
    319  1.1  christos 
    320  1.1  christos int
    321  1.1  christos gpath_search (char *file, unsigned int len)
    322  1.1  christos {
    323  1.1  christos   char **gp;
    324  1.1  christos 
    325  1.1  christos   if (gpaths && (len <= gpaths->maxlen))
    326  1.1  christos     for (gp = gpaths->searchpath; *gp != NULL; ++gp)
    327  1.1  christos       if (strneq (*gp, file, len) && (*gp)[len] == '\0')
    328  1.1  christos         return 1;
    329  1.1  christos 
    330  1.1  christos   return 0;
    331  1.1  christos }
    332  1.1  christos 
    333  1.1  christos /* Search the VPATH list whose pattern matches *FILE for a directory
    335  1.1  christos    where the name pointed to by FILE exists.  If it is found, we set *FILE to
    336  1.1  christos    the newly malloc'd name of the existing file, *MTIME_PTR (if MTIME_PTR is
    337  1.1  christos    not NULL) to its modtime (or zero if no stat call was done), and return 1.
    338  1.1  christos    Otherwise we return 0.  */
    339  1.1  christos 
    340  1.1  christos int
    341  1.1  christos vpath_search (char **file, FILE_TIMESTAMP *mtime_ptr)
    342  1.1  christos {
    343  1.1  christos   register struct vpath *v;
    344  1.1  christos 
    345  1.1  christos   /* If there are no VPATH entries or FILENAME starts at the root,
    346  1.1  christos      there is nothing we can do.  */
    347  1.1  christos 
    348  1.1  christos   if (**file == '/'
    349  1.1  christos #ifdef HAVE_DOS_PATHS
    350  1.1  christos       || **file == '\\'
    351  1.1  christos       || (*file)[1] == ':'
    352  1.1  christos #endif
    353  1.1  christos       || (vpaths == 0 && general_vpath == 0))
    354  1.1  christos     return 0;
    355  1.1  christos 
    356  1.1  christos   for (v = vpaths; v != 0; v = v->next)
    357  1.1  christos     if (pattern_matches (v->pattern, v->percent, *file))
    358  1.1  christos       if (selective_vpath_search (v, file, mtime_ptr))
    359  1.1  christos 	return 1;
    360  1.1  christos 
    361  1.1  christos   if (general_vpath != 0
    362  1.1  christos       && selective_vpath_search (general_vpath, file, mtime_ptr))
    363  1.1  christos     return 1;
    364  1.1  christos 
    365  1.1  christos   return 0;
    366  1.1  christos }
    367  1.1  christos 
    368  1.1  christos 
    369  1.1  christos /* Search the given VPATH list for a directory where the name pointed
    370  1.1  christos    to by FILE exists.  If it is found, we set *FILE to the newly malloc'd
    371  1.1  christos    name of the existing file, *MTIME_PTR (if MTIME_PTR is not NULL) to
    372  1.1  christos    its modtime (or zero if no stat call was done), and we return 1.
    373  1.1  christos    Otherwise we return 0.  */
    374  1.1  christos 
    375  1.1  christos static int
    376  1.1  christos selective_vpath_search (struct vpath *path, char **file,
    377  1.1  christos                         FILE_TIMESTAMP *mtime_ptr)
    378  1.1  christos {
    379  1.1  christos   int not_target;
    380  1.1  christos   char *name, *n;
    381  1.1  christos   char *filename;
    382  1.1  christos   register char **vpath = path->searchpath;
    383  1.1  christos   unsigned int maxvpath = path->maxlen;
    384  1.1  christos   register unsigned int i;
    385  1.1  christos   unsigned int flen, vlen, name_dplen;
    386  1.1  christos   int exists = 0;
    387  1.1  christos 
    388  1.1  christos   /* Find out if *FILE is a target.
    389  1.1  christos      If and only if it is NOT a target, we will accept prospective
    390  1.1  christos      files that don't exist but are mentioned in a makefile.  */
    391  1.1  christos   {
    392  1.1  christos     struct file *f = lookup_file (*file);
    393  1.1  christos     not_target = f == 0 || !f->is_target;
    394  1.1  christos   }
    395  1.1  christos 
    396  1.1  christos   flen = strlen (*file);
    397  1.1  christos 
    398  1.1  christos   /* Split *FILE into a directory prefix and a name-within-directory.
    399  1.1  christos      NAME_DPLEN gets the length of the prefix; FILENAME gets the
    400  1.1  christos      pointer to the name-within-directory and FLEN is its length.  */
    401  1.1  christos 
    402  1.1  christos   n = strrchr (*file, '/');
    403  1.1  christos #ifdef HAVE_DOS_PATHS
    404  1.1  christos   /* We need the rightmost slash or backslash.  */
    405  1.1  christos   {
    406  1.1  christos     char *bslash = strrchr(*file, '\\');
    407  1.1  christos     if (!n || bslash > n)
    408  1.1  christos       n = bslash;
    409  1.1  christos   }
    410  1.1  christos #endif
    411  1.1  christos   name_dplen = n != 0 ? n - *file : 0;
    412  1.1  christos   filename = name_dplen > 0 ? n + 1 : *file;
    413  1.1  christos   if (name_dplen > 0)
    414  1.1  christos     flen -= name_dplen + 1;
    415  1.1  christos 
    416  1.1  christos   /* Allocate enough space for the biggest VPATH entry,
    417  1.1  christos      a slash, the directory prefix that came with *FILE,
    418  1.1  christos      another slash (although this one may not always be
    419  1.1  christos      necessary), the filename, and a null terminator.  */
    420  1.1  christos   name = (char *) xmalloc (maxvpath + 1 + name_dplen + 1 + flen + 1);
    421  1.1  christos 
    422  1.1  christos   /* Try each VPATH entry.  */
    423  1.1  christos   for (i = 0; vpath[i] != 0; ++i)
    424  1.1  christos     {
    425  1.1  christos       int exists_in_cache = 0;
    426  1.1  christos 
    427  1.1  christos       n = name;
    428  1.1  christos 
    429  1.1  christos       /* Put the next VPATH entry into NAME at N and increment N past it.  */
    430  1.1  christos       vlen = strlen (vpath[i]);
    431  1.1  christos       bcopy (vpath[i], n, vlen);
    432  1.1  christos       n += vlen;
    433  1.1  christos 
    434  1.1  christos       /* Add the directory prefix already in *FILE.  */
    435  1.1  christos       if (name_dplen > 0)
    436  1.1  christos 	{
    437  1.1  christos #ifndef VMS
    438  1.1  christos 	  *n++ = '/';
    439  1.1  christos #endif
    440  1.1  christos 	  bcopy (*file, n, name_dplen);
    441  1.1  christos 	  n += name_dplen;
    442  1.1  christos 	}
    443  1.1  christos 
    444  1.1  christos #ifdef HAVE_DOS_PATHS
    445  1.1  christos       /* Cause the next if to treat backslash and slash alike.  */
    446  1.1  christos       if (n != name && n[-1] == '\\' )
    447  1.1  christos 	n[-1] = '/';
    448  1.1  christos #endif
    449  1.1  christos       /* Now add the name-within-directory at the end of NAME.  */
    450  1.1  christos #ifndef VMS
    451  1.1  christos       if (n != name && n[-1] != '/')
    452  1.1  christos 	{
    453  1.1  christos 	  *n = '/';
    454  1.1  christos 	  bcopy (filename, n + 1, flen + 1);
    455  1.1  christos 	}
    456  1.1  christos       else
    457  1.1  christos #endif
    458  1.1  christos 	bcopy (filename, n, flen + 1);
    459  1.1  christos 
    460  1.1  christos       /* Check if the file is mentioned in a makefile.  If *FILE is not
    461  1.1  christos 	 a target, that is enough for us to decide this file exists.
    462  1.1  christos 	 If *FILE is a target, then the file must be mentioned in the
    463  1.1  christos 	 makefile also as a target to be chosen.
    464  1.1  christos 
    465  1.1  christos 	 The restriction that *FILE must not be a target for a
    466  1.1  christos 	 makefile-mentioned file to be chosen was added by an
    467  1.1  christos 	 inadequately commented change in July 1990; I am not sure off
    468  1.1  christos 	 hand what problem it fixes.
    469  1.1  christos 
    470  1.1  christos 	 In December 1993 I loosened this restriction to allow a file
    471  1.1  christos 	 to be chosen if it is mentioned as a target in a makefile.  This
    472  1.1  christos 	 seem logical.
    473  1.1  christos 
    474  1.1  christos          Special handling for -W / -o: make sure we preserve the special
    475  1.1  christos          values here.  Actually this whole thing is a little bogus: I think
    476  1.1  christos          we should ditch the name/hname thing and look into the renamed
    477  1.1  christos          capability that already exists for files: that is, have a new struct
    478  1.1  christos          file* entry for the VPATH-found file, and set the renamed field if
    479  1.1  christos          we use it.
    480  1.1  christos       */
    481  1.1  christos       {
    482  1.1  christos 	struct file *f = lookup_file (name);
    483  1.1  christos 	if (f != 0)
    484  1.1  christos           {
    485  1.1  christos             exists = not_target || f->is_target;
    486  1.1  christos             if (exists && mtime_ptr
    487  1.1  christos                 && (f->last_mtime == OLD_MTIME || f->last_mtime == NEW_MTIME))
    488  1.1  christos               {
    489  1.1  christos                 *mtime_ptr = f->last_mtime;
    490  1.1  christos                 mtime_ptr = 0;
    491  1.1  christos               }
    492  1.1  christos           }
    493  1.1  christos       }
    494  1.1  christos 
    495  1.1  christos       if (!exists)
    496  1.1  christos 	{
    497  1.1  christos 	  /* That file wasn't mentioned in the makefile.
    498  1.1  christos 	     See if it actually exists.  */
    499  1.1  christos 
    500  1.1  christos #ifdef VMS
    501  1.1  christos 	  exists_in_cache = exists = dir_file_exists_p (vpath[i], filename);
    502  1.1  christos #else
    503  1.1  christos 	  /* Clobber a null into the name at the last slash.
    504  1.1  christos 	     Now NAME is the name of the directory to look in.  */
    505  1.1  christos 	  *n = '\0';
    506  1.1  christos 
    507  1.1  christos 	  /* We know the directory is in the hash table now because either
    508  1.1  christos 	     construct_vpath_list or the code just above put it there.
    509  1.1  christos 	     Does the file we seek exist in it?  */
    510  1.1  christos 	  exists_in_cache = exists = dir_file_exists_p (name, filename);
    511  1.1  christos #endif
    512  1.1  christos 	}
    513  1.1  christos 
    514  1.1  christos       if (exists)
    515  1.1  christos 	{
    516  1.1  christos 	  /* The file is in the directory cache.
    517  1.1  christos 	     Now check that it actually exists in the filesystem.
    518  1.1  christos 	     The cache may be out of date.  When vpath thinks a file
    519  1.1  christos 	     exists, but stat fails for it, confusion results in the
    520  1.1  christos 	     higher levels.  */
    521  1.1  christos 
    522  1.1  christos 	  struct stat st;
    523  1.1  christos 
    524  1.1  christos #ifndef VMS
    525  1.1  christos 	  /* Put the slash back in NAME.  */
    526  1.1  christos 	  *n = '/';
    527  1.1  christos #endif
    528  1.1  christos 
    529  1.1  christos 	  if (exists_in_cache)	/* Makefile-mentioned file need not exist.  */
    530  1.1  christos 	    {
    531  1.1  christos               int e;
    532  1.1  christos 
    533  1.1  christos               EINTRLOOP (e, stat (name, &st)); /* Does it really exist?  */
    534  1.1  christos               if (e != 0)
    535  1.1  christos                 {
    536  1.1  christos                   exists = 0;
    537  1.1  christos                   continue;
    538  1.1  christos                 }
    539  1.1  christos 
    540  1.1  christos               /* Store the modtime into *MTIME_PTR for the caller.  */
    541  1.1  christos               if (mtime_ptr != 0)
    542  1.1  christos                 {
    543  1.1  christos                   *mtime_ptr = FILE_TIMESTAMP_STAT_MODTIME (name, st);
    544  1.1  christos                   mtime_ptr = 0;
    545  1.1  christos                 }
    546  1.1  christos             }
    547  1.1  christos 
    548  1.1  christos           /* We have found a file.
    549  1.1  christos              Store the name we found into *FILE for the caller.  */
    550  1.1  christos 
    551  1.1  christos           *file = savestring (name, (n + 1 - name) + flen);
    552  1.1  christos 
    553  1.1  christos           /* If we get here and mtime_ptr hasn't been set, record
    554  1.1  christos              UNKNOWN_MTIME to indicate this.  */
    555  1.1  christos           if (mtime_ptr != 0)
    556  1.1  christos             *mtime_ptr = UNKNOWN_MTIME;
    557  1.1  christos 
    558  1.1  christos           free (name);
    559  1.1  christos           return 1;
    560  1.1  christos 	}
    561  1.1  christos     }
    562  1.1  christos 
    563  1.1  christos   free (name);
    564  1.1  christos   return 0;
    565  1.1  christos }
    566  1.1  christos 
    567  1.1  christos /* Print the data base of VPATH search paths.  */
    569  1.1  christos 
    570  1.1  christos void
    571  1.1  christos print_vpath_data_base (void)
    572  1.1  christos {
    573  1.1  christos   register unsigned int nvpaths;
    574  1.1  christos   register struct vpath *v;
    575  1.1  christos 
    576  1.1  christos   puts (_("\n# VPATH Search Paths\n"));
    577  1.1  christos 
    578  1.1  christos   nvpaths = 0;
    579  1.1  christos   for (v = vpaths; v != 0; v = v->next)
    580  1.1  christos     {
    581  1.1  christos       register unsigned int i;
    582  1.1  christos 
    583  1.1  christos       ++nvpaths;
    584  1.1  christos 
    585  1.1  christos       printf ("vpath %s ", v->pattern);
    586  1.1  christos 
    587  1.1  christos       for (i = 0; v->searchpath[i] != 0; ++i)
    588  1.1  christos 	printf ("%s%c", v->searchpath[i],
    589  1.1  christos 		v->searchpath[i + 1] == 0 ? '\n' : PATH_SEPARATOR_CHAR);
    590  1.1  christos     }
    591  1.1  christos 
    592  1.1  christos   if (vpaths == 0)
    593  1.1  christos     puts (_("# No `vpath' search paths."));
    594  1.1  christos   else
    595  1.1  christos     printf (_("\n# %u `vpath' search paths.\n"), nvpaths);
    596  1.1  christos 
    597  1.1  christos   if (general_vpath == 0)
    598  1.1  christos     puts (_("\n# No general (`VPATH' variable) search path."));
    599  1.1  christos   else
    600  1.1  christos     {
    601  1.1  christos       register char **path = general_vpath->searchpath;
    602  1.1  christos       register unsigned int i;
    603  1.1  christos 
    604  1.1  christos       fputs (_("\n# General (`VPATH' variable) search path:\n# "), stdout);
    605  1.1  christos 
    606                      for (i = 0; path[i] != 0; ++i)
    607                	printf ("%s%c", path[i],
    608                		path[i + 1] == 0 ? '\n' : PATH_SEPARATOR_CHAR);
    609                    }
    610                }
    611