VirtualBox

source: kBuild/vendor/gnumake/current/vpath.c

Last change on this file was 3138, checked in by bird, 7 years ago

Imported make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6) from https://git.savannah.gnu.org/git/make.git.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette