📄 file.c
字号:
/* Target file hash table management for GNU Make.Copyright (C) 1988,89,90,91,92,93,94,95,96,97 Free Software Foundation, Inc.This file is part of GNU Make.GNU Make is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Make; see the file COPYING. If not, write tothe Free Software Foundation, Inc., 59 Temple Place - Suite 330,Boston, MA 02111-1307, USA. */#include <assert.h>#include "make.h"#include "dep.h"#include "filedef.h"#include "job.h"#include "commands.h"#include "variable.h"/* Hash table of files the makefile knows how to make. */#ifndef FILE_BUCKETS#define FILE_BUCKETS 1007#endifstatic 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;/* 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;#ifdef VMS register char *lname, *ln;#endif if (*name == '\0') abort (); /* 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 lname = (char *)malloc(strlen(name) + 1); for (n=name, ln=lname; *n != '\0'; ++n, ++ln) *ln = isupper(*n) ? tolower(*n) : *n; *ln = '\0'; name = lname; while (name[0] == '[' && name[1] == ']' && name[2] != '\0') name += 2;#endif while (name[0] == '.' && name[1] == '/' && name[2] != '\0') { 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 name = "./";#endif /* AMIGA */#endif /* VMS */ hashval = 0; for (n = name; *n != '\0'; ++n) HASHI (hashval, *n); hashval %= FILE_BUCKETS; for (f = files[hashval]; f != 0; f = f->next) { if (strieq (f->hname, name)) {#ifdef VMS free (lname);#endif return f; } }#ifdef VMS free (lname);#endif return 0;}struct file *enter_file (name) char *name;{ register struct file *f, *new; register char *n; register unsigned int hashval;#ifdef VMS char *lname, *ln;#endif if (*name == '\0') abort ();#ifdef VMS lname = (char *)malloc (strlen (name) + 1); for (n = name, ln = lname; *n != '\0'; ++n, ++ln) { if (isupper(*n)) *ln = tolower(*n); else *ln = *n; } *ln = 0; name = lname;#endif hashval = 0; for (n = name; *n != '\0'; ++n) HASHI (hashval, *n); hashval %= FILE_BUCKETS; for (f = files[hashval]; f != 0; f = f->next) if (strieq (f->hname, name)) break; if (f != 0 && !f->double_colon) {#ifdef VMS free(lname);#endif return f; } new = (struct file *) xmalloc (sizeof (struct file)); bzero ((char *) new, sizeof (struct file)); new->name = new->hname = name; 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; while (f->prev != 0) f = f->prev; f->prev = new; } return new;}/* Rehash FILE to NAME. This is not as simple as resetting the `hname' member, since it must be put in a new hash bucket, and possibly merged with an existing file called NAME. */voidrehash_file (file, name) register struct file *file; char *name;{ char *oldname = file->hname; register unsigned int oldhash; register char *n; while (file->renamed != 0) file = file->renamed; /* Find the hash values of the old and new names. */ oldhash = 0; for (n = oldname; *n != '\0'; ++n) HASHI (oldhash, *n); file_hash_enter (file, name, oldhash, file->name);}/* 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. */voidrename_file (file, name) register struct file *file; char *name;{ rehash_file(file, name); while (file) { file->name = file->hname; file = file->prev; }}voidfile_hash_enter (file, name, oldhash, oldname) register struct file *file; char *name; unsigned int oldhash; char *oldname;{ unsigned int oldbucket = oldhash % FILE_BUCKETS; register unsigned int newhash, newbucket; struct file *oldfile; register char *n; register struct file *f; newhash = 0; for (n = name; *n != '\0'; ++n) HASHI (newhash, *n); newbucket = newhash % FILE_BUCKETS; /* Look for an existing file under the new name. */ for (oldfile = files[newbucket]; oldfile != 0; oldfile = oldfile->next) if (strieq (oldfile->hname, name)) break; /* If the old file is the same as the new file, something's wrong. */ assert (oldfile != file); if (oldhash != 0 && (newbucket != oldbucket || oldfile != 0)) { /* Remove FILE from its hash bucket. */ struct file *lastf = 0; for (f = files[oldbucket]; f != file; f = f->next) lastf = f; if (lastf == 0) files[oldbucket] = f->next; else lastf->next = f->next; } /* Give FILE its new name. */ file->hname = name; for (f = file->double_colon; f != 0; f = f->prev) f->hname = name; if (oldfile == 0) { /* There is no existing file with the new name. */ if (newbucket != oldbucket) { /* Put FILE in its new hash bucket. */ file->next = files[newbucket]; files[newbucket] = file; } } 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. */ if (oldfile->cmds->fileinfo.filenm != 0) error (&file->cmds->fileinfo, _("Commands were specified for \file `%s' at %s:%lu,"), oldname, oldfile->cmds->fileinfo.filenm, oldfile->cmds->fileinfo.lineno); else error (&file->cmds->fileinfo, _("Commands for file `%s' were found by \implicit rule search,"), oldname); error (&file->cmds->fileinfo, _("but `%s' is now considered the same file \as `%s'."), oldname, name); error (&file->cmds->fileinfo, _("Commands for `%s' will be ignored \in favor of those for `%s'."), name, oldname); } } /* 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'"), 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; } 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;#define MERGE(field) oldfile->field |= file->field MERGE (precious); MERGE (tried_implicit); MERGE (updating); MERGE (updated); MERGE (is_target); MERGE (cmd_target); MERGE (phony); MERGE (ignore_vpath);#undef MERGE file->renamed = oldfile; }}/* Remove all nonprecious intermediate files.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -