VirtualBox

source: kBuild/vendor/gnumake/2003-11-23/file.c@ 3138

Last change on this file since 3138 was 54, checked in by (none), 21 years ago

This commit was manufactured by cvs2svn to create branch 'GNU'.

  • Property svn:eol-style set to native
File size: 21.2 KB
Line 
1/* Target file hash table management for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
32002 Free Software Foundation, Inc.
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Make is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Make; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include "make.h"
22
23#include <assert.h>
24
25#include "dep.h"
26#include "filedef.h"
27#include "job.h"
28#include "commands.h"
29#include "variable.h"
30#include "debug.h"
31#include "hash.h"
32
33
34/* Hash table of files the makefile knows how to make. */
35
36static unsigned long
37file_hash_1 (const void *key)
38{
39 return_ISTRING_HASH_1 (((struct file const *) key)->hname);
40}
41
42static unsigned long
43file_hash_2 (const void *key)
44{
45 return_ISTRING_HASH_2 (((struct file const *) key)->hname);
46}
47
48static int
49file_hash_cmp (const void *x, const void *y)
50{
51 return_ISTRING_COMPARE (((struct file const *) x)->hname,
52 ((struct file const *) y)->hname);
53}
54
55#ifndef FILE_BUCKETS
56#define FILE_BUCKETS 1007
57#endif
58static struct hash_table files;
59
60/* Whether or not .SECONDARY with no prerequisites was given. */
61static int all_secondary = 0;
62
63/* Access the hash table of all file records.
64 lookup_file given a name, return the struct file * for that name,
65 or nil if there is none.
66 enter_file similar, but create one if there is none. */
67
68struct file *
69lookup_file (char *name)
70{
71 register struct file *f;
72 struct file file_key;
73#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
74 register char *lname, *ln;
75#endif
76
77 assert (*name != '\0');
78
79 /* This is also done in parse_file_seq, so this is redundant
80 for names read from makefiles. It is here for names passed
81 on the command line. */
82#ifdef VMS
83# ifndef WANT_CASE_SENSITIVE_TARGETS
84 {
85 register char *n;
86 lname = (char *) malloc (strlen (name) + 1);
87 for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
88 *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n;
89 *ln = '\0';
90 name = lname;
91 }
92# endif
93
94 while (name[0] == '[' && name[1] == ']' && name[2] != '\0')
95 name += 2;
96#endif
97 while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
98 {
99 name += 2;
100 while (*name == '/')
101 /* Skip following slashes: ".//foo" is "foo", not "/foo". */
102 ++name;
103 }
104
105 if (*name == '\0')
106 /* It was all slashes after a dot. */
107#ifdef VMS
108 name = "[]";
109#else
110#ifdef _AMIGA
111 name = "";
112#else
113 name = "./";
114#endif /* AMIGA */
115#endif /* VMS */
116
117 file_key.hname = name;
118 f = (struct file *) hash_find_item (&files, &file_key);
119#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
120 free (lname);
121#endif
122 return f;
123}
124
125struct file *
126enter_file (char *name)
127{
128 register struct file *f;
129 register struct file *new;
130 register struct file **file_slot;
131 struct file file_key;
132#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
133 char *lname, *ln;
134#endif
135
136 assert (*name != '\0');
137
138#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
139 {
140 register char *n;
141 lname = (char *) malloc (strlen (name) + 1);
142 for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
143 {
144 if (isupper ((unsigned char)*n))
145 *ln = tolower ((unsigned char)*n);
146 else
147 *ln = *n;
148 }
149
150 *ln = 0;
151 /* Creates a possible leak, old value of name is unreachable, but I
152 currently don't know how to fix it. */
153 name = lname;
154 }
155#endif
156
157 file_key.hname = name;
158 file_slot = (struct file **) hash_find_slot (&files, &file_key);
159 f = *file_slot;
160 if (! HASH_VACANT (f) && !f->double_colon)
161 {
162#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
163 free(lname);
164#endif
165 return f;
166 }
167
168 new = (struct file *) xmalloc (sizeof (struct file));
169 bzero ((char *) new, sizeof (struct file));
170 new->name = new->hname = name;
171 new->update_status = -1;
172
173 if (HASH_VACANT (f))
174 hash_insert_at (&files, new, file_slot);
175 else
176 {
177 /* There is already a double-colon entry for this file. */
178 new->double_colon = f;
179 while (f->prev != 0)
180 f = f->prev;
181 f->prev = new;
182 }
183
184 return new;
185}
186
187
188/* Rename FILE to NAME. This is not as simple as resetting
189 the `name' member, since it must be put in a new hash bucket,
190 and possibly merged with an existing file called NAME. */
191
192void
193rename_file (struct file *from_file, char *to_hname)
194{
195 rehash_file (from_file, to_hname);
196 while (from_file)
197 {
198 from_file->name = from_file->hname;
199 from_file = from_file->prev;
200 }
201}
202
203/* Rehash FILE to NAME. This is not as simple as resetting
204 the `hname' member, since it must be put in a new hash bucket,
205 and possibly merged with an existing file called NAME. */
206
207void
208rehash_file (struct file *from_file, char *to_hname)
209{
210 struct file file_key;
211 struct file **file_slot;
212 struct file *to_file;
213 struct file *deleted_file;
214 struct file *f;
215
216 file_key.hname = to_hname;
217 if (0 == file_hash_cmp (from_file, &file_key))
218 return;
219
220 file_key.hname = from_file->hname;
221 while (from_file->renamed != 0)
222 from_file = from_file->renamed;
223 if (file_hash_cmp (from_file, &file_key))
224 /* hname changed unexpectedly */
225 abort ();
226
227 deleted_file = hash_delete (&files, from_file);
228 if (deleted_file != from_file)
229 /* from_file isn't the one stored in files */
230 abort ();
231
232 file_key.hname = to_hname;
233 file_slot = (struct file **) hash_find_slot (&files, &file_key);
234 to_file = *file_slot;
235
236 from_file->hname = to_hname;
237 for (f = from_file->double_colon; f != 0; f = f->prev)
238 f->hname = to_hname;
239
240 if (HASH_VACANT (to_file))
241 hash_insert_at (&files, from_file, file_slot);
242 else
243 {
244 /* TO_FILE already exists under TO_HNAME.
245 We must retain TO_FILE and merge FROM_FILE into it. */
246
247 if (from_file->cmds != 0)
248 {
249 if (to_file->cmds == 0)
250 to_file->cmds = from_file->cmds;
251 else if (from_file->cmds != to_file->cmds)
252 {
253 /* We have two sets of commands. We will go with the
254 one given in the rule explicitly mentioning this name,
255 but give a message to let the user know what's going on. */
256 if (to_file->cmds->fileinfo.filenm != 0)
257 error (&from_file->cmds->fileinfo,
258 _("Commands were specified for file `%s' at %s:%lu,"),
259 from_file->name, to_file->cmds->fileinfo.filenm,
260 to_file->cmds->fileinfo.lineno);
261 else
262 error (&from_file->cmds->fileinfo,
263 _("Commands for file `%s' were found by implicit rule search,"),
264 from_file->name);
265 error (&from_file->cmds->fileinfo,
266 _("but `%s' is now considered the same file as `%s'."),
267 from_file->name, to_hname);
268 error (&from_file->cmds->fileinfo,
269 _("Commands for `%s' will be ignored in favor of those for `%s'."),
270 to_hname, from_file->name);
271 }
272 }
273
274 /* Merge the dependencies of the two files. */
275
276 if (to_file->deps == 0)
277 to_file->deps = from_file->deps;
278 else
279 {
280 register struct dep *deps = to_file->deps;
281 while (deps->next != 0)
282 deps = deps->next;
283 deps->next = from_file->deps;
284 }
285
286 merge_variable_set_lists (&to_file->variables, from_file->variables);
287
288 if (to_file->double_colon && from_file->is_target && !from_file->double_colon)
289 fatal (NILF, _("can't rename single-colon `%s' to double-colon `%s'"),
290 from_file->name, to_hname);
291 if (!to_file->double_colon && from_file->double_colon)
292 {
293 if (to_file->is_target)
294 fatal (NILF, _("can't rename double-colon `%s' to single-colon `%s'"),
295 from_file->name, to_hname);
296 else
297 to_file->double_colon = from_file->double_colon;
298 }
299
300 if (from_file->last_mtime > to_file->last_mtime)
301 /* %%% Kludge so -W wins on a file that gets vpathized. */
302 to_file->last_mtime = from_file->last_mtime;
303
304 to_file->mtime_before_update = from_file->mtime_before_update;
305
306#define MERGE(field) to_file->field |= from_file->field
307 MERGE (precious);
308 MERGE (tried_implicit);
309 MERGE (updating);
310 MERGE (updated);
311 MERGE (is_target);
312 MERGE (cmd_target);
313 MERGE (phony);
314 MERGE (ignore_vpath);
315#undef MERGE
316
317 from_file->renamed = to_file;
318 }
319}
320
321
322/* Remove all nonprecious intermediate files.
323 If SIG is nonzero, this was caused by a fatal signal,
324 meaning that a different message will be printed, and
325 the message will go to stderr rather than stdout. */
326
327void
328remove_intermediates (int sig)
329{
330 register struct file **file_slot;
331 register struct file **file_end;
332 int doneany = 0;
333
334 /* If there's no way we will ever remove anything anyway, punt early. */
335 if (question_flag || touch_flag || all_secondary)
336 return;
337
338 if (sig && just_print_flag)
339 return;
340
341 file_slot = (struct file **) files.ht_vec;
342 file_end = file_slot + files.ht_size;
343 for ( ; file_slot < file_end; file_slot++)
344 if (! HASH_VACANT (*file_slot))
345 {
346 register struct file *f = *file_slot;
347 if (f->intermediate && (f->dontcare || !f->precious)
348 && !f->secondary && !f->cmd_target)
349 {
350 int status;
351 if (f->update_status == -1)
352 /* If nothing would have created this file yet,
353 don't print an "rm" command for it. */
354 continue;
355 if (just_print_flag)
356 status = 0;
357 else
358 {
359 status = unlink (f->name);
360 if (status < 0 && errno == ENOENT)
361 continue;
362 }
363 if (!f->dontcare)
364 {
365 if (sig)
366 error (NILF, _("*** Deleting intermediate file `%s'"), f->name);
367 else
368 {
369 if (! doneany)
370 DB (DB_BASIC, (_("Removing intermediate files...\n")));
371 if (!silent_flag)
372 {
373 if (! doneany)
374 {
375 fputs ("rm ", stdout);
376 doneany = 1;
377 }
378 else
379 putchar (' ');
380 fputs (f->name, stdout);
381 fflush (stdout);
382 }
383 }
384 if (status < 0)
385 perror_with_name ("unlink: ", f->name);
386 }
387 }
388 }
389
390 if (doneany && !sig)
391 {
392 putchar ('\n');
393 fflush (stdout);
394 }
395}
396
397
398/* Set the intermediate flag. */
399
400static void
401set_intermediate (const void *item)
402{
403 struct file *f = (struct file *) item;
404 f->intermediate = 1;
405}
406
407/* For each dependency of each file, make the `struct dep' point
408 at the appropriate `struct file' (which may have to be created).
409
410 Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
411 and various other special targets. */
412
413void
414snap_deps (void)
415{
416 register struct file *f;
417 register struct file *f2;
418 register struct dep *d;
419 register struct file **file_slot_0;
420 register struct file **file_slot;
421 register struct file **file_end;
422
423 /* Enter each dependency name as a file. */
424 /* We must use hash_dump (), because within this loop
425 we might add new files to the table, possibly causing
426 an in-situ table expansion. */
427 file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
428 file_end = file_slot_0 + files.ht_fill;
429 for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
430 for (f2 = *file_slot; f2 != 0; f2 = f2->prev)
431 for (d = f2->deps; d != 0; d = d->next)
432 if (d->name != 0)
433 {
434 d->file = lookup_file (d->name);
435 if (d->file == 0)
436 d->file = enter_file (d->name);
437 else
438 free (d->name);
439 d->name = 0;
440 }
441 free (file_slot_0);
442
443 for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
444 for (d = f->deps; d != 0; d = d->next)
445 for (f2 = d->file; f2 != 0; f2 = f2->prev)
446 f2->precious = 1;
447
448 for (f = lookup_file (".LOW_RESOLUTION_TIME"); f != 0; f = f->prev)
449 for (d = f->deps; d != 0; d = d->next)
450 for (f2 = d->file; f2 != 0; f2 = f2->prev)
451 f2->low_resolution_time = 1;
452
453 for (f = lookup_file (".PHONY"); f != 0; f = f->prev)
454 for (d = f->deps; d != 0; d = d->next)
455 for (f2 = d->file; f2 != 0; f2 = f2->prev)
456 {
457 /* Mark this file as phony and nonexistent. */
458 f2->phony = 1;
459 f2->last_mtime = NONEXISTENT_MTIME;
460 f2->mtime_before_update = NONEXISTENT_MTIME;
461 }
462
463 for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
464 {
465 /* .INTERMEDIATE with deps listed
466 marks those deps as intermediate files. */
467 for (d = f->deps; d != 0; d = d->next)
468 for (f2 = d->file; f2 != 0; f2 = f2->prev)
469 f2->intermediate = 1;
470 /* .INTERMEDIATE with no deps does nothing.
471 Marking all files as intermediates is useless
472 since the goal targets would be deleted after they are built. */
473 }
474
475 for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev)
476 {
477 /* .SECONDARY with deps listed
478 marks those deps as intermediate files
479 in that they don't get rebuilt if not actually needed;
480 but unlike real intermediate files,
481 these are not deleted after make finishes. */
482 if (f->deps)
483 for (d = f->deps; d != 0; d = d->next)
484 for (f2 = d->file; f2 != 0; f2 = f2->prev)
485 f2->intermediate = f2->secondary = 1;
486 /* .SECONDARY with no deps listed marks *all* files that way. */
487 else
488 {
489 all_secondary = 1;
490 hash_map (&files, set_intermediate);
491 }
492 }
493
494 f = lookup_file (".EXPORT_ALL_VARIABLES");
495 if (f != 0 && f->is_target)
496 export_all_variables = 1;
497
498 f = lookup_file (".IGNORE");
499 if (f != 0 && f->is_target)
500 {
501 if (f->deps == 0)
502 ignore_errors_flag = 1;
503 else
504 for (d = f->deps; d != 0; d = d->next)
505 for (f2 = d->file; f2 != 0; f2 = f2->prev)
506 f2->command_flags |= COMMANDS_NOERROR;
507 }
508
509 f = lookup_file (".SILENT");
510 if (f != 0 && f->is_target)
511 {
512 if (f->deps == 0)
513 silent_flag = 1;
514 else
515 for (d = f->deps; d != 0; d = d->next)
516 for (f2 = d->file; f2 != 0; f2 = f2->prev)
517 f2->command_flags |= COMMANDS_SILENT;
518 }
519
520 f = lookup_file (".POSIX");
521 if (f != 0 && f->is_target)
522 posix_pedantic = 1;
523
524 f = lookup_file (".NOTPARALLEL");
525 if (f != 0 && f->is_target)
526 not_parallel = 1;
527}
528
529
530/* Set the `command_state' member of FILE and all its `also_make's. */
531
532void
533set_command_state (struct file *file, int state)
534{
535 struct dep *d;
536
537 file->command_state = state;
538
539 for (d = file->also_make; d != 0; d = d->next)
540 d->file->command_state = state;
541}
542
543
544/* Convert an external file timestamp to internal form. */
545
546FILE_TIMESTAMP
547file_timestamp_cons (const char *fname, time_t s, int ns)
548{
549 int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0);
550 FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS;
551 FILE_TIMESTAMP ts = product + offset;
552
553 if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX)
554 && product <= ts && ts <= ORDINARY_MTIME_MAX))
555 {
556 char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
557 ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX;
558 file_timestamp_sprintf (buf, ts);
559 error (NILF, _("%s: Timestamp out of range; substituting %s"),
560 fname ? fname : _("Current time"), buf);
561 }
562
563 return ts;
564}
565
566
567/* Return the current time as a file timestamp, setting *RESOLUTION to
568 its resolution. */
569FILE_TIMESTAMP
570file_timestamp_now (int *resolution)
571{
572 int r;
573 time_t s;
574 int ns;
575
576 /* Don't bother with high-resolution clocks if file timestamps have
577 only one-second resolution. The code below should work, but it's
578 not worth the hassle of debugging it on hosts where it fails. */
579#if FILE_TIMESTAMP_HI_RES
580# if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME
581 {
582 struct timespec timespec;
583 if (clock_gettime (CLOCK_REALTIME, &timespec) == 0)
584 {
585 r = 1;
586 s = timespec.tv_sec;
587 ns = timespec.tv_nsec;
588 goto got_time;
589 }
590 }
591# endif
592# if HAVE_GETTIMEOFDAY
593 {
594 struct timeval timeval;
595 if (gettimeofday (&timeval, 0) == 0)
596 {
597 r = 1000;
598 s = timeval.tv_sec;
599 ns = timeval.tv_usec * 1000;
600 goto got_time;
601 }
602 }
603# endif
604#endif
605
606 r = 1000000000;
607 s = time ((time_t *) 0);
608 ns = 0;
609
610#if FILE_TIMESTAMP_HI_RES
611 got_time:
612#endif
613 *resolution = r;
614 return file_timestamp_cons (0, s, ns);
615}
616
617/* Place into the buffer P a printable representation of the file
618 timestamp TS. */
619void
620file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
621{
622 time_t t = FILE_TIMESTAMP_S (ts);
623 struct tm *tm = localtime (&t);
624
625 if (tm)
626 sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d",
627 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
628 tm->tm_hour, tm->tm_min, tm->tm_sec);
629 else if (t < 0)
630 sprintf (p, "%ld", (long) t);
631 else
632 sprintf (p, "%lu", (unsigned long) t);
633 p += strlen (p);
634
635 /* Append nanoseconds as a fraction, but remove trailing zeros.
636 We don't know the actual timestamp resolution, since clock_getres
637 applies only to local times, whereas this timestamp might come
638 from a remote filesystem. So removing trailing zeros is the
639 best guess that we can do. */
640 sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts));
641 p += strlen (p) - 1;
642 while (*p == '0')
643 p--;
644 p += *p != '.';
645
646 *p = '\0';
647}
648
649
650/* Print the data base of files. */
651
652static void
653print_file (const void *item)
654{
655 struct file *f = (struct file *) item;
656 struct dep *d;
657 struct dep *ood = 0;
658
659 putchar ('\n');
660 if (!f->is_target)
661 puts (_("# Not a target:"));
662 printf ("%s:%s", f->name, f->double_colon ? ":" : "");
663
664 /* Print all normal dependencies; note any order-only deps. */
665 for (d = f->deps; d != 0; d = d->next)
666 if (! d->ignore_mtime)
667 printf (" %s", dep_name (d));
668 else if (! ood)
669 ood = d;
670
671 /* Print order-only deps, if we have any. */
672 if (ood)
673 {
674 printf (" | %s", dep_name (ood));
675 for (d = ood->next; d != 0; d = d->next)
676 if (d->ignore_mtime)
677 printf (" %s", dep_name (d));
678 }
679
680 putchar ('\n');
681
682 if (f->precious)
683 puts (_("# Precious file (prerequisite of .PRECIOUS)."));
684 if (f->phony)
685 puts (_("# Phony target (prerequisite of .PHONY)."));
686 if (f->cmd_target)
687 puts (_("# Command-line target."));
688 if (f->dontcare)
689 puts (_("# A default or MAKEFILES makefile."));
690 puts (f->tried_implicit
691 ? _("# Implicit rule search has been done.")
692 : _("# Implicit rule search has not been done."));
693 if (f->stem != 0)
694 printf (_("# Implicit/static pattern stem: `%s'\n"), f->stem);
695 if (f->intermediate)
696 puts (_("# File is an intermediate prerequisite."));
697 if (f->also_make != 0)
698 {
699 fputs (_("# Also makes:"), stdout);
700 for (d = f->also_make; d != 0; d = d->next)
701 printf (" %s", dep_name (d));
702 putchar ('\n');
703 }
704 if (f->last_mtime == UNKNOWN_MTIME)
705 puts (_("# Modification time never checked."));
706 else if (f->last_mtime == NONEXISTENT_MTIME)
707 puts (_("# File does not exist."));
708 else if (f->last_mtime == OLD_MTIME)
709 puts (_("# File is very old."));
710 else
711 {
712 char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
713 file_timestamp_sprintf (buf, f->last_mtime);
714 printf (_("# Last modified %s\n"), buf);
715 }
716 puts (f->updated
717 ? _("# File has been updated.") : _("# File has not been updated."));
718 switch (f->command_state)
719 {
720 case cs_running:
721 puts (_("# Commands currently running (THIS IS A BUG)."));
722 break;
723 case cs_deps_running:
724 puts (_("# Dependencies commands running (THIS IS A BUG)."));
725 break;
726 case cs_not_started:
727 case cs_finished:
728 switch (f->update_status)
729 {
730 case -1:
731 break;
732 case 0:
733 puts (_("# Successfully updated."));
734 break;
735 case 1:
736 assert (question_flag);
737 puts (_("# Needs to be updated (-q is set)."));
738 break;
739 case 2:
740 puts (_("# Failed to be updated."));
741 break;
742 default:
743 puts (_("# Invalid value in `update_status' member!"));
744 fflush (stdout);
745 fflush (stderr);
746 abort ();
747 }
748 break;
749 default:
750 puts (_("# Invalid value in `command_state' member!"));
751 fflush (stdout);
752 fflush (stderr);
753 abort ();
754 }
755
756 if (f->variables != 0)
757 print_file_variables (f);
758
759 if (f->cmds != 0)
760 print_commands (f->cmds);
761}
762
763void
764print_file_data_base (void)
765{
766 puts (_("\n# Files"));
767
768 hash_map (&files, print_file);
769
770 fputs (_("\n# files hash-table stats:\n# "), stdout);
771 hash_print_stats (&files, stdout);
772}
773
774#define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500)
775
776char *
777build_target_list (char *value)
778{
779 static unsigned long last_targ_count = 0;
780
781 if (files.ht_fill != last_targ_count)
782 {
783 unsigned long max = EXPANSION_INCREMENT (strlen (value));
784 unsigned long len;
785 char *p;
786 struct file **fp = (struct file **) files.ht_vec;
787 struct file **end = &fp[files.ht_size];
788
789 /* Make sure we have at least MAX bytes in the allocated buffer. */
790 value = xrealloc (value, max);
791
792 p = value;
793 len = 0;
794 for (; fp < end; ++fp)
795 if (!HASH_VACANT (*fp) && (*fp)->is_target)
796 {
797 struct file *f = *fp;
798 int l = strlen (f->name);
799
800 len += l + 1;
801 if (len > max)
802 {
803 unsigned long off = p - value;
804
805 max += EXPANSION_INCREMENT (l + 1);
806 value = xrealloc (value, max);
807 p = &value[off];
808 }
809
810 bcopy (f->name, p, l);
811 p += l;
812 *(p++) = ' ';
813 }
814 *(p-1) = '\0';
815
816 last_targ_count = files.ht_fill;
817 }
818
819 return value;
820}
821
822void
823init_hash_files (void)
824{
825 hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp);
826}
827
828/* EOF */
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