VirtualBox

source: kBuild/trunk/src/gmake/vpath.c@ 285

Last change on this file since 285 was 154, checked in by bird, 20 years ago

This commit was generated by cvs2svn to compensate for changes in r153,
which included commits to RCS files with non-trunk default branches.

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