VirtualBox

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

Last change on this file since 2634 was 2592, checked in by bird, 13 years ago

kmk build fixes for win.amd64.

  • Property svn:eol-style set to native
File size: 17.8 KB
Line 
1/* Implementation of pattern-matching file search paths for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
31998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
42010 Free Software Foundation, Inc.
5This file is part of GNU Make.
6
7GNU Make is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 3 of the License, or (at your option) any later
10version.
11
12GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License along with
17this program. If not, see <http://www.gnu.org/licenses/>. */
18
19#include "make.h"
20#include "filedef.h"
21#include "variable.h"
22#ifdef WINDOWS32
23#include "pathstuff.h"
24#endif
25
26
27/* Structure used to represent a selective VPATH searchpath. */
28
29struct vpath
30 {
31 struct vpath *next; /* Pointer to next struct in the linked list. */
32 const char *pattern;/* The pattern to match. */
33 const char *percent;/* Pointer into `pattern' where the `%' is. */
34 unsigned int patlen;/* Length of the pattern. */
35 const char **searchpath; /* Null-terminated list of directories. */
36 unsigned int maxlen;/* Maximum length of any entry in the list. */
37 };
38
39/* Linked-list of all selective VPATHs. */
40
41static struct vpath *vpaths;
42
43/* Structure for the general VPATH given in the variable. */
44
45static struct vpath *general_vpath;
46
47/* Structure for GPATH given in the variable. */
48
49static struct vpath *gpaths;
50
51
52
53/* Reverse the chain of selective VPATH lists so they will be searched in the
54 order given in the makefiles and construct the list from the VPATH
55 variable. */
56
57void
58build_vpath_lists ()
59{
60 register struct vpath *new = 0;
61 register struct vpath *old, *nexto;
62 register char *p;
63#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
64 char expr[64];
65#endif
66
67 /* Reverse the chain. */
68 for (old = vpaths; old != 0; old = nexto)
69 {
70 nexto = old->next;
71 old->next = new;
72 new = old;
73 }
74
75 vpaths = new;
76
77 /* If there is a VPATH variable with a nonnull value, construct the
78 general VPATH list from it. We use variable_expand rather than just
79 calling lookup_variable so that it will be recursively expanded. */
80
81 {
82 /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
83 int save = warn_undefined_variables_flag;
84 warn_undefined_variables_flag = 0;
85#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
86 p = variable_expand (strcpy (expr, "$(strip $(VPATH))"));
87#else
88 p = variable_expand ("$(strip $(VPATH))");
89#endif
90
91 warn_undefined_variables_flag = save;
92 }
93
94 if (*p != '\0')
95 {
96 /* Save the list of vpaths. */
97 struct vpath *save_vpaths = vpaths;
98 char gp[] = "%";
99
100 /* Empty `vpaths' so the new one will have no next, and `vpaths'
101 will still be nil if P contains no existing directories. */
102 vpaths = 0;
103
104 /* Parse P. */
105 construct_vpath_list (gp, p);
106
107 /* Store the created path as the general path,
108 and restore the old list of vpaths. */
109 general_vpath = vpaths;
110 vpaths = save_vpaths;
111 }
112
113 /* If there is a GPATH variable with a nonnull value, construct the
114 GPATH list from it. We use variable_expand rather than just
115 calling lookup_variable so that it will be recursively expanded. */
116
117 {
118 /* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
119 int save = warn_undefined_variables_flag;
120 warn_undefined_variables_flag = 0;
121
122#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
123 p = variable_expand (strcpy (expr, "$(strip $(GPATH))"));
124#else
125 p = variable_expand ("$(strip $(GPATH))");
126#endif
127
128 warn_undefined_variables_flag = save;
129 }
130
131 if (*p != '\0')
132 {
133 /* Save the list of vpaths. */
134 struct vpath *save_vpaths = vpaths;
135 char gp[] = "%";
136
137 /* Empty `vpaths' so the new one will have no next, and `vpaths'
138 will still be nil if P contains no existing directories. */
139 vpaths = 0;
140
141 /* Parse P. */
142 construct_vpath_list (gp, p);
143
144 /* Store the created path as the GPATH,
145 and restore the old list of vpaths. */
146 gpaths = vpaths;
147 vpaths = save_vpaths;
148 }
149}
150
151
152/* Construct the VPATH listing for the PATTERN and DIRPATH given.
153
154 This function is called to generate selective VPATH lists and also for
155 the general VPATH list (which is in fact just a selective VPATH that
156 is applied to everything). The returned pointer is either put in the
157 linked list of all selective VPATH lists or in the GENERAL_VPATH
158 variable.
159
160 If DIRPATH is nil, remove all previous listings with the same
161 pattern. If PATTERN is nil, remove all VPATH listings. Existing
162 and readable directories that are not "." given in the DIRPATH
163 separated by the path element separator (defined in make.h) are
164 loaded into the directory hash table if they are not there already
165 and put in the VPATH searchpath for the given pattern with trailing
166 slashes stripped off if present (and if the directory is not the
167 root, "/"). The length of the longest entry in the list is put in
168 the structure as well. The new entry will be at the head of the
169 VPATHS chain. */
170
171void
172construct_vpath_list (char *pattern, char *dirpath)
173{
174 unsigned int elem;
175 char *p;
176 const char **vpath;
177 unsigned int maxvpath;
178 unsigned int maxelem;
179 const char *percent = NULL;
180
181 if (pattern != 0)
182 percent = find_percent (pattern);
183
184 if (dirpath == 0)
185 {
186 /* Remove matching listings. */
187 struct vpath *path, *lastpath;
188
189 lastpath = 0;
190 path = vpaths;
191 while (path != 0)
192 {
193 struct vpath *next = path->next;
194
195 if (pattern == 0
196 || (((percent == 0 && path->percent == 0)
197 || (percent - pattern == path->percent - path->pattern))
198 && streq (pattern, path->pattern)))
199 {
200 /* Remove it from the linked list. */
201 if (lastpath == 0)
202 vpaths = path->next;
203 else
204 lastpath->next = next;
205
206 /* Free its unused storage. */
207 /* MSVC erroneously warns without a cast here. */
208 free ((void *)path->searchpath);
209 free (path);
210 }
211 else
212 lastpath = path;
213
214 path = next;
215 }
216
217 return;
218 }
219
220#ifdef WINDOWS32
221 convert_vpath_to_windows32(dirpath, ';');
222#endif
223
224 /* Skip over any initial separators and blanks. */
225 while (*dirpath == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*dirpath))
226 ++dirpath;
227
228 /* Figure out the maximum number of VPATH entries and put it in
229 MAXELEM. We start with 2, one before the first separator and one
230 nil (the list terminator) and increment our estimated number for
231 each separator or blank we find. */
232 maxelem = 2;
233 p = dirpath;
234 while (*p != '\0')
235 if (*p++ == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
236 ++maxelem;
237
238 vpath = xmalloc (maxelem * sizeof (const char *));
239 maxvpath = 0;
240
241 elem = 0;
242 p = dirpath;
243 while (*p != '\0')
244 {
245 char *v;
246 unsigned int len;
247
248 /* Find the end of this entry. */
249 v = p;
250 while (*p != '\0'
251#if defined(HAVE_DOS_PATHS) && (PATH_SEPARATOR_CHAR == ':')
252 /* Platforms whose PATH_SEPARATOR_CHAR is ':' and which
253 also define HAVE_DOS_PATHS would like us to recognize
254 colons after the drive letter in the likes of
255 "D:/foo/bar:C:/xyzzy". */
256 && (*p != PATH_SEPARATOR_CHAR
257 || (p == v + 1 && (p[1] == '/' || p[1] == '\\')))
258#else
259 && *p != PATH_SEPARATOR_CHAR
260#endif
261 && !isblank ((unsigned char)*p))
262 ++p;
263
264 len = p - v;
265 /* Make sure there's no trailing slash,
266 but still allow "/" as a directory. */
267#if defined(__MSDOS__) || defined(__EMX__) || defined(HAVE_DOS_PATHS)
268 /* We need also to leave alone a trailing slash in "d:/". */
269 if (len > 3 || (len > 1 && v[1] != ':'))
270#endif
271 if (len > 1 && p[-1] == '/')
272 --len;
273
274 /* Put the directory on the vpath list. */
275 if (len > 1 || *v != '.')
276 {
277 vpath[elem++] = dir_name (strcache_add_len (v, len));
278 if (len > maxvpath)
279 maxvpath = len;
280 }
281
282 /* Skip over separators and blanks between entries. */
283 while (*p == PATH_SEPARATOR_CHAR || isblank ((unsigned char)*p))
284 ++p;
285 }
286
287 if (elem > 0)
288 {
289 struct vpath *path;
290 /* ELEM is now incremented one element past the last
291 entry, to where the nil-pointer terminator goes.
292 Usually this is maxelem - 1. If not, shrink down. */
293 if (elem < (maxelem - 1))
294 vpath = (const char **)xrealloc (vpath, (elem+1) * sizeof (const char *));
295
296 /* Put the nil-pointer terminator on the end of the VPATH list. */
297 vpath[elem] = NULL;
298
299 /* Construct the vpath structure and put it into the linked list. */
300 path = xmalloc (sizeof (struct vpath));
301 path->searchpath = vpath;
302 path->maxlen = maxvpath;
303 path->next = vpaths;
304 vpaths = path;
305
306 /* Set up the members. */
307 path->pattern = strcache_add (pattern);
308 path->patlen = strlen (pattern);
309 path->percent = percent ? path->pattern + (percent - pattern) : 0;
310 }
311 else
312 /* There were no entries, so free whatever space we allocated. */
313 /* MSVC erroneously warns without a cast here. */
314 free ((void *)vpath);
315}
316
317
318/* Search the GPATH list for a pathname string that matches the one passed
319 in. If it is found, return 1. Otherwise we return 0. */
320
321int
322gpath_search (const char *file, unsigned int len)
323{
324 const char **gp;
325
326 if (gpaths && (len <= gpaths->maxlen))
327 for (gp = gpaths->searchpath; *gp != NULL; ++gp)
328 if (strneq (*gp, file, len) && (*gp)[len] == '\0')
329 return 1;
330
331 return 0;
332}
333
334
335
336/* Search the given VPATH list for a directory where the name pointed to by
337 FILE exists. If it is found, we return a cached name of the existing file
338 and set *MTIME_PTR (if MTIME_PTR is not NULL) to its modtime (or zero if no
339 stat call was done). Also set the matching directory index in PATH_INDEX
340 if it is not NULL. Otherwise we return NULL. */
341
342static const char *
343selective_vpath_search (struct vpath *path, const char *file,
344 FILE_TIMESTAMP *mtime_ptr, unsigned int* path_index)
345{
346 int not_target;
347 char *name;
348 const char *n;
349 const char *filename;
350 const char **vpath = path->searchpath;
351 unsigned int maxvpath = path->maxlen;
352 unsigned int i;
353 unsigned int flen, vlen, name_dplen;
354 int exists = 0;
355
356 /* Find out if *FILE is a target.
357 If and only if it is NOT a target, we will accept prospective
358 files that don't exist but are mentioned in a makefile. */
359 {
360 struct file *f = lookup_file (file);
361 not_target = f == 0 || !f->is_target;
362 }
363
364 flen = strlen (file);
365
366 /* Split *FILE into a directory prefix and a name-within-directory.
367 NAME_DPLEN gets the length of the prefix; FILENAME gets the pointer to
368 the name-within-directory and FLEN is its length. */
369
370 n = strrchr (file, '/');
371#ifdef HAVE_DOS_PATHS
372 /* We need the rightmost slash or backslash. */
373 {
374 const char *bslash = strrchr(file, '\\');
375 if (!n || bslash > n)
376 n = bslash;
377 }
378#endif
379 name_dplen = n != 0 ? n - file : 0;
380 filename = name_dplen > 0 ? n + 1 : file;
381 if (name_dplen > 0)
382 flen -= name_dplen + 1;
383
384 /* Get enough space for the biggest VPATH entry, a slash, the directory
385 prefix that came with FILE, another slash (although this one may not
386 always be necessary), the filename, and a null terminator. */
387 name = alloca (maxvpath + 1 + name_dplen + 1 + flen + 1);
388
389 /* Try each VPATH entry. */
390 for (i = 0; vpath[i] != 0; ++i)
391 {
392 int exists_in_cache = 0;
393 char *p;
394
395 p = name;
396
397 /* Put the next VPATH entry into NAME at P and increment P past it. */
398 vlen = strlen (vpath[i]);
399 memcpy (p, vpath[i], vlen);
400 p += vlen;
401
402 /* Add the directory prefix already in *FILE. */
403 if (name_dplen > 0)
404 {
405#ifndef VMS
406 *p++ = '/';
407#endif
408 memcpy (p, file, name_dplen);
409 p += name_dplen;
410 }
411
412#ifdef HAVE_DOS_PATHS
413 /* Cause the next if to treat backslash and slash alike. */
414 if (p != name && p[-1] == '\\' )
415 p[-1] = '/';
416#endif
417 /* Now add the name-within-directory at the end of NAME. */
418#ifndef VMS
419 if (p != name && 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 exists_in_cache = exists = dir_file_exists_p (vpath[i], filename);
470#else
471 /* Clobber a null into the name at the last slash.
472 Now NAME is the name of the directory to look in. */
473 *p = '\0';
474
475 /* We know the directory is in the hash table now because either
476 construct_vpath_list or the code just above put it there.
477 Does the file we seek exist in it? */
478 exists_in_cache = exists = dir_file_exists_p (name, filename);
479#endif
480 }
481
482 if (exists)
483 {
484 /* The file is in the directory cache.
485 Now check that it actually exists in the filesystem.
486 The cache may be out of date. When vpath thinks a file
487 exists, but stat fails for it, confusion results in the
488 higher levels. */
489
490 struct stat st;
491
492#ifndef VMS
493 /* Put the slash back in NAME. */
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
541const char *
542vpath_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
593/* Print the data base of VPATH search paths. */
594
595void
596print_vpath_data_base (void)
597{
598 unsigned int nvpaths;
599 struct vpath *v;
600
601 puts (_("\n# VPATH Search Paths\n"));
602
603 nvpaths = 0;
604 for (v = vpaths; v != 0; v = v->next)
605 {
606 register unsigned int i;
607
608 ++nvpaths;
609
610 printf ("vpath %s ", v->pattern);
611
612 for (i = 0; v->searchpath[i] != 0; ++i)
613 printf ("%s%c", v->searchpath[i],
614 v->searchpath[i + 1] == 0 ? '\n' : PATH_SEPARATOR_CHAR);
615 }
616
617 if (vpaths == 0)
618 puts (_("# No `vpath' search paths."));
619 else
620 printf (_("\n# %u `vpath' search paths.\n"), nvpaths);
621
622 if (general_vpath == 0)
623 puts (_("\n# No general (`VPATH' variable) search path."));
624 else
625 {
626 const char **path = general_vpath->searchpath;
627 unsigned int i;
628
629 fputs (_("\n# General (`VPATH' variable) search path:\n# "), stdout);
630
631 for (i = 0; path[i] != 0; ++i)
632 printf ("%s%c", path[i],
633 path[i + 1] == 0 ? '\n' : PATH_SEPARATOR_CHAR);
634 }
635}
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