source: trunk/src/gmake/file.c@ 217

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

More proper .NOTPARALLEL.

  • Property svn:eol-style set to native
File size: 21.5 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 /* kmk changed */
525 f = lookup_file (".NOTPARALLEL");
526 if (f != 0 && f->is_target)
527 {
528 if (f->deps == 0)
529 not_parallel = 1;
530 else
531 for (d = f->deps; d != 0; d = d->next)
532 for (f2 = d->file; f2 != 0; f2 = f2->prev)
533 f2->command_flags |= COMMANDS_NOTPARALLEL;
534 }
535
536}
537
538
539/* Set the `command_state' member of FILE and all its `also_make's. */
540
541void
542set_command_state (struct file *file, enum cmd_state state)
543{
544 struct dep *d;
545
546 file->command_state = state;
547
548 for (d = file->also_make; d != 0; d = d->next)
549 d->file->command_state = state;
550}
551
552
553/* Convert an external file timestamp to internal form. */
554
555FILE_TIMESTAMP
556file_timestamp_cons (const char *fname, time_t s, int ns)
557{
558 int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0);
559 FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS;
560 FILE_TIMESTAMP ts = product + offset;
561
562 if (! (s <= FILE_TIMESTAMP_S (ORDINARY_MTIME_MAX)
563 && product <= ts && ts <= ORDINARY_MTIME_MAX))
564 {
565 char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
566 ts = s <= OLD_MTIME ? ORDINARY_MTIME_MIN : ORDINARY_MTIME_MAX;
567 file_timestamp_sprintf (buf, ts);
568 error (NILF, _("%s: Timestamp out of range; substituting %s"),
569 fname ? fname : _("Current time"), buf);
570 }
571
572 return ts;
573}
574
575
576/* Return the current time as a file timestamp, setting *RESOLUTION to
577 its resolution. */
578FILE_TIMESTAMP
579file_timestamp_now (int *resolution)
580{
581 int r;
582 time_t s;
583 int ns;
584
585 /* Don't bother with high-resolution clocks if file timestamps have
586 only one-second resolution. The code below should work, but it's
587 not worth the hassle of debugging it on hosts where it fails. */
588#if FILE_TIMESTAMP_HI_RES
589# if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME
590 {
591 struct timespec timespec;
592 if (clock_gettime (CLOCK_REALTIME, &timespec) == 0)
593 {
594 r = 1;
595 s = timespec.tv_sec;
596 ns = timespec.tv_nsec;
597 goto got_time;
598 }
599 }
600# endif
601# if HAVE_GETTIMEOFDAY
602 {
603 struct timeval timeval;
604 if (gettimeofday (&timeval, 0) == 0)
605 {
606 r = 1000;
607 s = timeval.tv_sec;
608 ns = timeval.tv_usec * 1000;
609 goto got_time;
610 }
611 }
612# endif
613#endif
614
615 r = 1000000000;
616 s = time ((time_t *) 0);
617 ns = 0;
618
619#if FILE_TIMESTAMP_HI_RES
620 got_time:
621#endif
622 *resolution = r;
623 return file_timestamp_cons (0, s, ns);
624}
625
626/* Place into the buffer P a printable representation of the file
627 timestamp TS. */
628void
629file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
630{
631 time_t t = FILE_TIMESTAMP_S (ts);
632 struct tm *tm = localtime (&t);
633
634 if (tm)
635 sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d",
636 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
637 tm->tm_hour, tm->tm_min, tm->tm_sec);
638 else if (t < 0)
639 sprintf (p, "%ld", (long) t);
640 else
641 sprintf (p, "%lu", (unsigned long) t);
642 p += strlen (p);
643
644 /* Append nanoseconds as a fraction, but remove trailing zeros.
645 We don't know the actual timestamp resolution, since clock_getres
646 applies only to local times, whereas this timestamp might come
647 from a remote filesystem. So removing trailing zeros is the
648 best guess that we can do. */
649 sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts));
650 p += strlen (p) - 1;
651 while (*p == '0')
652 p--;
653 p += *p != '.';
654
655 *p = '\0';
656}
657
658
659/* Print the data base of files. */
660
661static void
662print_file (const void *item)
663{
664 struct file *f = (struct file *) item;
665 struct dep *d;
666 struct dep *ood = 0;
667
668 putchar ('\n');
669 if (!f->is_target)
670 puts (_("# Not a target:"));
671 printf ("%s:%s", f->name, f->double_colon ? ":" : "");
672
673 /* Print all normal dependencies; note any order-only deps. */
674 for (d = f->deps; d != 0; d = d->next)
675 if (! d->ignore_mtime)
676 printf (" %s", dep_name (d));
677 else if (! ood)
678 ood = d;
679
680 /* Print order-only deps, if we have any. */
681 if (ood)
682 {
683 printf (" | %s", dep_name (ood));
684 for (d = ood->next; d != 0; d = d->next)
685 if (d->ignore_mtime)
686 printf (" %s", dep_name (d));
687 }
688
689 putchar ('\n');
690
691 if (f->precious)
692 puts (_("# Precious file (prerequisite of .PRECIOUS)."));
693 if (f->phony)
694 puts (_("# Phony target (prerequisite of .PHONY)."));
695 if (f->cmd_target)
696 puts (_("# Command-line target."));
697 if (f->dontcare)
698 puts (_("# A default or MAKEFILES makefile."));
699 puts (f->tried_implicit
700 ? _("# Implicit rule search has been done.")
701 : _("# Implicit rule search has not been done."));
702 if (f->stem != 0)
703 printf (_("# Implicit/static pattern stem: `%s'\n"), f->stem);
704 if (f->intermediate)
705 puts (_("# File is an intermediate prerequisite."));
706 if (f->also_make != 0)
707 {
708 fputs (_("# Also makes:"), stdout);
709 for (d = f->also_make; d != 0; d = d->next)
710 printf (" %s", dep_name (d));
711 putchar ('\n');
712 }
713 if (f->last_mtime == UNKNOWN_MTIME)
714 puts (_("# Modification time never checked."));
715 else if (f->last_mtime == NONEXISTENT_MTIME)
716 puts (_("# File does not exist."));
717 else if (f->last_mtime == OLD_MTIME)
718 puts (_("# File is very old."));
719 else
720 {
721 char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
722 file_timestamp_sprintf (buf, f->last_mtime);
723 printf (_("# Last modified %s\n"), buf);
724 }
725 puts (f->updated
726 ? _("# File has been updated.") : _("# File has not been updated."));
727 switch (f->command_state)
728 {
729 case cs_running:
730 puts (_("# Commands currently running (THIS IS A BUG)."));
731 break;
732 case cs_deps_running:
733 puts (_("# Dependencies commands running (THIS IS A BUG)."));
734 break;
735 case cs_not_started:
736 case cs_finished:
737 switch (f->update_status)
738 {
739 case -1:
740 break;
741 case 0:
742 puts (_("# Successfully updated."));
743 break;
744 case 1:
745 assert (question_flag);
746 puts (_("# Needs to be updated (-q is set)."));
747 break;
748 case 2:
749 puts (_("# Failed to be updated."));
750 break;
751 default:
752 puts (_("# Invalid value in `update_status' member!"));
753 fflush (stdout);
754 fflush (stderr);
755 abort ();
756 }
757 break;
758 default:
759 puts (_("# Invalid value in `command_state' member!"));
760 fflush (stdout);
761 fflush (stderr);
762 abort ();
763 }
764
765 if (f->variables != 0)
766 print_file_variables (f);
767
768 if (f->cmds != 0)
769 print_commands (f->cmds);
770
771 if (f->prev)
772 print_file ((const void *) f->prev);
773}
774
775void
776print_file_data_base (void)
777{
778 puts (_("\n# Files"));
779
780 hash_map (&files, print_file);
781
782 fputs (_("\n# files hash-table stats:\n# "), stdout);
783 hash_print_stats (&files, stdout);
784}
785
786#define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500)
787
788char *
789build_target_list (char *value)
790{
791 static unsigned long last_targ_count = 0;
792
793 if (files.ht_fill != last_targ_count)
794 {
795 unsigned long max = EXPANSION_INCREMENT (strlen (value));
796 unsigned long len;
797 char *p;
798 struct file **fp = (struct file **) files.ht_vec;
799 struct file **end = &fp[files.ht_size];
800
801 /* Make sure we have at least MAX bytes in the allocated buffer. */
802 value = xrealloc (value, max);
803
804 p = value;
805 len = 0;
806 for (; fp < end; ++fp)
807 if (!HASH_VACANT (*fp) && (*fp)->is_target)
808 {
809 struct file *f = *fp;
810 int l = strlen (f->name);
811
812 len += l + 1;
813 if (len > max)
814 {
815 unsigned long off = p - value;
816
817 max += EXPANSION_INCREMENT (l + 1);
818 value = xrealloc (value, max);
819 p = &value[off];
820 }
821
822 bcopy (f->name, p, l);
823 p += l;
824 *(p++) = ' ';
825 }
826 *(p-1) = '\0';
827
828 last_targ_count = files.ht_fill;
829 }
830
831 return value;
832}
833
834void
835init_hash_files (void)
836{
837 hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp);
838}
839
840/* EOF */
Note: See TracBrowser for help on using the repository browser.