make-dfsg/file.c

749 lines
18 KiB
C
Raw Normal View History

1994-03-23 14:12:55 +00:00
/* Target file hash table management for GNU Make.
1997-08-27 20:30:54 +00:00
Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.
1992-01-11 11:37:36 +00:00
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Make is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
1992-01-11 11:37:36 +00:00
1998-10-03 05:39:55 +00:00
#include <assert.h>
1992-01-11 11:37:36 +00:00
#include "make.h"
#include "dep.h"
#include "filedef.h"
#include "job.h"
#include "commands.h"
1992-01-11 11:37:36 +00:00
#include "variable.h"
/* Hash table of files the makefile knows how to make. */
#ifndef FILE_BUCKETS
#define FILE_BUCKETS 1007
#endif
static struct file *files[FILE_BUCKETS];
/* Number of files with the `intermediate' flag set. */
unsigned int num_intermediates = 0;
/* Current value for pruning the scan of the goal chain (toggle 0/1). */
unsigned int considered = 0;
1992-01-11 11:37:36 +00:00
/* Access the hash table of all file records.
lookup_file given a name, return the struct file * for that name,
or nil if there is none.
enter_file similar, but create one if there is none. */
struct file *
lookup_file (name)
char *name;
{
register struct file *f;
register char *n;
register unsigned int hashval;
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
1998-07-30 20:54:47 +00:00
register char *lname, *ln;
#endif
1992-01-11 11:37:36 +00:00
assert (*name != '\0');
1992-01-11 11:37:36 +00:00
1992-10-12 18:04:07 +00:00
/* This is also done in parse_file_seq, so this is redundant
for names read from makefiles. It is here for names passed
on the command line. */
#ifdef VMS
2000-01-22 05:43:03 +00:00
# ifndef WANT_CASE_SENSITIVE_TARGETS
1998-07-30 20:54:47 +00:00
lname = (char *)malloc(strlen(name) + 1);
for (n=name, ln=lname; *n != '\0'; ++n, ++ln)
*ln = isupper((unsigned char)*n) ? tolower((unsigned char)*n) : *n;
1998-07-30 20:54:47 +00:00
*ln = '\0';
name = lname;
2000-01-22 05:43:03 +00:00
# endif
1998-07-30 20:54:47 +00:00
while (name[0] == '[' && name[1] == ']' && name[2] != '\0')
name += 2;
#endif
1992-01-11 11:37:36 +00:00
while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
1992-10-12 18:04:07 +00:00
{
name += 2;
while (*name == '/')
/* Skip following slashes: ".//foo" is "foo", not "/foo". */
++name;
}
if (*name == '\0')
/* It was all slashes after a dot. */
#ifdef VMS
name = "[]";
#else
#ifdef _AMIGA
name = "";
#else
1992-10-12 18:04:07 +00:00
name = "./";
#endif /* AMIGA */
#endif /* VMS */
1992-01-11 11:37:36 +00:00
hashval = 0;
for (n = name; *n != '\0'; ++n)
HASHI (hashval, *n);
1992-01-11 11:37:36 +00:00
hashval %= FILE_BUCKETS;
for (f = files[hashval]; f != 0; f = f->next)
{
1997-04-07 07:21:16 +00:00
if (strieq (f->hname, name))
{
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
1998-07-30 20:54:47 +00:00
free (lname);
#endif
return f;
}
}
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
1998-07-30 20:54:47 +00:00
free (lname);
#endif
1992-01-11 11:37:36 +00:00
return 0;
}
struct file *
enter_file (name)
char *name;
{
register struct file *f, *new;
register char *n;
register unsigned int hashval;
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
char *lname, *ln;
#endif
1992-01-11 11:37:36 +00:00
assert (*name != '\0');
1992-01-11 11:37:36 +00:00
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
lname = (char *)malloc (strlen (name) + 1);
for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
{
if (isupper((unsigned char)*n))
*ln = tolower((unsigned char)*n);
else
*ln = *n;
}
*ln = 0;
2000-01-22 05:43:03 +00:00
/* Creates a possible leak, old value of name is unreachable, but I
currently don't know how to fix it. */
name = lname;
#endif
1992-01-11 11:37:36 +00:00
hashval = 0;
for (n = name; *n != '\0'; ++n)
HASHI (hashval, *n);
1992-01-11 11:37:36 +00:00
hashval %= FILE_BUCKETS;
for (f = files[hashval]; f != 0; f = f->next)
1997-04-07 07:21:16 +00:00
if (strieq (f->hname, name))
1992-01-11 11:37:36 +00:00
break;
if (f != 0 && !f->double_colon)
{
2000-01-22 05:43:03 +00:00
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
free(lname);
#endif
return f;
}
1992-01-11 11:37:36 +00:00
new = (struct file *) xmalloc (sizeof (struct file));
bzero ((char *) new, sizeof (struct file));
1997-04-07 07:21:16 +00:00
new->name = new->hname = name;
1992-01-11 11:37:36 +00:00
new->update_status = -1;
if (f == 0)
{
/* This is a completely new file. */
new->next = files[hashval];
files[hashval] = new;
}
else
{
/* There is already a double-colon entry for this file. */
new->double_colon = f;
1992-01-11 11:37:36 +00:00
while (f->prev != 0)
f = f->prev;
f->prev = new;
}
return new;
}
1997-04-07 07:21:16 +00:00
/* Rehash FILE to NAME. This is not as simple as resetting
the `hname' member, since it must be put in a new hash bucket,
1992-01-11 11:37:36 +00:00
and possibly merged with an existing file called NAME. */
void
1997-04-07 07:21:16 +00:00
rehash_file (file, name)
1992-01-11 11:37:36 +00:00
register struct file *file;
char *name;
{
1997-04-07 07:21:16 +00:00
char *oldname = file->hname;
1992-08-02 10:16:54 +00:00
register unsigned int oldhash;
1992-01-11 11:37:36 +00:00
register char *n;
1992-04-01 09:58:26 +00:00
while (file->renamed != 0)
file = file->renamed;
1992-01-11 11:37:36 +00:00
/* Find the hash values of the old and new names. */
oldhash = 0;
for (n = oldname; *n != '\0'; ++n)
HASHI (oldhash, *n);
1992-01-11 11:37:36 +00:00
1992-08-27 22:06:44 +00:00
file_hash_enter (file, name, oldhash, file->name);
1992-08-02 10:16:54 +00:00
}
1997-08-18 18:11:04 +00:00
/* Rename FILE to NAME. This is not as simple as resetting
the `name' member, since it must be put in a new hash bucket,
and possibly merged with an existing file called NAME. */
void
rename_file (file, name)
register struct file *file;
char *name;
{
rehash_file(file, name);
while (file)
{
file->name = file->hname;
file = file->prev;
}
}
1992-08-02 10:16:54 +00:00
void
1992-08-02 11:28:04 +00:00
file_hash_enter (file, name, oldhash, oldname)
1992-08-02 10:16:54 +00:00
register struct file *file;
char *name;
unsigned int oldhash;
1992-08-02 11:28:04 +00:00
char *oldname;
1992-08-02 10:16:54 +00:00
{
1993-03-10 20:24:57 +00:00
unsigned int oldbucket = oldhash % FILE_BUCKETS;
register unsigned int newhash, newbucket;
1992-08-02 10:16:54 +00:00
struct file *oldfile;
register char *n;
register struct file *f;
1992-01-11 11:37:36 +00:00
newhash = 0;
for (n = name; *n != '\0'; ++n)
HASHI (newhash, *n);
1993-03-10 20:24:57 +00:00
newbucket = newhash % FILE_BUCKETS;
1992-01-11 11:37:36 +00:00
/* Look for an existing file under the new name. */
1993-03-10 20:24:57 +00:00
for (oldfile = files[newbucket]; oldfile != 0; oldfile = oldfile->next)
1997-04-07 07:21:16 +00:00
if (strieq (oldfile->hname, name))
1992-01-11 11:37:36 +00:00
break;
/* If the old file is the same as the new file, never mind. */
if (oldfile == file)
return;
1997-04-07 07:21:16 +00:00
1993-03-10 20:24:57 +00:00
if (oldhash != 0 && (newbucket != oldbucket || oldfile != 0))
1992-01-11 11:37:36 +00:00
{
/* Remove FILE from its hash bucket. */
struct file *lastf = 0;
1993-03-10 20:24:57 +00:00
for (f = files[oldbucket]; f != file; f = f->next)
1992-01-11 11:37:36 +00:00
lastf = f;
if (lastf == 0)
1993-03-10 20:24:57 +00:00
files[oldbucket] = f->next;
1992-01-11 11:37:36 +00:00
else
lastf->next = f->next;
}
/* Give FILE its new name. */
1997-04-07 07:21:16 +00:00
file->hname = name;
for (f = file->double_colon; f != 0; f = f->prev)
1997-04-07 07:21:16 +00:00
f->hname = name;
1992-01-11 11:37:36 +00:00
if (oldfile == 0)
{
/* There is no existing file with the new name. */
1993-03-10 20:24:57 +00:00
if (newbucket != oldbucket)
1992-01-11 11:37:36 +00:00
{
/* Put FILE in its new hash bucket. */
1993-03-10 20:24:57 +00:00
file->next = files[newbucket];
files[newbucket] = file;
1992-01-11 11:37:36 +00:00
}
}
else
{
/* There is an existing file with the new name.
We must merge FILE into the existing file. */
register struct dep *d;
if (file->cmds != 0)
{
if (oldfile->cmds == 0)
oldfile->cmds = file->cmds;
else if (file->cmds != oldfile->cmds)
{
/* We have two sets of commands. We will go with the
one given in the rule explicitly mentioning this name,
but give a message to let the user know what's going on. */
1998-10-03 05:39:55 +00:00
if (oldfile->cmds->fileinfo.filenm != 0)
error (&file->cmds->fileinfo,
_("Commands were specified for \
file `%s' at %s:%lu,"),
1998-10-03 05:39:55 +00:00
oldname, oldfile->cmds->fileinfo.filenm,
oldfile->cmds->fileinfo.lineno);
1992-11-04 01:44:30 +00:00
else
1998-10-03 05:39:55 +00:00
error (&file->cmds->fileinfo,
_("Commands for file `%s' were found by \
implicit rule search,"),
1992-11-04 01:44:30 +00:00
oldname);
1998-10-03 05:39:55 +00:00
error (&file->cmds->fileinfo,
_("but `%s' is now considered the same file \
as `%s'."),
1992-08-02 11:28:04 +00:00
oldname, name);
1998-10-03 05:39:55 +00:00
error (&file->cmds->fileinfo,
_("Commands for `%s' will be ignored \
in favor of those for `%s'."),
1992-08-02 11:28:04 +00:00
name, oldname);
1992-01-11 11:37:36 +00:00
}
}
/* Merge the dependencies of the two files. */
d = oldfile->deps;
if (d == 0)
oldfile->deps = file->deps;
else
{
while (d->next != 0)
d = d->next;
d->next = file->deps;
}
merge_variable_set_lists (&oldfile->variables, file->variables);
if (oldfile->double_colon && file->is_target && !file->double_colon)
fatal (NILF, _("can't rename single-colon `%s' to double-colon `%s'"),
1992-01-11 11:37:36 +00:00
oldname, name);
if (!oldfile->double_colon && file->double_colon)
{
if (oldfile->is_target)
fatal (NILF, _("can't rename double-colon `%s' to single-colon `%s'"),
oldname, name);
else
oldfile->double_colon = file->double_colon;
}
1992-01-11 11:37:36 +00:00
if (file->last_mtime > oldfile->last_mtime)
/* %%% Kludge so -W wins on a file that gets vpathized. */
oldfile->last_mtime = file->last_mtime;
oldfile->mtime_before_update = file->mtime_before_update;
1992-01-11 11:37:36 +00:00
#define MERGE(field) oldfile->field |= file->field
MERGE (precious);
MERGE (tried_implicit);
MERGE (updating);
MERGE (updated);
MERGE (is_target);
MERGE (cmd_target);
MERGE (phony);
1997-04-07 07:21:16 +00:00
MERGE (ignore_vpath);
1992-01-11 11:37:36 +00:00
#undef MERGE
file->renamed = oldfile;
}
}
/* Remove all nonprecious intermediate files.
If SIG is nonzero, this was caused by a fatal signal,
meaning that a different message will be printed, and
the message will go to stderr rather than stdout. */
void
remove_intermediates (sig)
int sig;
{
register int i;
register struct file *f;
char doneany;
if (question_flag || touch_flag)
return;
if (sig && just_print_flag)
1992-01-11 11:37:36 +00:00
return;
doneany = 0;
for (i = 0; i < FILE_BUCKETS; ++i)
for (f = files[i]; f != 0; f = f->next)
if (f->intermediate && (f->dontcare || !f->precious)
&& !f->secondary && !f->cmd_target)
1992-01-11 11:37:36 +00:00
{
int status;
if (f->update_status == -1)
/* If nothing would have created this file yet,
don't print an "rm" command for it. */
1998-07-30 20:54:47 +00:00
continue;
else if (just_print_flag)
status = 0;
1992-01-11 11:37:36 +00:00
else
{
status = unlink (f->name);
if (status < 0 && errno == ENOENT)
continue;
}
if (!f->dontcare)
{
if (sig)
error (NILF, _("*** Deleting intermediate file `%s'"), f->name);
1992-06-23 22:42:43 +00:00
else if (!silent_flag)
1992-01-11 11:37:36 +00:00
{
1993-05-22 20:24:37 +00:00
if (! doneany)
1992-01-11 11:37:36 +00:00
{
fputs ("rm ", stdout);
doneany = 1;
}
1993-05-22 20:24:37 +00:00
else
putchar (' ');
1992-01-11 11:37:36 +00:00
fputs (f->name, stdout);
fflush (stdout);
}
if (status < 0)
perror_with_name ("unlink: ", f->name);
}
}
if (doneany && !sig)
{
putchar ('\n');
fflush (stdout);
}
}
/* For each dependency of each file, make the `struct dep' point
at the appropriate `struct file' (which may have to be created).
Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
and various other special targets. */
1992-01-11 11:37:36 +00:00
void
snap_deps ()
{
register struct file *f, *f2;
register struct dep *d;
register int i;
/* Enter each dependency name as a file. */
for (i = 0; i < FILE_BUCKETS; ++i)
for (f = files[i]; f != 0; f = f->next)
for (f2 = f; f2 != 0; f2 = f2->prev)
for (d = f2->deps; d != 0; d = d->next)
if (d->name != 0)
{
d->file = lookup_file (d->name);
if (d->file == 0)
d->file = enter_file (d->name);
else
free (d->name);
d->name = 0;
}
1992-01-11 11:37:36 +00:00
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->precious = 1;
for (f = lookup_file (".PHONY"); f != 0; f = f->prev)
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
{
/* Mark this file as phony and nonexistent. */
f2->phony = 1;
1998-10-03 05:39:55 +00:00
f2->last_mtime = (FILE_TIMESTAMP) -1;
f2->mtime_before_update = (FILE_TIMESTAMP) -1;
1992-01-11 11:37:36 +00:00
}
1992-06-04 03:52:53 +00:00
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
{
/* .INTERMEDIATE with deps listed
marks those deps as intermediate files. */
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->intermediate = 1;
/* .INTERMEDIATE with no deps does nothing.
Marking all files as intermediates is useless
since the goal targets would be deleted after they are built. */
}
for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev)
{
/* .SECONDARY with deps listed
marks those deps as intermediate files
in that they don't get rebuilt if not actually needed;
but unlike real intermediate files,
these are not deleted after make finishes. */
if (f->deps)
{
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->intermediate = f2->secondary = 1;
}
/* .SECONDARY with no deps listed marks *all* files that way. */
else
{
int i;
for (i = 0; i < FILE_BUCKETS; i++)
for (f2 = files[i]; f2; f2= f2->next)
f2->intermediate = f2->secondary = 1;
}
}
1992-06-04 03:52:53 +00:00
f = lookup_file (".EXPORT_ALL_VARIABLES");
1994-10-24 23:44:16 +00:00
if (f != 0 && f->is_target)
export_all_variables = 1;
f = lookup_file (".IGNORE");
1994-10-24 23:44:16 +00:00
if (f != 0 && f->is_target)
{
if (f->deps == 0)
ignore_errors_flag = 1;
else
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->command_flags |= COMMANDS_NOERROR;
1994-10-24 23:44:16 +00:00
}
f = lookup_file (".SILENT");
1994-10-24 23:44:16 +00:00
if (f != 0 && f->is_target)
{
if (f->deps == 0)
silent_flag = 1;
else
for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev)
f2->command_flags |= COMMANDS_SILENT;
1994-10-24 23:44:16 +00:00
}
f = lookup_file (".POSIX");
1994-10-24 23:44:16 +00:00
if (f != 0 && f->is_target)
posix_pedantic = 1;
f = lookup_file (".NOTPARALLEL");
if (f != 0 && f->is_target)
not_parallel = 1;
1992-01-11 11:37:36 +00:00
}
1994-09-07 00:02:25 +00:00
/* Set the `command_state' member of FILE and all its `also_make's. */
void
set_command_state (file, state)
struct file *file;
int state;
{
1994-09-07 00:17:57 +00:00
struct dep *d;
1994-09-07 00:02:25 +00:00
file->command_state = state;
1994-09-07 00:02:25 +00:00
for (d = file->also_make; d != 0; d = d->next)
1994-09-07 00:24:10 +00:00
d->file->command_state = state;
1994-09-07 00:02:25 +00:00
}
1998-10-03 05:39:55 +00:00
/* Get and print file timestamps. */
FILE_TIMESTAMP
file_timestamp_now ()
{
#if HAVE_CLOCK_GETTIME && defined CLOCK_REALTIME
struct timespec timespec;
if (clock_gettime (CLOCK_REALTIME, &timespec) == 0)
return FILE_TIMESTAMP_FROM_S_AND_NS (timespec.tv_sec, timespec.tv_nsec);
#endif
return FILE_TIMESTAMP_FROM_S_AND_NS (time ((time_t *) 0), 0);
}
void
file_timestamp_sprintf (p, ts)
char *p;
FILE_TIMESTAMP ts;
{
time_t t = FILE_TIMESTAMP_S (ts);
struct tm *tm = localtime (&t);
if (tm)
sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
else if (t < 0)
sprintf (p, "%ld", (long) t);
else
sprintf (p, "%lu", (unsigned long) t);
p += strlen (p);
/* Append nanoseconds as a fraction, but remove trailing zeros.
We don't know the actual timestamp resolution, since clock_getres
applies only to local times, whereas this timestamp might come
from a remote filesystem. So removing trailing zeros is the
best guess that we can do. */
sprintf (p, ".%09ld", (long) FILE_TIMESTAMP_NS (ts));
p += strlen (p) - 1;
while (*p == '0')
p--;
p += *p != '.';
*p = '\0';
}
1992-01-11 11:37:36 +00:00
/* Print the data base of files. */
1993-10-18 11:01:37 +00:00
static void
print_file (f)
struct file *f;
{
register struct dep *d;
1997-08-27 20:30:54 +00:00
1993-10-18 11:01:37 +00:00
putchar ('\n');
if (!f->is_target)
puts (_("# Not a target:"));
1993-10-18 11:01:37 +00:00
printf ("%s:%s", f->name, f->double_colon ? ":" : "");
1993-10-18 11:01:37 +00:00
for (d = f->deps; d != 0; d = d->next)
printf (" %s", dep_name (d));
putchar ('\n');
1993-10-18 11:01:37 +00:00
if (f->precious)
1999-08-24 04:49:39 +00:00
puts (_("# Precious file (prerequisite of .PRECIOUS)."));
1993-10-18 11:01:37 +00:00
if (f->phony)
1999-08-24 04:49:39 +00:00
puts (_("# Phony target (prerequisite of .PHONY)."));
1993-10-18 11:01:37 +00:00
if (f->cmd_target)
puts (_("# Command-line target."));
1993-10-18 11:01:37 +00:00
if (f->dontcare)
puts (_("# A default or MAKEFILES makefile."));
puts (f->tried_implicit
? _("# Implicit rule search has been done.")
: _("# Implicit rule search has not been done."));
1993-10-18 11:01:37 +00:00
if (f->stem != 0)
printf (_("# Implicit/static pattern stem: `%s'\n"), f->stem);
1993-10-18 11:01:37 +00:00
if (f->intermediate)
1999-08-24 04:49:39 +00:00
puts (_("# File is an intermediate prerequisite."));
1993-10-18 11:01:37 +00:00
if (f->also_make != 0)
{
fputs (_("# Also makes:"), stdout);
1993-10-18 11:01:37 +00:00
for (d = f->also_make; d != 0; d = d->next)
printf (" %s", dep_name (d));
putchar ('\n');
}
1998-10-03 05:39:55 +00:00
if (f->last_mtime == 0)
puts (_("# Modification time never checked."));
1998-10-03 05:39:55 +00:00
else if (f->last_mtime == (FILE_TIMESTAMP) -1)
puts (_("# File does not exist."));
1993-10-18 11:01:37 +00:00
else
1998-10-03 05:39:55 +00:00
{
char buf[FILE_TIMESTAMP_PRINT_LEN_BOUND + 1];
file_timestamp_sprintf (buf, f->last_mtime);
printf (_("# Last modified %s\n"), buf);
1998-10-03 05:39:55 +00:00
}
puts (f->updated
? _("# File has been updated.") : _("# File has not been updated."));
1993-10-18 11:01:37 +00:00
switch (f->command_state)
{
case cs_running:
puts (_("# Commands currently running (THIS IS A BUG)."));
1993-10-18 11:01:37 +00:00
break;
case cs_deps_running:
puts (_("# Dependencies commands running (THIS IS A BUG)."));
1993-10-18 11:01:37 +00:00
break;
case cs_not_started:
case cs_finished:
switch (f->update_status)
{
case -1:
break;
case 0:
puts (_("# Successfully updated."));
1993-10-18 11:01:37 +00:00
break;
case 1:
assert (question_flag);
puts (_("# Needs to be updated (-q is set)."));
break;
case 2:
puts (_("# Failed to be updated."));
1993-10-18 11:01:37 +00:00
break;
default:
puts (_("# Invalid value in `update_status' member!"));
1993-10-18 11:01:37 +00:00
fflush (stdout);
fflush (stderr);
abort ();
}
break;
default:
puts (_("# Invalid value in `command_state' member!"));
1993-10-18 11:01:37 +00:00
fflush (stdout);
fflush (stderr);
abort ();
}
if (f->variables != 0)
print_file_variables (f);
if (f->cmds != 0)
print_commands (f->cmds);
}
1992-01-11 11:37:36 +00:00
void
print_file_data_base ()
{
register unsigned int i, nfiles, per_bucket;
register struct file *file;
puts (_("\n# Files"));
1992-01-11 11:37:36 +00:00
per_bucket = nfiles = 0;
for (i = 0; i < FILE_BUCKETS; ++i)
{
register unsigned int this_bucket = 0;
for (file = files[i]; file != 0; file = file->next)
{
register struct file *f;
++this_bucket;
for (f = file; f != 0; f = f->prev)
1993-10-18 11:01:37 +00:00
print_file (f);
1992-01-11 11:37:36 +00:00
}
nfiles += this_bucket;
if (this_bucket > per_bucket)
per_bucket = this_bucket;
}
if (nfiles == 0)
puts (_("\n# No files."));
1992-01-11 11:37:36 +00:00
else
{
printf (_("\n# %u files in %u hash buckets.\n"), nfiles, FILE_BUCKETS);
1992-01-11 11:37:36 +00:00
#ifndef NO_FLOAT
printf (_("# average %.3f files per bucket, max %u files in one bucket.\n"),
1998-07-30 20:54:47 +00:00
((double) nfiles) / ((double) FILE_BUCKETS), per_bucket);
1992-01-11 11:37:36 +00:00
#endif
}
}
/* EOF */