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