VirtualBox

source: kBuild/trunk/src/kmk/vpath.c@ 3387

Last change on this file since 3387 was 3140, checked in by bird, 6 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

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

© 2023 Oracle
ContactPrivacy policyTerms of Use