VirtualBox

source: kBuild/trunk/src/gmake/file.c@ 225

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

2nd try on .NOTPARALLEL.

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