This is a major update, which switches virtually every allocated-but-not-freed

string into the strcache.  As a side-effect, many more structure members and
function arguments can/should be declared const.

As mentioned in the changelog, unfortunately measurement shows that this
change does not yet reduce memory.  The problem is with secondary expansion:
because of this we store all the prerequisites in the string cache twice.
First we store the prerequisite string after initial expansion but before
secondary expansion, then we store each individual file after secondary
expansion and expand_deps().  I plan to change expand_deps() to be callable
in either context (eval or snap_deps) then have non-second-expansion
targets call expand_deps() during eval, so that we only need to store that
dependency list once.
This commit is contained in:
Paul Smith 2007-03-20 03:02:26 +00:00
parent e4da308580
commit 6ccf33cdbd
27 changed files with 1271 additions and 1250 deletions

View File

@ -1,10 +1,31 @@
2007-03-19 Paul Smith <psmith@gnu.org>
* ALL: Use the strcache for all file name strings, or other
strings which we will never free. The goal is to save memory by
avoiding duplicate copies of strings. However, at the moment this
doesn't save much memory in most situations: due to secondary
expansion we actually save prerequisite lists twice (once before
the secondary expansion, and then again after it's been parsed
into individual file names in the dep list). We will resolve this
in a future change, by doing the parsing up-front for targets
where secondary expansion is not set.
Moving things into the strcache also allows us to use const
pointers in many more places.
2007-01-03 Paul Smith <psmith@gnu.org>
* make.h (ENULLLOOP): Reset errno after each failed invocation of
the function, not just the first. Fixes Savannah bug #18680.
2006-11-18 Paul Smith <psmith@gnu.org> 2006-11-18 Paul Smith <psmith@gnu.org>
* strcache.c (strcache_add_len): Don't allocate a new buffer * strcache.c (strcache_add_len): Don't allocate a new buffer
unless the string is not already nil-terminated. Technically this unless the string is not already nil-terminated. Technically this
is a violation of the standard, since we may be passed an array is a violation of the standard, since we may be passed an array
that is not long enough to test one past. However, in make this that is not long enough to test one past. However, in make this
is never true since we only use nil-terminated strings. is never true since we only use nil-terminated strings or
sub-strings thereof.
* read.c (eval, do_define): Use cmd_prefix instead of '\t'. * read.c (eval, do_define): Use cmd_prefix instead of '\t'.
@ -24,6 +45,7 @@
* vmsify.c: Constification. Hard to test this but I hope I didn't * vmsify.c: Constification. Hard to test this but I hope I didn't
screw it up! screw it up!
* vpath.c: Partial constification. * vpath.c: Partial constification.
* w32/pathstuff.c: Partial constification.
2006-11-16 Eli Zaretskii <eliz@gnu.org> 2006-11-16 Eli Zaretskii <eliz@gnu.org>

63
ar.c
View File

@ -50,19 +50,19 @@ ar_name (const char *name)
/* Parse the archive-member reference NAME into the archive and member names. /* Parse the archive-member reference NAME into the archive and member names.
Put the malloc'd archive name in *ARNAME_P if ARNAME_P is non-nil; Creates one allocated string containing both names, pointed to by ARNAME_P.
put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */ MEMNAME_P points to the member. */
void void
ar_parse_name (const char *name, char **arname_p, char **memname_p) ar_parse_name (const char *name, char **arname_p, char **memname_p)
{ {
const char *p = strchr (name, '('), *end = name + strlen (name) - 1; char *p;
if (arname_p != 0) *arname_p = xstrdup (name);
*arname_p = savestring (name, p - name); p = strchr (*arname_p, '(');
*(p++) = '\0';
if (memname_p != 0) p[strlen(p) - 1] = '\0';
*memname_p = savestring (p + 1, end - (p + 1)); *memname_p = p;
} }
@ -86,7 +86,6 @@ ar_member_date (const char *name)
{ {
char *arname; char *arname;
char *memname; char *memname;
int arname_used = 0;
long int val; long int val;
ar_parse_name (name, &arname, &memname); ar_parse_name (name, &arname, &memname);
@ -102,10 +101,7 @@ ar_member_date (const char *name)
struct file *arfile; struct file *arfile;
arfile = lookup_file (arname); arfile = lookup_file (arname);
if (arfile == 0 && file_exists_p (arname)) if (arfile == 0 && file_exists_p (arname))
{ arfile = enter_file (strcache_add (arname));
arfile = enter_file (arname);
arname_used = 1;
}
if (arfile != 0) if (arfile != 0)
(void) f_mtime (arfile, 0); (void) f_mtime (arfile, 0);
@ -113,9 +109,7 @@ ar_member_date (const char *name)
val = ar_scan (arname, ar_member_date_1, memname); val = ar_scan (arname, ar_member_date_1, memname);
if (!arname_used) free (arname);
free (arname);
free (memname);
return (val <= 0 ? (time_t) -1 : (time_t) val); return (val <= 0 ? (time_t) -1 : (time_t) val);
} }
@ -134,23 +128,16 @@ int
ar_touch (const char *name) ar_touch (const char *name)
{ {
char *arname, *memname; char *arname, *memname;
int arname_used = 0; int val;
register int val;
ar_parse_name (name, &arname, &memname); ar_parse_name (name, &arname, &memname);
/* Make sure we know the modtime of the archive itself before we /* Make sure we know the modtime of the archive itself before we
touch the member, since this will change the archive itself. */ touch the member, since this will change the archive modtime. */
{ {
struct file *arfile; struct file *arfile;
arfile = lookup_file (arname); arfile = enter_file (strcache_add (arname));
if (arfile == 0) f_mtime (arfile, 0);
{
arfile = enter_file (arname);
arname_used = 1;
}
(void) f_mtime (arfile, 0);
} }
val = 1; val = 1;
@ -177,9 +164,7 @@ ar_touch (const char *name)
_("touch: Bad return code from ar_member_touch on `%s'"), name); _("touch: Bad return code from ar_member_touch on `%s'"), name);
} }
if (!arname_used) free (arname);
free (arname);
free (memname);
return val; return val;
} }
@ -189,7 +174,7 @@ ar_touch (const char *name)
struct ar_glob_state struct ar_glob_state
{ {
char *arname; const char *arname;
const char *pattern; const char *pattern;
unsigned int size; unsigned int size;
struct nameseq *chain; struct nameseq *chain;
@ -211,7 +196,7 @@ ar_glob_match (int desc UNUSED, const char *mem, int truncated UNUSED,
{ {
/* We have a match. Add it to the chain. */ /* We have a match. Add it to the chain. */
struct nameseq *new = xmalloc (state->size); struct nameseq *new = xmalloc (state->size);
new->name = concat (state->arname, mem, ")"); new->name = strcache_add (concat (state->arname, mem, ")"));
new->next = state->chain; new->next = state->chain;
state->chain = new; state->chain = new;
++state->n; ++state->n;
@ -260,8 +245,9 @@ struct nameseq *
ar_glob (const char *arname, const char *member_pattern, unsigned int size) ar_glob (const char *arname, const char *member_pattern, unsigned int size)
{ {
struct ar_glob_state state; struct ar_glob_state state;
char **names;
struct nameseq *n; struct nameseq *n;
const char **names;
char *name;
unsigned int i; unsigned int i;
if (! glob_pattern_p (member_pattern, 1)) if (! glob_pattern_p (member_pattern, 1))
@ -270,10 +256,11 @@ ar_glob (const char *arname, const char *member_pattern, unsigned int size)
/* Scan the archive for matches. /* Scan the archive for matches.
ar_glob_match will accumulate them in STATE.chain. */ ar_glob_match will accumulate them in STATE.chain. */
i = strlen (arname); i = strlen (arname);
state.arname = alloca (i + 2); name = alloca (i + 2);
memcpy (state.arname, arname, i); memcpy (name, arname, i);
state.arname[i] = '('; name[i] = '(';
state.arname[i + 1] = '\0'; name[i + 1] = '\0';
state.arname = name;
state.pattern = member_pattern; state.pattern = member_pattern;
state.size = size; state.size = size;
state.chain = 0; state.chain = 0;
@ -284,7 +271,7 @@ ar_glob (const char *arname, const char *member_pattern, unsigned int size)
return 0; return 0;
/* Now put the names into a vector for sorting. */ /* Now put the names into a vector for sorting. */
names = alloca (state.n * sizeof (char *)); names = alloca (state.n * sizeof (const char *));
i = 0; i = 0;
for (n = state.chain; n != 0; n = n->next) for (n = state.chain; n != 0; n = n->next)
names[i++] = n->name; names[i++] = n->name;

View File

@ -97,12 +97,12 @@ set_file_variables (struct file *file)
len = strlen (name); len = strlen (name);
} }
for (d = enter_file (".SUFFIXES")->deps; d != 0; d = d->next) for (d = enter_file (strcache_add (".SUFFIXES"))->deps; d ; d = d->next)
{ {
unsigned int slen = strlen (dep_name (d)); unsigned int slen = strlen (dep_name (d));
if (len > slen && strneq (dep_name (d), name + (len - slen), slen)) if (len > slen && strneq (dep_name (d), name + (len - slen), slen))
{ {
file->stem = savestring (name, len - slen); file->stem = strcache_add_len (name, len - slen);
break; break;
} }
} }

View File

@ -522,23 +522,23 @@ static const char *default_variables[] =
void void
set_default_suffixes (void) set_default_suffixes (void)
{ {
suffix_file = enter_file (".SUFFIXES"); suffix_file = enter_file (strcache_add (".SUFFIXES"));
if (no_builtin_rules_flag) if (no_builtin_rules_flag)
(void) define_variable ("SUFFIXES", 8, "", o_default, 0); define_variable ("SUFFIXES", 8, "", o_default, 0);
else else
{ {
char *p = default_suffixes; char *p = default_suffixes;
suffix_file->deps = (struct dep *) suffix_file->deps = (struct dep *)
multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1),
sizeof (struct dep)); sizeof (struct dep));
(void) define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0); define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0);
} }
} }
/* Enter the default suffix rules as file rules. This used to be done in /* Enter the default suffix rules as file rules. This used to be done in
install_default_implicit_rules, but that loses because we want the install_default_implicit_rules, but that loses because we want the
suffix rules installed before reading makefiles, and thee pattern rules suffix rules installed before reading makefiles, and the pattern rules
installed after. */ installed after. */
void void
@ -551,7 +551,7 @@ install_default_suffix_rules (void)
for (s = default_suffix_rules; *s != 0; s += 2) for (s = default_suffix_rules; *s != 0; s += 2)
{ {
struct file *f = enter_file (s[0]); struct file *f = enter_file (strcache_add (s[0]));
/* Don't clobber cmds given in a makefile if there were any. */ /* Don't clobber cmds given in a makefile if there were any. */
if (f->cmds == 0) if (f->cmds == 0)
{ {

15
dep.h
View File

@ -36,8 +36,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
struct dep struct dep
{ {
struct dep *next; struct dep *next;
char *name; const char *name;
char *stem; const char *stem;
struct file *file; struct file *file;
unsigned int changed : 8; unsigned int changed : 8;
unsigned int ignore_mtime : 1; unsigned int ignore_mtime : 1;
@ -51,7 +51,7 @@ struct dep
struct nameseq struct nameseq
{ {
struct nameseq *next; struct nameseq *next;
char *name; const char *name;
}; };
@ -61,25 +61,20 @@ struct nameseq *parse_file_seq ();
#else #else
struct nameseq *parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip); struct nameseq *parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip);
#endif #endif
char *tilde_expand (char *name); char *tilde_expand (const char *name);
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size); struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size);
#endif #endif
#ifndef iAPX286
#define dep_name(d) ((d)->name == 0 ? (d)->file->name : (d)->name) #define dep_name(d) ((d)->name == 0 ? (d)->file->name : (d)->name)
#else
/* Buggy compiler can't hack this. */
char *dep_name ();
#endif
struct dep *alloc_dep (void); struct dep *alloc_dep (void);
void free_dep (struct dep *d); void free_dep (struct dep *d);
struct dep *copy_dep_chain (const struct dep *d); struct dep *copy_dep_chain (const struct dep *d);
void free_dep_chain (struct dep *d); void free_dep_chain (struct dep *d);
void free_ns_chain (struct nameseq *n); void free_ns_chain (struct nameseq *n);
struct dep *read_all_makefiles (char **makefiles); struct dep *read_all_makefiles (const char **makefiles);
int eval_buffer (char *buffer); int eval_buffer (char *buffer);
int update_goal_chain (struct dep *goals); int update_goal_chain (struct dep *goals);
void uniquize_deps (struct dep *); void uniquize_deps (struct dep *);

24
dir.c
View File

@ -1124,29 +1124,28 @@ open_dirstream (const char *directory)
static struct dirent * static struct dirent *
read_dirstream (__ptr_t stream) read_dirstream (__ptr_t stream)
{ {
struct dirstream *const ds = (struct dirstream *) stream;
struct directory_contents *dc = ds->contents;
struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
static char *buf; static char *buf;
static unsigned int bufsz; static unsigned int bufsz;
struct dirstream *const ds = (struct dirstream *) stream;
struct directory_contents *dc = ds->contents;
struct dirfile **dirfile_end = (struct dirfile **) dc->dirfiles.ht_vec + dc->dirfiles.ht_size;
while (ds->dirfile_slot < dirfile_end) while (ds->dirfile_slot < dirfile_end)
{ {
register struct dirfile *df = *ds->dirfile_slot++; struct dirfile *df = *ds->dirfile_slot++;
if (! HASH_VACANT (df) && !df->impossible) if (! HASH_VACANT (df) && !df->impossible)
{ {
/* The glob interface wants a `struct dirent', /* The glob interface wants a `struct dirent', so mock one up. */
so mock one up. */
struct dirent *d; struct dirent *d;
unsigned int len = df->length + 1; unsigned int len = df->length + 1;
if (sizeof *d - sizeof d->d_name + len > bufsz) unsigned int sz = sizeof (*d) - sizeof (d->d_name) + len;
if (sz > bufsz)
{ {
if (buf != 0)
free (buf);
bufsz *= 2; bufsz *= 2;
if (sizeof *d - sizeof d->d_name + len > bufsz) if (sz > bufsz)
bufsz = sizeof *d - sizeof d->d_name + len; bufsz = sz;
buf = xmalloc (bufsz); buf = xrealloc (buf, bufsz);
} }
d = (struct dirent *) buf; d = (struct dirent *) buf;
#ifdef __MINGW32__ #ifdef __MINGW32__
@ -1200,7 +1199,6 @@ local_stat (const char *path, struct stat *buf)
void void
dir_setup_glob (glob_t *gl) dir_setup_glob (glob_t *gl)
{ {
/* Bogus sunos4 compiler complains (!) about & before functions. */
gl->gl_opendir = open_dirstream; gl->gl_opendir = open_dirstream;
gl->gl_readdir = read_dirstream; gl->gl_readdir = read_dirstream;
gl->gl_closedir = ansi_free; gl->gl_closedir = ansi_free;

View File

@ -360,7 +360,9 @@ variable_expand_string (char *line, const char *string, long length)
if (ppercent) if (ppercent)
{ {
++ppercent; ++ppercent;
rpercent = 0; rpercent = find_percent (replace);
if (rpercent)
++rpercent;
} }
else else
{ {
@ -370,8 +372,8 @@ variable_expand_string (char *line, const char *string, long length)
--replace; --replace;
} }
o = patsubst_expand (o, value, pattern, replace, o = patsubst_expand_pat (o, value, pattern, replace,
ppercent, rpercent); ppercent, rpercent);
if (v->recursive) if (v->recursive)
free (value); free (value);

412
file.c
View File

@ -69,16 +69,16 @@ static int all_secondary = 0;
/* Access the hash table of all file records. /* Access the hash table of all file records.
lookup_file given a name, return the struct file * for that name, lookup_file given a name, return the struct file * for that name,
or nil if there is none. or nil if there is none.
enter_file similar, but create one if there is none. */ */
struct file * struct file *
lookup_file (char *name) lookup_file (const char *name)
{ {
register struct file *f; struct file *f;
struct file file_key; struct file file_key;
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
char *lname, *ln; char *lname;
#endif #endif
assert (*name != '\0'); assert (*name != '\0');
@ -90,8 +90,9 @@ lookup_file (char *name)
# ifndef WANT_CASE_SENSITIVE_TARGETS # ifndef WANT_CASE_SENSITIVE_TARGETS
if (*name != '.') if (*name != '.')
{ {
char *n; const char *n;
lname = xmalloc (strlen (name) + 1); char *ln;
lname = xstrdup (name);
for (n = name, ln = lname; *n != '\0'; ++n, ++ln) for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
*ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n;
*ln = '\0'; *ln = '\0';
@ -112,15 +113,13 @@ lookup_file (char *name)
if (*name == '\0') if (*name == '\0')
/* It was all slashes after a dot. */ /* It was all slashes after a dot. */
#ifdef VMS #if defined(VMS)
name = "[]"; name = "[]";
#else #elif defined(_AMIGA)
#ifdef _AMIGA
name = ""; name = "";
#else #else
name = "./"; name = "./";
#endif /* AMIGA */ #endif
#endif /* VMS */
file_key.hname = name; file_key.hname = name;
f = hash_find_item (&files, &file_key); f = hash_find_item (&files, &file_key);
@ -128,39 +127,41 @@ lookup_file (char *name)
if (*name != '.') if (*name != '.')
free (lname); free (lname);
#endif #endif
return f; return f;
} }
/* Look up a file record for file NAME and return it.
Create a new record if one doesn't exist. NAME will be stored in the
new record so it should be constant or in the strcache etc.
*/
struct file * struct file *
enter_file (char *name) enter_file (const char *name)
{ {
register struct file *f; struct file *f;
register struct file *new; struct file *new;
register struct file **file_slot; struct file **file_slot;
struct file file_key; struct file file_key;
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
char *lname, *ln;
#endif
assert (*name != '\0'); assert (*name != '\0');
assert (strcache_iscached (name));
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
if (*name != '.') if (*name != '.')
{ {
char *n; const char *n;
lname = xmalloc (strlen (name) + 1); char *lname, *ln;
lname = xstrdup (name);
for (n = name, ln = lname; *n != '\0'; ++n, ++ln) for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
{ if (isupper ((unsigned char)*n))
if (isupper ((unsigned char)*n)) *ln = tolower ((unsigned char)*n);
*ln = tolower ((unsigned char)*n); else
else *ln = *n;
*ln = *n;
}
*ln = 0; *ln = '\0';
/* Creates a possible leak, old value of name is unreachable, but I name = strcache_add (lname);
currently don't know how to fix it. */ free (lname);
name = lname;
} }
#endif #endif
@ -168,13 +169,7 @@ enter_file (char *name)
file_slot = (struct file **) hash_find_slot (&files, &file_key); file_slot = (struct file **) hash_find_slot (&files, &file_key);
f = *file_slot; f = *file_slot;
if (! HASH_VACANT (f) && !f->double_colon) if (! HASH_VACANT (f) && !f->double_colon)
{ return f;
#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS)
if (*name != '.')
free (lname);
#endif
return f;
}
new = xmalloc (sizeof (struct file)); new = xmalloc (sizeof (struct file));
memset (new, '\0', sizeof (struct file)); memset (new, '\0', sizeof (struct file));
@ -197,27 +192,12 @@ enter_file (char *name)
return new; return new;
} }
/* 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 (struct file *from_file, char *to_hname)
{
rehash_file (from_file, to_hname);
while (from_file)
{
from_file->name = from_file->hname;
from_file = from_file->prev;
}
}
/* Rehash FILE to NAME. This is not as simple as resetting /* Rehash FILE to NAME. This is not as simple as resetting
the `hname' member, since it must be put in a new hash bucket, the `hname' member, since it must be put in a new hash bucket,
and possibly merged with an existing file called NAME. */ and possibly merged with an existing file called NAME. */
void void
rehash_file (struct file *from_file, char *to_hname) rehash_file (struct file *from_file, const char *to_hname)
{ {
struct file file_key; struct file file_key;
struct file **file_slot; struct file **file_slot;
@ -225,108 +205,130 @@ rehash_file (struct file *from_file, char *to_hname)
struct file *deleted_file; struct file *deleted_file;
struct file *f; struct file *f;
/* If it's already that name, we're done. */
file_key.hname = to_hname; file_key.hname = to_hname;
if (0 == file_hash_cmp (from_file, &file_key)) if (! file_hash_cmp (from_file, &file_key))
return; return;
/* Find the end of the renamed list for the "from" file. */
file_key.hname = from_file->hname; file_key.hname = from_file->hname;
while (from_file->renamed != 0) while (from_file->renamed != 0)
from_file = from_file->renamed; from_file = from_file->renamed;
if (file_hash_cmp (from_file, &file_key)) if (file_hash_cmp (from_file, &file_key))
/* hname changed unexpectedly */ /* hname changed unexpectedly!! */
abort (); abort ();
/* Remove the "from" file from the hash. */
deleted_file = hash_delete (&files, from_file); deleted_file = hash_delete (&files, from_file);
if (deleted_file != from_file) if (deleted_file != from_file)
/* from_file isn't the one stored in files */ /* from_file isn't the one stored in files */
abort (); abort ();
/* Find where the newly renamed file will go in the hash. */
file_key.hname = to_hname; file_key.hname = to_hname;
file_slot = (struct file **) hash_find_slot (&files, &file_key); file_slot = (struct file **) hash_find_slot (&files, &file_key);
to_file = *file_slot; to_file = *file_slot;
/* Change the hash name for this file. */
from_file->hname = to_hname; from_file->hname = to_hname;
for (f = from_file->double_colon; f != 0; f = f->prev) for (f = from_file->double_colon; f != 0; f = f->prev)
f->hname = to_hname; f->hname = to_hname;
/* If the new name doesn't exist yet just set it to the renamed file. */
if (HASH_VACANT (to_file)) if (HASH_VACANT (to_file))
hash_insert_at (&files, from_file, file_slot); {
hash_insert_at (&files, from_file, file_slot);
return;
}
/* TO_FILE already exists under TO_HNAME.
We must retain TO_FILE and merge FROM_FILE into it. */
if (from_file->cmds != 0)
{
if (to_file->cmds == 0)
to_file->cmds = from_file->cmds;
else if (from_file->cmds != to_file->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 (to_file->cmds->fileinfo.filenm != 0)
error (&from_file->cmds->fileinfo,
_("Commands were specified for file `%s' at %s:%lu,"),
from_file->name, to_file->cmds->fileinfo.filenm,
to_file->cmds->fileinfo.lineno);
else
error (&from_file->cmds->fileinfo,
_("Commands for file `%s' were found by implicit rule search,"),
from_file->name);
error (&from_file->cmds->fileinfo,
_("but `%s' is now considered the same file as `%s'."),
from_file->name, to_hname);
error (&from_file->cmds->fileinfo,
_("Commands for `%s' will be ignored in favor of those for `%s'."),
to_hname, from_file->name);
}
}
/* Merge the dependencies of the two files. */
if (to_file->deps == 0)
to_file->deps = from_file->deps;
else else
{ {
/* TO_FILE already exists under TO_HNAME. struct dep *deps = to_file->deps;
We must retain TO_FILE and merge FROM_FILE into it. */ while (deps->next != 0)
deps = deps->next;
deps->next = from_file->deps;
}
if (from_file->cmds != 0) merge_variable_set_lists (&to_file->variables, from_file->variables);
{
if (to_file->cmds == 0)
to_file->cmds = from_file->cmds;
else if (from_file->cmds != to_file->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 (to_file->cmds->fileinfo.filenm != 0)
error (&from_file->cmds->fileinfo,
_("Commands were specified for file `%s' at %s:%lu,"),
from_file->name, to_file->cmds->fileinfo.filenm,
to_file->cmds->fileinfo.lineno);
else
error (&from_file->cmds->fileinfo,
_("Commands for file `%s' were found by implicit rule search,"),
from_file->name);
error (&from_file->cmds->fileinfo,
_("but `%s' is now considered the same file as `%s'."),
from_file->name, to_hname);
error (&from_file->cmds->fileinfo,
_("Commands for `%s' will be ignored in favor of those for `%s'."),
to_hname, from_file->name);
}
}
/* Merge the dependencies of the two files. */ if (to_file->double_colon && from_file->is_target && !from_file->double_colon)
fatal (NILF, _("can't rename single-colon `%s' to double-colon `%s'"),
if (to_file->deps == 0) from_file->name, to_hname);
to_file->deps = from_file->deps; if (!to_file->double_colon && from_file->double_colon)
{
if (to_file->is_target)
fatal (NILF, _("can't rename double-colon `%s' to single-colon `%s'"),
from_file->name, to_hname);
else else
{ to_file->double_colon = from_file->double_colon;
register struct dep *deps = to_file->deps; }
while (deps->next != 0)
deps = deps->next;
deps->next = from_file->deps;
}
merge_variable_set_lists (&to_file->variables, from_file->variables); if (from_file->last_mtime > to_file->last_mtime)
/* %%% Kludge so -W wins on a file that gets vpathized. */
to_file->last_mtime = from_file->last_mtime;
if (to_file->double_colon && from_file->is_target && !from_file->double_colon) to_file->mtime_before_update = from_file->mtime_before_update;
fatal (NILF, _("can't rename single-colon `%s' to double-colon `%s'"),
from_file->name, to_hname);
if (!to_file->double_colon && from_file->double_colon)
{
if (to_file->is_target)
fatal (NILF, _("can't rename double-colon `%s' to single-colon `%s'"),
from_file->name, to_hname);
else
to_file->double_colon = from_file->double_colon;
}
if (from_file->last_mtime > to_file->last_mtime)
/* %%% Kludge so -W wins on a file that gets vpathized. */
to_file->last_mtime = from_file->last_mtime;
to_file->mtime_before_update = from_file->mtime_before_update;
#define MERGE(field) to_file->field |= from_file->field #define MERGE(field) to_file->field |= from_file->field
MERGE (precious); MERGE (precious);
MERGE (tried_implicit); MERGE (tried_implicit);
MERGE (updating); MERGE (updating);
MERGE (updated); MERGE (updated);
MERGE (is_target); MERGE (is_target);
MERGE (cmd_target); MERGE (cmd_target);
MERGE (phony); MERGE (phony);
MERGE (ignore_vpath); MERGE (ignore_vpath);
#undef MERGE #undef MERGE
from_file->renamed = to_file; from_file->renamed = to_file;
}
/* 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 (struct file *from_file, const char *to_hname)
{
rehash_file (from_file, to_hname);
while (from_file)
{
from_file->name = from_file->hname;
from_file = from_file->prev;
} }
} }
@ -338,8 +340,8 @@ rehash_file (struct file *from_file, char *to_hname)
void void
remove_intermediates (int sig) remove_intermediates (int sig)
{ {
register struct file **file_slot; struct file **file_slot;
register struct file **file_end; struct file **file_end;
int doneany = 0; int doneany = 0;
/* If there's no way we will ever remove anything anyway, punt early. */ /* If there's no way we will ever remove anything anyway, punt early. */
@ -354,7 +356,7 @@ remove_intermediates (int sig)
for ( ; file_slot < file_end; file_slot++) for ( ; file_slot < file_end; file_slot++)
if (! HASH_VACANT (*file_slot)) if (! HASH_VACANT (*file_slot))
{ {
register struct file *f = *file_slot; struct file *f = *file_slot;
/* Is this file eligible for automatic deletion? /* Is this file eligible for automatic deletion?
Yes, IFF: it's marked intermediate, it's not secondary, it wasn't Yes, IFF: it's marked intermediate, it's not secondary, it wasn't
given on the command-line, and it's either a -include makefile or given on the command-line, and it's either a -include makefile or
@ -444,7 +446,6 @@ parse_prereqs (char *p)
return new; return new;
} }
/* Set the intermediate flag. */ /* Set the intermediate flag. */
static void static void
@ -460,7 +461,7 @@ expand_deps (struct file *f)
{ {
struct dep *d; struct dep *d;
struct dep *old = f->deps; struct dep *old = f->deps;
char *file_stem = f->stem; const char *file_stem = f->stem;
unsigned int last_dep_has_cmds = f->updating; unsigned int last_dep_has_cmds = f->updating;
int initialized = 0; int initialized = 0;
@ -476,9 +477,13 @@ expand_deps (struct file *f)
continue; continue;
/* Create the dependency list. /* Create the dependency list.
If we're not doing 2nd expansion, then it's just the name. */ If we're not doing 2nd expansion, then it's just the name. We will
still need to massage it though. */
if (! d->need_2nd_expansion) if (! d->need_2nd_expansion)
p = d->name; {
p = variable_expand ("");
variable_buffer_output (p, d->name, strlen (d->name) + 1);
}
else else
{ {
/* If it's from a static pattern rule, convert the patterns into /* If it's from a static pattern rule, convert the patterns into
@ -490,8 +495,7 @@ expand_deps (struct file *f)
o = subst_expand (buffer, d->name, "%", "$*", 1, 2, 0); o = subst_expand (buffer, d->name, "%", "$*", 1, 2, 0);
free (d->name); d->name = strcache_add_len (buffer, o - buffer);
d->name = savestring (buffer, o - buffer);
d->staticpattern = 0; /* Clear staticpattern so that we don't d->staticpattern = 0; /* Clear staticpattern so that we don't
re-expand %s below. */ re-expand %s below. */
} }
@ -525,48 +529,47 @@ expand_deps (struct file *f)
plain prerequisite names. */ plain prerequisite names. */
if (new && d->staticpattern) if (new && d->staticpattern)
{ {
char *pattern = "%"; const char *pattern = "%";
char *buffer = variable_expand (""); char *buffer = variable_expand ("");
struct dep *dp = new, *dl = 0; struct dep *dp = new, *dl = 0;
while (dp != 0) while (dp != 0)
{ {
char *percent = find_percent (dp->name); char *percent;
int nl = strlen (dp->name) + 1;
char *nm = alloca (nl);
memcpy (nm, dp->name, nl);
percent = find_percent (nm);
if (percent) if (percent)
{ {
char *o;
/* We have to handle empty stems specially, because that /* We have to handle empty stems specially, because that
would be equivalent to $(patsubst %,dp->name,) which would be equivalent to $(patsubst %,dp->name,) which
will always be empty. */ will always be empty. */
if (d->stem[0] == '\0') if (d->stem[0] == '\0')
/* This needs memmove() in ISO C. */
memmove (percent, percent+1, strlen (percent));
else
{ {
char *o = patsubst_expand (buffer, d->stem, pattern, memmove (percent, percent+1, strlen (percent));
dp->name, pattern+1, o = variable_buffer_output (buffer, nm, strlen (nm) + 1);
percent+1);
if (o == buffer)
dp->name[0] = '\0';
else
{
free (dp->name);
dp->name = savestring (buffer, o - buffer);
}
} }
else
o = patsubst_expand_pat (buffer, d->stem, pattern, nm,
pattern+1, percent+1);
/* If the name expanded to the empty string, ignore it. */ /* If the name expanded to the empty string, ignore it. */
if (dp->name[0] == '\0') if (buffer[0] == '\0')
{ {
struct dep *df = dp; struct dep *df = dp;
if (dp == new) if (dp == new)
dp = new = new->next; dp = new = new->next;
else else
dp = dl->next = dp->next; dp = dl->next = dp->next;
/* @@ Are we leaking df->name here? */
df->name = 0;
free_dep (df); free_dep (df);
continue; continue;
} }
/* Save the name. */
dp->name = strcache_add_len (buffer, o - buffer);
} }
dl = dp; dl = dp;
dp = dp->next; dp = dp->next;
@ -579,8 +582,6 @@ expand_deps (struct file *f)
d1->file = lookup_file (d1->name); d1->file = lookup_file (d1->name);
if (d1->file == 0) if (d1->file == 0)
d1->file = enter_file (d1->name); d1->file = enter_file (d1->name);
else
free (d1->name);
d1->name = 0; d1->name = 0;
d1->staticpattern = 0; d1->staticpattern = 0;
d1->need_2nd_expansion = 0; d1->need_2nd_expansion = 0;
@ -635,27 +636,25 @@ snap_deps (void)
struct file **file_slot; struct file **file_slot;
struct file **file_end; struct file **file_end;
/* Perform second expansion and enter each dependency /* Perform second expansion and enter each dependency name as a file. */
name as a file. */
/* Expand .SUFFIXES first; it's dependencies are used for /* Expand .SUFFIXES first; it's dependencies are used for $$* calculation. */
$$* calculation. */
for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev) for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev)
expand_deps (f); expand_deps (f);
/* We must use hash_dump (), because within this loop /* For every target that's not .SUFFIXES, expand its dependencies.
we might add new files to the table, possibly causing We must use hash_dump (), because within this loop we might add new files
an in-situ table expansion. */ to the table, possibly causing an in-situ table expansion. */
file_slot_0 = (struct file **) hash_dump (&files, 0, 0); file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
file_end = file_slot_0 + files.ht_fill; file_end = file_slot_0 + files.ht_fill;
for (file_slot = file_slot_0; file_slot < file_end; file_slot++) for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
for (f = *file_slot; f != 0; f = f->prev) for (f = *file_slot; f != 0; f = f->prev)
{ if (strcmp (f->name, ".SUFFIXES") != 0)
if (strcmp (f->name, ".SUFFIXES") != 0) expand_deps (f);
expand_deps (f);
}
free (file_slot_0); free (file_slot_0);
/* Now manage all the special targets. */
for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
for (d = f->deps; d != 0; d = d->next) for (d = f->deps; d != 0; d = d->next)
for (f2 = d->file; f2 != 0; f2 = f2->prev) for (f2 = d->file; f2 != 0; f2 = f2->prev)
@ -678,35 +677,26 @@ snap_deps (void)
} }
for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
{ /* Mark .INTERMEDIATE deps as intermediate files. */
/* .INTERMEDIATE with deps listed for (d = f->deps; d != 0; d = d->next)
marks those deps as intermediate files. */ for (f2 = d->file; f2 != 0; f2 = f2->prev)
for (d = f->deps; d != 0; d = d->next) f2->intermediate = 1;
for (f2 = d->file; f2 != 0; f2 = f2->prev) /* .INTERMEDIATE with no deps does nothing.
f2->intermediate = 1; Marking all files as intermediates is useless since the goal targets
/* .INTERMEDIATE with no deps does nothing. would be deleted after they are built. */
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) for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev)
{ /* Mark .SECONDARY deps as both intermediate and secondary. */
/* .SECONDARY with deps listed if (f->deps)
marks those deps as intermediate files for (d = f->deps; d != 0; d = d->next)
in that they don't get rebuilt if not actually needed; for (f2 = d->file; f2 != 0; f2 = f2->prev)
but unlike real intermediate files, f2->intermediate = f2->secondary = 1;
these are not deleted after make finishes. */ /* .SECONDARY with no deps listed marks *all* files that way. */
if (f->deps) else
for (d = f->deps; d != 0; d = d->next) {
for (f2 = d->file; f2 != 0; f2 = f2->prev) all_secondary = 1;
f2->intermediate = f2->secondary = 1; hash_map (&files, set_intermediate);
/* .SECONDARY with no deps listed marks *all* files that way. */ }
else
{
all_secondary = 1;
hash_map (&files, set_intermediate);
}
}
f = lookup_file (".EXPORT_ALL_VARIABLES"); f = lookup_file (".EXPORT_ALL_VARIABLES");
if (f != 0 && f->is_target) if (f != 0 && f->is_target)
@ -853,11 +843,10 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
sprintf (p, "%lu", (unsigned long) t); sprintf (p, "%lu", (unsigned long) t);
p += strlen (p); p += strlen (p);
/* Append nanoseconds as a fraction, but remove trailing zeros. /* Append nanoseconds as a fraction, but remove trailing zeros. We don't
We don't know the actual timestamp resolution, since clock_getres know the actual timestamp resolution, since clock_getres applies only to
applies only to local times, whereas this timestamp might come local times, whereas this timestamp might come from a remote filesystem.
from a remote filesystem. So removing trailing zeros is the So removing trailing zeros is the best guess that we can do. */
best guess that we can do. */
sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts)); sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts));
p += strlen (p) - 1; p += strlen (p) - 1;
while (*p == '0') while (*p == '0')
@ -872,7 +861,7 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
static void static void
print_file (const void *item) print_file (const void *item)
{ {
struct file *f = (struct file *) item; const struct file *f = item;
struct dep *d; struct dep *d;
struct dep *ood = 0; struct dep *ood = 0;
@ -993,6 +982,39 @@ print_file_data_base (void)
fputs (_("\n# files hash-table stats:\n# "), stdout); fputs (_("\n# files hash-table stats:\n# "), stdout);
hash_print_stats (&files, stdout); hash_print_stats (&files, stdout);
} }
/* Verify the integrity of the data base of files. */
#define VERIFY_CACHED(_p,_n) \
do{\
if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \
printf ("%s: Field %s not cached: %s\n", _p->name, # _n, _p->_n); \
}while(0)
static void
verify_file (const void *item)
{
const struct file *f = item;
const struct dep *d;
VERIFY_CACHED (f, name);
VERIFY_CACHED (f, hname);
VERIFY_CACHED (f, vpath);
VERIFY_CACHED (f, stem);
/* Check the deps. */
for (d = f->deps; d != 0; d = d->next)
{
VERIFY_CACHED (d, name);
VERIFY_CACHED (d, stem);
}
}
void
verify_file_data_base (void)
{
hash_map (&files, verify_file);
}
#define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) #define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500)

View File

@ -25,14 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
struct file struct file
{ {
char *name; const char *name;
char *hname; /* Hashed filename */ const char *hname; /* Hashed filename */
char *vpath; /* VPATH/vpath pathname */ const char *vpath; /* VPATH/vpath pathname */
struct dep *deps; /* all dependencies, including duplicates */ struct dep *deps; /* all dependencies, including duplicates */
struct commands *cmds; /* Commands to execute for this target. */ struct commands *cmds; /* Commands to execute for this target. */
int command_flags; /* Flags OR'd in for cmds; see commands.h. */ int command_flags; /* Flags OR'd in for cmds; see commands.h. */
char *stem; /* Implicit stem, if an implicit const char *stem; /* Implicit stem, if an implicit
rule has been used */ rule has been used */
struct dep *also_make; /* Targets that are made by making this. */ struct dep *also_make; /* Targets that are made by making this. */
FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */ FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */
FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating
@ -101,13 +101,13 @@ extern struct file *default_goal_file, *suffix_file, *default_file;
extern char **default_goal_name; extern char **default_goal_name;
struct file *lookup_file (char *name); struct file *lookup_file (const char *name);
struct file *enter_file (char *name); struct file *enter_file (const char *name);
struct dep *parse_prereqs (char *prereqs); struct dep *parse_prereqs (char *prereqs);
void remove_intermediates (int sig); void remove_intermediates (int sig);
void snap_deps (void); void snap_deps (void);
void rename_file (struct file *file, char *name); void rename_file (struct file *file, const char *name);
void rehash_file (struct file *file, char *name); void rehash_file (struct file *file, const char *name);
void set_command_state (struct file *file, enum cmd_state state); void set_command_state (struct file *file, enum cmd_state state);
void notice_finished_file (struct file *file); void notice_finished_file (struct file *file);
void init_hash_files (void); void init_hash_files (void);

View File

@ -74,11 +74,11 @@ static struct hash_table function_table;
whitespace-delimited words. */ whitespace-delimited words. */
char * char *
subst_expand (char *o, char *text, char *subst, char *replace, subst_expand (char *o, const char *text, const char *subst, const char *replace,
unsigned int slen, unsigned int rlen, int by_word) unsigned int slen, unsigned int rlen, int by_word)
{ {
char *t = text; const char *t = text;
char *p; const char *p;
if (slen == 0 && !by_word) if (slen == 0 && !by_word)
{ {
@ -123,10 +123,7 @@ subst_expand (char *o, char *text, char *subst, char *replace,
o = variable_buffer_output (o, replace, rlen); o = variable_buffer_output (o, replace, rlen);
/* Advance T past the string to be replaced. */ /* Advance T past the string to be replaced. */
{ t = p + slen;
char *nt = p + slen;
t = nt;
}
} while (*t != '\0'); } while (*t != '\0');
return o; return o;
@ -144,24 +141,16 @@ subst_expand (char *o, char *text, char *subst, char *replace,
*/ */
char * char *
patsubst_expand (char *o, char *text, char *pattern, char *replace, patsubst_expand_pat (char *o, const char *text,
char *pattern_percent, char *replace_percent) const char *pattern, const char *replace,
const char *pattern_percent, const char *replace_percent)
{ {
unsigned int pattern_prepercent_len, pattern_postpercent_len; unsigned int pattern_prepercent_len, pattern_postpercent_len;
unsigned int replace_prepercent_len, replace_postpercent_len; unsigned int replace_prepercent_len, replace_postpercent_len;
char *t; const char *t;
unsigned int len; unsigned int len;
int doneany = 0; int doneany = 0;
/* We call find_percent on REPLACE before checking PATTERN so that REPLACE
will be collapsed before we call subst_expand if PATTERN has no %. */
if (!replace_percent)
{
replace_percent = find_percent (replace);
if (replace_percent)
++replace_percent;
}
/* Record the length of REPLACE before and after the % so we don't have to /* Record the length of REPLACE before and after the % so we don't have to
compute these lengths more than once. */ compute these lengths more than once. */
if (replace_percent) if (replace_percent)
@ -175,12 +164,6 @@ patsubst_expand (char *o, char *text, char *pattern, char *replace,
replace_postpercent_len = 0; replace_postpercent_len = 0;
} }
if (!pattern_percent)
{
pattern_percent = find_percent (pattern);
if (pattern_percent)
++pattern_percent;
}
if (!pattern_percent) if (!pattern_percent)
/* With no % in the pattern, this is just a simple substitution. */ /* With no % in the pattern, this is just a simple substitution. */
return subst_expand (o, text, pattern, replace, return subst_expand (o, text, pattern, replace,
@ -251,6 +234,32 @@ patsubst_expand (char *o, char *text, char *pattern, char *replace,
return o; return o;
} }
/* Store into VARIABLE_BUFFER at O the result of scanning TEXT
and replacing strings matching PATTERN with REPLACE.
If PATTERN_PERCENT is not nil, PATTERN has already been
run through find_percent, and PATTERN_PERCENT is the result.
If REPLACE_PERCENT is not nil, REPLACE has already been
run through find_percent, and REPLACE_PERCENT is the result.
Note that we expect PATTERN_PERCENT and REPLACE_PERCENT to point to the
character _AFTER_ the %, not to the % itself.
*/
char *
patsubst_expand (char *o, const char *text, char *pattern, char *replace)
{
const char *pattern_percent = find_percent (pattern);
const char *replace_percent = find_percent (replace);
/* If there's a percent in the pattern or replacement skip it. */
if (replace_percent)
++replace_percent;
if (pattern_percent)
++pattern_percent;
return patsubst_expand_pat (o, text, pattern, replace,
pattern_percent, replace_percent);
}
/* Look up a function by name. */ /* Look up a function by name. */
@ -343,8 +352,8 @@ string_glob (char *line)
{ {
static char *result = 0; static char *result = 0;
static unsigned int length; static unsigned int length;
register struct nameseq *chain; struct nameseq *chain;
register unsigned int idx; unsigned int idx;
chain = multi_glob (parse_file_seq chain = multi_glob (parse_file_seq
(&line, '\0', sizeof (struct nameseq), (&line, '\0', sizeof (struct nameseq),
@ -363,7 +372,7 @@ string_glob (char *line)
idx = 0; idx = 0;
while (chain != 0) while (chain != 0)
{ {
register char *name = chain->name; const char *name = chain->name;
unsigned int len = strlen (name); unsigned int len = strlen (name);
struct nameseq *next = chain->next; struct nameseq *next = chain->next;
@ -383,8 +392,6 @@ string_glob (char *line)
idx += len; idx += len;
result[idx++] = ' '; result[idx++] = ' ';
} }
free (name);
} }
/* Kill the last space and terminate the string. */ /* Kill the last space and terminate the string. */
@ -403,7 +410,7 @@ string_glob (char *line)
static char * static char *
func_patsubst (char *o, char **argv, const char *funcname UNUSED) func_patsubst (char *o, char **argv, const char *funcname UNUSED)
{ {
o = patsubst_expand (o, argv[2], argv[0], argv[1], (char *) 0, (char *) 0); o = patsubst_expand (o, argv[2], argv[0], argv[1]);
return o; return o;
} }
@ -417,10 +424,10 @@ func_join (char *o, char **argv, const char *funcname UNUSED)
by the corresponding word of the second argument. by the corresponding word of the second argument.
If the two arguments have a different number of words, If the two arguments have a different number of words,
the excess words are just output separated by blanks. */ the excess words are just output separated by blanks. */
register char *tp; const char *tp;
register char *pp; const char *pp;
char *list1_iterator = argv[0]; const char *list1_iterator = argv[0];
char *list2_iterator = argv[1]; const char *list2_iterator = argv[1];
do do
{ {
unsigned int len1, len2; unsigned int len1, len2;
@ -452,7 +459,7 @@ static char *
func_origin (char *o, char **argv, const char *funcname UNUSED) func_origin (char *o, char **argv, const char *funcname UNUSED)
{ {
/* Expand the argument. */ /* Expand the argument. */
register struct variable *v = lookup_variable (argv[0], strlen (argv[0])); struct variable *v = lookup_variable (argv[0], strlen (argv[0]));
if (v == 0) if (v == 0)
o = variable_buffer_output (o, "undefined", 9); o = variable_buffer_output (o, "undefined", 9);
else else
@ -491,7 +498,7 @@ func_origin (char *o, char **argv, const char *funcname UNUSED)
static char * static char *
func_flavor (char *o, char **argv, const char *funcname UNUSED) func_flavor (char *o, char **argv, const char *funcname UNUSED)
{ {
register struct variable *v = lookup_variable (argv[0], strlen (argv[0])); struct variable *v = lookup_variable (argv[0], strlen (argv[0]));
if (v == 0) if (v == 0)
o = variable_buffer_output (o, "undefined", 9); o = variable_buffer_output (o, "undefined", 9);
@ -519,8 +526,8 @@ static char *
func_notdir_suffix (char *o, char **argv, const char *funcname) func_notdir_suffix (char *o, char **argv, const char *funcname)
{ {
/* Expand the argument. */ /* Expand the argument. */
char *list_iterator = argv[0]; const char *list_iterator = argv[0];
char *p2 =0; const char *p2;
int doneany =0; int doneany =0;
unsigned int len=0; unsigned int len=0;
@ -528,7 +535,7 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
int is_notdir = !is_suffix; int is_notdir = !is_suffix;
while ((p2 = find_next_token (&list_iterator, &len)) != 0) while ((p2 = find_next_token (&list_iterator, &len)) != 0)
{ {
char *p = p2 + len; const char *p = p2 + len;
while (p >= p2 && (!is_suffix || *p != '.')) while (p >= p2 && (!is_suffix || *p != '.'))
@ -563,13 +570,12 @@ func_notdir_suffix (char *o, char **argv, const char *funcname)
doneany = 1; doneany = 1;
} }
} }
if (doneany) if (doneany)
/* Kill last space. */ /* Kill last space. */
--o; --o;
return o; return o;
} }
@ -577,68 +583,68 @@ static char *
func_basename_dir (char *o, char **argv, const char *funcname) func_basename_dir (char *o, char **argv, const char *funcname)
{ {
/* Expand the argument. */ /* Expand the argument. */
char *p3 = argv[0]; const char *p3 = argv[0];
char *p2=0; const char *p2;
int doneany=0; int doneany=0;
unsigned int len=0; unsigned int len=0;
char *p=0;
int is_basename= streq (funcname, "basename"); int is_basename= streq (funcname, "basename");
int is_dir= !is_basename; int is_dir= !is_basename;
while ((p2 = find_next_token (&p3, &len)) != 0) while ((p2 = find_next_token (&p3, &len)) != 0)
{ {
p = p2 + len; const char *p = p2 + len;
while (p >= p2 && (!is_basename || *p != '.')) while (p >= p2 && (!is_basename || *p != '.'))
{ {
if (IS_PATHSEP (*p)) if (IS_PATHSEP (*p))
break; break;
--p; --p;
} }
if (p >= p2 && (is_dir)) if (p >= p2 && (is_dir))
o = variable_buffer_output (o, p2, ++p - p2); o = variable_buffer_output (o, p2, ++p - p2);
else if (p >= p2 && (*p == '.')) else if (p >= p2 && (*p == '.'))
o = variable_buffer_output (o, p2, p - p2); o = variable_buffer_output (o, p2, p - p2);
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* Handle the "d:foobar" case */ /* Handle the "d:foobar" case */
else if (p2[0] && p2[1] == ':' && is_dir) else if (p2[0] && p2[1] == ':' && is_dir)
o = variable_buffer_output (o, p2, 2); o = variable_buffer_output (o, p2, 2);
#endif #endif
else if (is_dir) else if (is_dir)
#ifdef VMS #ifdef VMS
o = variable_buffer_output (o, "[]", 2); o = variable_buffer_output (o, "[]", 2);
#else #else
#ifndef _AMIGA #ifndef _AMIGA
o = variable_buffer_output (o, "./", 2); o = variable_buffer_output (o, "./", 2);
#else #else
; /* Just a nop... */ ; /* Just a nop... */
#endif /* AMIGA */ #endif /* AMIGA */
#endif /* !VMS */ #endif /* !VMS */
else else
/* The entire name is the basename. */ /* The entire name is the basename. */
o = variable_buffer_output (o, p2, len); o = variable_buffer_output (o, p2, len);
o = variable_buffer_output (o, " ", 1); o = variable_buffer_output (o, " ", 1);
doneany = 1; doneany = 1;
} }
if (doneany)
/* Kill last space. */
--o;
if (doneany)
/* Kill last space. */
--o;
return o; return o;
} }
static char * static char *
func_addsuffix_addprefix (char *o, char **argv, const char *funcname) func_addsuffix_addprefix (char *o, char **argv, const char *funcname)
{ {
int fixlen = strlen (argv[0]); int fixlen = strlen (argv[0]);
char *list_iterator = argv[1]; const char *list_iterator = argv[1];
int is_addprefix = streq (funcname, "addprefix"); int is_addprefix = streq (funcname, "addprefix");
int is_addsuffix = !is_addprefix; int is_addsuffix = !is_addprefix;
int doneany = 0; int doneany = 0;
char *p; const char *p;
unsigned int len; unsigned int len;
while ((p = find_next_token (&list_iterator, &len)) != 0) while ((p = find_next_token (&list_iterator, &len)) != 0)
@ -673,8 +679,8 @@ static char *
func_firstword (char *o, char **argv, const char *funcname UNUSED) func_firstword (char *o, char **argv, const char *funcname UNUSED)
{ {
unsigned int i; unsigned int i;
char *words = argv[0]; /* Use a temp variable for find_next_token */ const char *words = argv[0]; /* Use a temp variable for find_next_token */
char *p = find_next_token (&words, &i); const char *p = find_next_token (&words, &i);
if (p != 0) if (p != 0)
o = variable_buffer_output (o, p, i); o = variable_buffer_output (o, p, i);
@ -686,9 +692,9 @@ static char *
func_lastword (char *o, char **argv, const char *funcname UNUSED) func_lastword (char *o, char **argv, const char *funcname UNUSED)
{ {
unsigned int i; unsigned int i;
char *words = argv[0]; /* Use a temp variable for find_next_token */ const char *words = argv[0]; /* Use a temp variable for find_next_token */
char *p = 0; const char *p;
char *t; const char *t;
while ((t = find_next_token (&words, &i))) while ((t = find_next_token (&words, &i)))
p = t; p = t;
@ -703,7 +709,7 @@ static char *
func_words (char *o, char **argv, const char *funcname UNUSED) func_words (char *o, char **argv, const char *funcname UNUSED)
{ {
int i = 0; int i = 0;
char *word_iterator = argv[0]; const char *word_iterator = argv[0];
char buf[20]; char buf[20];
while (find_next_token (&word_iterator, (unsigned int *) 0) != 0) while (find_next_token (&word_iterator, (unsigned int *) 0) != 0)
@ -712,7 +718,6 @@ func_words (char *o, char **argv, const char *funcname UNUSED)
sprintf (buf, "%d", i); sprintf (buf, "%d", i);
o = variable_buffer_output (o, buf, strlen (buf)); o = variable_buffer_output (o, buf, strlen (buf));
return o; return o;
} }
@ -751,19 +756,18 @@ check_numeric (const char *s, const char *msg)
static char * static char *
func_word (char *o, char **argv, const char *funcname UNUSED) func_word (char *o, char **argv, const char *funcname UNUSED)
{ {
char *end_p=0; const char *end_p;
int i=0; const char *p;
char *p=0; int i;
/* Check the first argument. */ /* Check the first argument. */
check_numeric (argv[0], _("non-numeric first argument to `word' function")); check_numeric (argv[0], _("non-numeric first argument to `word' function"));
i = atoi (argv[0]); i = atoi (argv[0]);
if (i == 0) if (i == 0)
fatal (*expanding_var, fatal (*expanding_var,
_("first argument to `word' function must be greater than 0")); _("first argument to `word' function must be greater than 0"));
end_p = argv[1]; end_p = argv[1];
while ((p = find_next_token (&end_p, 0)) != 0) while ((p = find_next_token (&end_p, 0)) != 0)
if (--i == 0) if (--i == 0)
@ -795,8 +799,8 @@ func_wordlist (char *o, char **argv, const char *funcname UNUSED)
if (count > 0) if (count > 0)
{ {
char *p; const char *p;
char *end_p = argv[2]; const char *end_p = argv[2];
/* Find the beginning of the "start"th word. */ /* Find the beginning of the "start"th word. */
while (((p = find_next_token (&end_p, 0)) != 0) && --start) while (((p = find_next_token (&end_p, 0)) != 0) && --start)
@ -816,7 +820,7 @@ func_wordlist (char *o, char **argv, const char *funcname UNUSED)
return o; return o;
} }
static char* static char *
func_findstring (char *o, char **argv, const char *funcname UNUSED) func_findstring (char *o, char **argv, const char *funcname UNUSED)
{ {
/* Find the first occurrence of the first string in the second. */ /* Find the first occurrence of the first string in the second. */
@ -832,13 +836,13 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED)
/* expand only the first two. */ /* expand only the first two. */
char *varname = expand_argument (argv[0], NULL); char *varname = expand_argument (argv[0], NULL);
char *list = expand_argument (argv[1], NULL); char *list = expand_argument (argv[1], NULL);
char *body = argv[2]; const char *body = argv[2];
int doneany = 0; int doneany = 0;
char *list_iterator = list; const char *list_iterator = list;
char *p; const char *p;
unsigned int len; unsigned int len;
register struct variable *var; struct variable *var;
push_new_variable_scope (); push_new_variable_scope ();
var = define_variable (varname, strlen (varname), "", o_automatic, 0); var = define_variable (varname, strlen (varname), "", o_automatic, 0);
@ -848,14 +852,8 @@ func_foreach (char *o, char **argv, const char *funcname UNUSED)
{ {
char *result = 0; char *result = 0;
{ free (var->value);
char save = p[len]; var->value = savestring (p, len);
p[len] = '\0';
free (var->value);
var->value = xstrdup ((char*) p);
p[len] = save;
}
result = allocated_variable_expand (body); result = allocated_variable_expand (body);
@ -928,8 +926,8 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
struct hash_table a_word_table; struct hash_table a_word_table;
int is_filter = streq (funcname, "filter"); int is_filter = streq (funcname, "filter");
char *pat_iterator = argv[0]; const char *pat_iterator = argv[0];
char *word_iterator = argv[1]; const char *word_iterator = argv[1];
int literals = 0; int literals = 0;
int words = 0; int words = 0;
int hashing = 0; int hashing = 0;
@ -985,7 +983,8 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
hashing = (literals >= 2 && (literals * words) >= 10); hashing = (literals >= 2 && (literals * words) >= 10);
if (hashing) if (hashing)
{ {
hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2, a_word_hash_cmp); hash_init (&a_word_table, words, a_word_hash_1, a_word_hash_2,
a_word_hash_cmp);
for (wp = wordhead; wp != 0; wp = wp->next) for (wp = wordhead; wp != 0; wp = wp->next)
{ {
struct a_word *owp = hash_insert (&a_word_table, wp); struct a_word *owp = hash_insert (&a_word_table, wp);
@ -1009,7 +1008,7 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
struct a_word a_word_key; struct a_word a_word_key;
a_word_key.str = pp->str; a_word_key.str = pp->str;
a_word_key.length = pp->length; a_word_key.length = pp->length;
wp = (struct a_word *) hash_find_item (&a_word_table, &a_word_key); wp = hash_find_item (&a_word_table, &a_word_key);
while (wp) while (wp)
{ {
wp->matched |= 1; wp->matched |= 1;
@ -1049,13 +1048,13 @@ func_filter_filterout (char *o, char **argv, const char *funcname)
static char * static char *
func_strip (char *o, char **argv, const char *funcname UNUSED) func_strip (char *o, char **argv, const char *funcname UNUSED)
{ {
char *p = argv[0]; const char *p = argv[0];
int doneany =0; int doneany = 0;
while (*p != '\0') while (*p != '\0')
{ {
int i=0; int i=0;
char *word_start=0; const char *word_start;
while (isspace ((unsigned char)*p)) while (isspace ((unsigned char)*p))
++p; ++p;
@ -1072,6 +1071,7 @@ func_strip (char *o, char **argv, const char *funcname UNUSED)
if (doneany) if (doneany)
/* Kill the last space. */ /* Kill the last space. */
--o; --o;
return o; return o;
} }
@ -1130,46 +1130,61 @@ func_error (char *o, char **argv, const char *funcname)
static char * static char *
func_sort (char *o, char **argv, const char *funcname UNUSED) func_sort (char *o, char **argv, const char *funcname UNUSED)
{ {
char **words = 0; const char *t;
int nwords = 0; char **words;
register int wordi = 0; int wordi;
/* Chop ARGV[0] into words and put them in WORDS. */
char *t = argv[0];
char *p; char *p;
unsigned int len; unsigned int len;
int i; int i;
/* Find the maximum number of words we'll have. */
t = argv[0];
wordi = 1;
while (*t != '\0')
{
char c = *(t++);
if (! isspace ((unsigned char)c))
continue;
++wordi;
while (isspace ((unsigned char)*t))
++t;
}
words = xmalloc (wordi * sizeof (char *));
/* Now assign pointers to each string in the array. */
t = argv[0];
wordi = 0;
while ((p = find_next_token (&t, &len)) != 0) while ((p = find_next_token (&t, &len)) != 0)
{ {
if (wordi >= nwords - 1) ++t;
{ p[len] = '\0';
nwords = (2 * nwords) + 5; words[wordi++] = p;
words = xrealloc (words, nwords * sizeof (char *));
}
words[wordi++] = savestring (p, len);
} }
if (!wordi) if (wordi)
return o;
/* Now sort the list of words. */
qsort (words, wordi, sizeof (char *), alpha_compare);
/* Now write the sorted list. */
for (i = 0; i < wordi; ++i)
{ {
len = strlen (words[i]); /* Now sort the list of words. */
if (i == wordi - 1 || strlen (words[i + 1]) != len qsort (words, wordi, sizeof (char *), alpha_compare);
|| strcmp (words[i], words[i + 1]))
/* Now write the sorted list, uniquified. */
for (i = 0; i < wordi; ++i)
{ {
o = variable_buffer_output (o, words[i], len); len = strlen (words[i]);
o = variable_buffer_output (o, " ", 1); if (i == wordi - 1 || strlen (words[i + 1]) != len
|| strcmp (words[i], words[i + 1]))
{
o = variable_buffer_output (o, words[i], len);
o = variable_buffer_output (o, " ", 1);
}
} }
free (words[i]);
/* Kill the last space. */
--o;
} }
/* Kill the last space. */
--o;
free (words); free (words);
@ -1215,11 +1230,9 @@ func_if (char *o, char **argv, const char *funcname UNUSED)
argv += 1 + !result; argv += 1 + !result;
if (argv[0]) if (*argv)
{ {
char *expansion; char *expansion = expand_argument (*argv, NULL);
expansion = expand_argument (argv[0], NULL);
o = variable_buffer_output (o, expansion, strlen (expansion)); o = variable_buffer_output (o, expansion, strlen (expansion));
@ -1336,7 +1349,6 @@ func_and (char *o, char **argv, const char *funcname UNUSED)
static char * static char *
func_wildcard (char *o, char **argv, const char *funcname UNUSED) func_wildcard (char *o, char **argv, const char *funcname UNUSED)
{ {
#ifdef _AMIGA #ifdef _AMIGA
o = wildcard_expansion (argv[0], o); o = wildcard_expansion (argv[0], o);
#else #else
@ -1576,22 +1588,20 @@ msdos_openpipe (int* pipedes, int *pidp, char *text)
static char * static char *
func_shell (char *o, char **argv, const char *funcname UNUSED) func_shell (char *o, char **argv, const char *funcname UNUSED)
{ {
char* batch_filename = NULL; char *batch_filename = NULL;
#ifdef __MSDOS__ #ifdef __MSDOS__
FILE *fpipe; FILE *fpipe;
#endif #endif
char **command_argv; char **command_argv;
char *error_prefix; const char *error_prefix;
char **envp; char **envp;
int pipedes[2]; int pipedes[2];
int pid; int pid;
#ifndef __MSDOS__ #ifndef __MSDOS__
/* Construct the argument list. */ /* Construct the argument list. */
command_argv = construct_command_argv (argv[0], command_argv = construct_command_argv (argv[0], NULL, NULL, &batch_filename);
(char **) NULL, (struct file *) 0,
&batch_filename);
if (command_argv == 0) if (command_argv == 0)
return o; return o;
#endif #endif
@ -1603,6 +1613,8 @@ func_shell (char *o, char **argv, const char *funcname UNUSED)
var was not explicitly exported, but just appeared in the var was not explicitly exported, but just appeared in the
calling environment. calling environment.
See Savannah bug #10593.
envp = target_environment (NILF); envp = target_environment (NILF);
*/ */
@ -1611,35 +1623,31 @@ func_shell (char *o, char **argv, const char *funcname UNUSED)
/* For error messages. */ /* For error messages. */
if (reading_file && reading_file->filenm) if (reading_file && reading_file->filenm)
{ {
error_prefix = alloca (strlen (reading_file->filenm)+11+4); char *p = alloca (strlen (reading_file->filenm)+11+4);
sprintf (error_prefix, sprintf (p, "%s:%lu: ", reading_file->filenm, reading_file->lineno);
"%s:%lu: ", reading_file->filenm, reading_file->lineno); error_prefix = p;
} }
else else
error_prefix = ""; error_prefix = "";
#ifdef WINDOWS32 #if defined(__MSDOS__)
windows32_openpipe (pipedes, &pid, command_argv, envp);
if (pipedes[0] < 0) {
/* open of the pipe failed, mark as failed execution */
shell_function_completed = -1;
return o;
} else
#elif defined(__MSDOS__)
fpipe = msdos_openpipe (pipedes, &pid, argv[0]); fpipe = msdos_openpipe (pipedes, &pid, argv[0]);
if (pipedes[0] < 0) if (pipedes[0] < 0)
{ {
perror_with_name (error_prefix, "pipe"); perror_with_name (error_prefix, "pipe");
return o; return o;
} }
#elif defined(WINDOWS32)
windows32_openpipe (pipedes, &pid, command_argv, envp);
if (pipedes[0] < 0)
{
/* open of the pipe failed, mark as failed execution */
shell_function_completed = -1;
return o;
}
else
#else #else
if (pipe (pipedes) < 0) if (pipe (pipedes) < 0)
{ {
perror_with_name (error_prefix, "pipe"); perror_with_name (error_prefix, "pipe");
@ -1647,7 +1655,6 @@ func_shell (char *o, char **argv, const char *funcname UNUSED)
} }
# ifdef __EMX__ # ifdef __EMX__
/* close some handles that are unnecessary for the child process */ /* close some handles that are unnecessary for the child process */
CLOSE_ON_EXEC(pipedes[1]); CLOSE_ON_EXEC(pipedes[1]);
CLOSE_ON_EXEC(pipedes[0]); CLOSE_ON_EXEC(pipedes[0]);
@ -1655,18 +1662,14 @@ func_shell (char *o, char **argv, const char *funcname UNUSED)
pid = child_execute_job (0, pipedes[1], command_argv, envp); pid = child_execute_job (0, pipedes[1], command_argv, envp);
if (pid < 0) if (pid < 0)
perror_with_name (error_prefix, "spawn"); perror_with_name (error_prefix, "spawn");
# else /* ! __EMX__ */ # else /* ! __EMX__ */
pid = vfork (); pid = vfork ();
if (pid < 0) if (pid < 0)
perror_with_name (error_prefix, "fork"); perror_with_name (error_prefix, "fork");
else if (pid == 0) else if (pid == 0)
child_execute_job (0, pipedes[1], command_argv, envp); child_execute_job (0, pipedes[1], command_argv, envp);
else else
# endif # endif
#endif #endif
{ {
/* We are the parent. */ /* We are the parent. */
@ -1863,7 +1866,7 @@ func_eq (char *o, char **argv, char *funcname)
static char * static char *
func_not (char *o, char **argv, char *funcname) func_not (char *o, char **argv, char *funcname)
{ {
char *s = argv[0]; const char *s = argv[0];
int result = 0; int result = 0;
while (isspace ((unsigned char)*s)) while (isspace ((unsigned char)*s))
s++; s++;
@ -1956,8 +1959,8 @@ static char *
func_realpath (char *o, char **argv, const char *funcname UNUSED) func_realpath (char *o, char **argv, const char *funcname UNUSED)
{ {
/* Expand the argument. */ /* Expand the argument. */
char *p = argv[0]; const char *p = argv[0];
char *path = 0; const char *path = 0;
int doneany = 0; int doneany = 0;
unsigned int len = 0; unsigned int len = 0;
PATH_VAR (in); PATH_VAR (in);
@ -1970,14 +1973,13 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED)
strncpy (in, path, len); strncpy (in, path, len);
in[len] = '\0'; in[len] = '\0';
if if (
(
#ifdef HAVE_REALPATH #ifdef HAVE_REALPATH
realpath (in, out) realpath (in, out)
#else #else
abspath (in, out) abspath (in, out)
#endif #endif
) )
{ {
o = variable_buffer_output (o, out, strlen (out)); o = variable_buffer_output (o, out, strlen (out));
o = variable_buffer_output (o, " ", 1); o = variable_buffer_output (o, " ", 1);
@ -1990,15 +1992,15 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED)
if (doneany) if (doneany)
--o; --o;
return o; return o;
} }
static char * static char *
func_abspath (char *o, char **argv, const char *funcname UNUSED) func_abspath (char *o, char **argv, const char *funcname UNUSED)
{ {
/* Expand the argument. */ /* Expand the argument. */
char *p = argv[0]; const char *p = argv[0];
char *path = 0; const char *path = 0;
int doneany = 0; int doneany = 0;
unsigned int len = 0; unsigned int len = 0;
PATH_VAR (in); PATH_VAR (in);
@ -2024,7 +2026,7 @@ func_abspath (char *o, char **argv, const char *funcname UNUSED)
if (doneany) if (doneany)
--o; --o;
return o; return o;
} }
/* Lookup table for builtin functions. /* Lookup table for builtin functions.
@ -2268,13 +2270,11 @@ func_call (char *o, char **argv, const char *funcname UNUSED)
/* Are we invoking a builtin function? */ /* Are we invoking a builtin function? */
entry_p = lookup_function (fname); entry_p = lookup_function (fname);
if (entry_p) if (entry_p)
{ {
/* How many arguments do we have? */ /* How many arguments do we have? */
for (i=0; argv[i+1]; ++i) for (i=0; argv[i+1]; ++i)
; ;
return expand_builtin_function (o, i, argv+1, entry_p); return expand_builtin_function (o, i, argv+1, entry_p);
} }

View File

@ -68,9 +68,9 @@ try_implicit_rule (struct file *file, unsigned int depth)
struct idep struct idep
{ {
struct idep *next; /* struct dep -compatible interface */ struct idep *next; /* struct dep -compatible interface */
char *name; /* name of the prerequisite */ const char *name; /* name of the prerequisite */
struct file *intermediate_file; /* intermediate file, 0 otherwise */ struct file *intermediate_file; /* intermediate file, 0 otherwise */
char *intermediate_pattern; /* pattern for intermediate file */ const char *intermediate_pattern; /* pattern for intermediate file */
unsigned char had_stem; /* had % substituted with stem */ unsigned char had_stem; /* had % substituted with stem */
unsigned char ignore_mtime; /* ignore_mtime flag */ unsigned char ignore_mtime; /* ignore_mtime flag */
}; };
@ -83,18 +83,6 @@ free_idep_chain (struct idep *p)
for (; p != 0; p = n) for (; p != 0; p = n)
{ {
n = p->next; n = p->next;
if (p->name)
{
struct file *f = p->intermediate_file;
if (f != 0
&& (f->stem < f->name || f->stem > f->name + strlen (f->name)))
free (f->stem);
free (p->name);
}
free (p); free (p);
} }
} }
@ -105,9 +93,9 @@ free_idep_chain (struct idep *p)
length of the word. */ length of the word. */
static char * static char *
get_next_word (char *buffer, unsigned int *length) get_next_word (const char *buffer, unsigned int *length)
{ {
char *p = buffer, *beg; const char *p = buffer, *beg;
char c; char c;
/* Skip any leading whitespace. */ /* Skip any leading whitespace. */
@ -178,7 +166,7 @@ get_next_word (char *buffer, unsigned int *length)
if (length) if (length)
*length = p - beg; *length = p - beg;
return beg; return (char *)beg;
} }
/* Search the pattern rules for a rule with an existing dependency to make /* Search the pattern rules for a rule with an existing dependency to make
@ -200,7 +188,7 @@ pattern_search (struct file *file, int archive,
unsigned int depth, unsigned int recursions) unsigned int depth, unsigned int recursions)
{ {
/* Filename we are searching for a rule for. */ /* Filename we are searching for a rule for. */
char *filename = archive ? strchr (file->name, '(') : file->name; const char *filename = archive ? strchr (file->name, '(') : file->name;
/* Length of FILENAME. */ /* Length of FILENAME. */
unsigned int namelen = strlen (filename); unsigned int namelen = strlen (filename);
@ -225,7 +213,7 @@ pattern_search (struct file *file, int archive,
char *depname = alloca (namelen + max_pattern_dep_length); char *depname = alloca (namelen + max_pattern_dep_length);
/* The start and length of the stem of FILENAME for the current rule. */ /* The start and length of the stem of FILENAME for the current rule. */
char *stem = 0; const char *stem = 0;
unsigned int stemlen = 0; unsigned int stemlen = 0;
unsigned int fullstemlen = 0; unsigned int fullstemlen = 0;
@ -258,8 +246,6 @@ pattern_search (struct file *file, int archive,
struct rule *rule; struct rule *rule;
struct dep *dep, *expl_d; struct dep *dep, *expl_d;
char *p, *vname;
struct idep *d; struct idep *d;
struct idep **id_ptr; struct idep **id_ptr;
struct dep **d_ptr; struct dep **d_ptr;
@ -318,10 +304,10 @@ pattern_search (struct file *file, int archive,
continue; continue;
} }
for (ti = 0; rule->targets[ti] != 0; ++ti) for (ti = 0; ti < rule->num; ++ti)
{ {
char *target = rule->targets[ti]; const char *target = rule->targets[ti];
char *suffix = rule->suffixes[ti]; const char *suffix = rule->suffixes[ti];
int check_lastslash; int check_lastslash;
/* Rules that can match any filename and are not terminal /* Rules that can match any filename and are not terminal
@ -416,11 +402,12 @@ pattern_search (struct file *file, int archive,
if (!tryrules[ri]->terminal) if (!tryrules[ri]->terminal)
{ {
unsigned int j; unsigned int j;
for (j = 0; tryrules[ri]->targets[j] != 0; ++j) for (j = 0; j < tryrules[ri]->num; ++j)
if (tryrules[ri]->targets[j][1] == '\0') if (tryrules[ri]->targets[j][1] == '\0')
break; {
if (tryrules[ri]->targets[j] != 0) tryrules[ri] = 0;
tryrules[ri] = 0; break;
}
} }
/* We are going to do second expansion so initialize file variables /* We are going to do second expansion so initialize file variables
@ -486,6 +473,7 @@ pattern_search (struct file *file, int archive,
for (dep = rule->deps; dep != 0; dep = dep->next) for (dep = rule->deps; dep != 0; dep = dep->next)
{ {
unsigned int len; unsigned int len;
char *p;
char *p2; char *p2;
unsigned int order_only = 0; /* Set if '|' was seen. */ unsigned int order_only = 0; /* Set if '|' was seen. */
@ -614,14 +602,10 @@ pattern_search (struct file *file, int archive,
if (add_dir) if (add_dir)
{ {
char *n = d->name; char *n = alloca (strlen (d->name) + l + 1);
memcpy (n, filename, l);
d->name = xmalloc (strlen (n) + l + 1); memcpy (n+l, d->name, strlen (d->name) + 1);
d->name = strcache_add (n);
memcpy (d->name, filename, l);
memcpy (d->name + l, n, strlen (n) + 1);
free (n);
} }
if (had_stem) if (had_stem)
@ -653,7 +637,7 @@ pattern_search (struct file *file, int archive,
for (d = deps; d != 0; d = d->next) for (d = deps; d != 0; d = d->next)
{ {
char *name = d->name; const char *name = d->name;
if (file_impossible_p (name)) if (file_impossible_p (name))
{ {
@ -701,17 +685,16 @@ pattern_search (struct file *file, int archive,
/* This code, given FILENAME = "lib/foo.o", dependency name /* This code, given FILENAME = "lib/foo.o", dependency name
"lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */
vname = name; {
if (vpath_search (&vname, (FILE_TIMESTAMP *) 0)) const char *vname = vpath_search (name, 0);
{ if (vname)
DBS (DB_IMPLICIT, {
(_("Found prerequisite `%s' as VPATH `%s'\n"), DBS (DB_IMPLICIT,
name, (_("Found prerequisite `%s' as VPATH `%s'\n"),
vname)); name, vname));
continue;
free (vname); }
continue; }
}
/* We could not find the file in any place we should look. Try /* We could not find the file in any place we should look. Try
@ -734,10 +717,9 @@ pattern_search (struct file *file, int archive,
depth + 1, depth + 1,
recursions + 1)) recursions + 1))
{ {
d->intermediate_file = intermediate_file;
d->intermediate_pattern = intermediate_file->name; d->intermediate_pattern = intermediate_file->name;
intermediate_file->name = strcache_add (name);
intermediate_file->name = xstrdup (name); d->intermediate_file = intermediate_file;
intermediate_file = 0; intermediate_file = 0;
continue; continue;
@ -819,7 +801,7 @@ pattern_search (struct file *file, int archive,
for (d = deps; d != 0; d = d->next) for (d = deps; d != 0; d = d->next)
{ {
register char *s; const char *s;
if (d->intermediate_file != 0) if (d->intermediate_file != 0)
{ {
@ -839,7 +821,7 @@ pattern_search (struct file *file, int archive,
if (f != 0) if (f != 0)
f->precious = 1; f->precious = 1;
else else
f = enter_file (imf->name); f = enter_file (strcache_add (imf->name));
f->deps = imf->deps; f->deps = imf->deps;
f->cmds = imf->cmds; f->cmds = imf->cmds;
@ -859,9 +841,6 @@ pattern_search (struct file *file, int archive,
for (dep = f->deps; dep != 0; dep = dep->next) for (dep = f->deps; dep != 0; dep = dep->next)
{ {
dep->file = enter_file (dep->name); dep->file = enter_file (dep->name);
/* enter_file uses dep->name _if_ we created a new file. */
if (dep->name != dep->file->name)
free (dep->name);
dep->name = 0; dep->name = 0;
dep->file->tried_implicit |= dep->changed; dep->file->tried_implicit |= dep->changed;
} }
@ -875,17 +854,10 @@ pattern_search (struct file *file, int archive,
{ {
dep->file = lookup_file (s); dep->file = lookup_file (s);
if (dep->file == 0) if (dep->file == 0)
/* enter_file consumes S's storage. */
dep->file = enter_file (s); dep->file = enter_file (s);
else
/* A copy of S is already allocated in DEP->file->name.
So we can free S. */
free (s);
} }
else else
{ dep->name = s;
dep->name = s;
}
if (d->intermediate_file == 0 && tryrules[foundrule]->terminal) if (d->intermediate_file == 0 && tryrules[foundrule]->terminal)
{ {
@ -910,20 +882,22 @@ pattern_search (struct file *file, int archive,
{ {
/* Always allocate new storage, since STEM might be /* Always allocate new storage, since STEM might be
on the stack for an intermediate file. */ on the stack for an intermediate file. */
file->stem = savestring (stem, stemlen); file->stem = strcache_add_len (stem, stemlen);
fullstemlen = stemlen; fullstemlen = stemlen;
} }
else else
{ {
int dirlen = (lastslash + 1) - filename; int dirlen = (lastslash + 1) - filename;
char *sp;
/* We want to prepend the directory from /* We want to prepend the directory from
the original FILENAME onto the stem. */ the original FILENAME onto the stem. */
fullstemlen = dirlen + stemlen; fullstemlen = dirlen + stemlen;
file->stem = xmalloc (fullstemlen + 1); sp = alloca (fullstemlen + 1);
memcpy (file->stem, filename, dirlen); memcpy (sp, filename, dirlen);
memcpy (file->stem + dirlen, stem, stemlen); memcpy (sp + dirlen, stem, stemlen);
file->stem[fullstemlen] = '\0'; sp[fullstemlen] = '\0';
file->stem = strcache_add (sp);
} }
file->cmds = rule->cmds; file->cmds = rule->cmds;
@ -939,15 +913,15 @@ pattern_search (struct file *file, int archive,
/* If this rule builds other targets, too, put the others into FILE's /* If this rule builds other targets, too, put the others into FILE's
`also_make' member. */ `also_make' member. */
if (rule->targets[1] != 0) if (rule->num > 1)
for (ri = 0; rule->targets[ri] != 0; ++ri) for (ri = 0; ri < rule->num; ++ri)
if (ri != matches[foundrule]) if (ri != matches[foundrule])
{ {
char *p = alloca (rule->lens[ri] + fullstemlen + 1);
struct file *f; struct file *f;
struct dep *new = alloc_dep (); struct dep *new = alloc_dep ();
/* GKM FIMXE: handle '|' here too */ /* GKM FIMXE: handle '|' here too */
new->name = p = xmalloc (rule->lens[ri] + fullstemlen + 1);
memcpy (p, rule->targets[ri], memcpy (p, rule->targets[ri],
rule->suffixes[ri] - rule->targets[ri] - 1); rule->suffixes[ri] - rule->targets[ri] - 1);
p += rule->suffixes[ri] - rule->targets[ri] - 1; p += rule->suffixes[ri] - rule->targets[ri] - 1;
@ -955,6 +929,7 @@ pattern_search (struct file *file, int archive,
p += fullstemlen; p += fullstemlen;
memcpy (p, rule->suffixes[ri], memcpy (p, rule->suffixes[ri],
rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1);
new->name = strcache_add (p);
new->file = enter_file (new->name); new->file = enter_file (new->name);
new->next = file->also_make; new->next = file->also_make;

4
job.c
View File

@ -374,8 +374,8 @@ _is_unixy_shell (const char *path)
Append "(ignored)" if IGNORED is nonzero. */ Append "(ignored)" if IGNORED is nonzero. */
static void static void
child_error (char *target_name, int exit_code, int exit_sig, int coredump, child_error (const char *target_name,
int ignored) int exit_code, int exit_sig, int coredump, int ignored)
{ {
if (ignored && silent_flag) if (ignored && silent_flag)
return; return;

177
main.c
View File

@ -67,6 +67,8 @@ void print_rule_data_base (void);
void print_file_data_base (void); void print_file_data_base (void);
void print_vpath_data_base (void); void print_vpath_data_base (void);
void verify_file_data_base (void);
#if defined HAVE_WAITPID || defined HAVE_WAIT3 #if defined HAVE_WAITPID || defined HAVE_WAIT3
# define HAVE_WAIT_NOHANG # define HAVE_WAIT_NOHANG
#endif #endif
@ -87,7 +89,7 @@ static void print_version (void);
static void decode_switches (int argc, char **argv, int env); static void decode_switches (int argc, char **argv, int env);
static void decode_env_switches (char *envar, unsigned int len); static void decode_env_switches (char *envar, unsigned int len);
static void define_makeflags (int all, int makefile); static void define_makeflags (int all, int makefile);
static char *quote_for_env (char *out, char *in); static char *quote_for_env (char *out, const char *in);
static void initialize_global_hash_tables (void); static void initialize_global_hash_tables (void);
@ -102,6 +104,7 @@ struct command_switch
flag, /* Turn int flag on. */ flag, /* Turn int flag on. */
flag_off, /* Turn int flag off. */ flag_off, /* Turn int flag off. */
string, /* One string per switch. */ string, /* One string per switch. */
filename, /* A string containing a file name. */
positive_int, /* A positive integer. */ positive_int, /* A positive integer. */
floating, /* A floating-point number (double). */ floating, /* A floating-point number (double). */
ignore /* Ignored. */ ignore /* Ignored. */
@ -128,7 +131,7 @@ struct command_switch
struct stringlist struct stringlist
{ {
char **list; /* Nil-terminated list of strings. */ const char **list; /* Nil-terminated list of strings. */
unsigned int idx; /* Index into above. */ unsigned int idx; /* Index into above. */
unsigned int max; /* Number of pointers allocated. */ unsigned int max; /* Number of pointers allocated. */
}; };
@ -371,17 +374,17 @@ static const struct command_switch switches[] =
{ {
{ 'b', ignore, 0, 0, 0, 0, 0, 0, 0 }, { 'b', ignore, 0, 0, 0, 0, 0, 0, 0 },
{ 'B', flag, &always_make_set, 1, 1, 0, 0, 0, "always-make" }, { 'B', flag, &always_make_set, 1, 1, 0, 0, 0, "always-make" },
{ 'C', string, &directories, 0, 0, 0, 0, 0, "directory" }, { 'C', filename, &directories, 0, 0, 0, 0, 0, "directory" },
{ 'd', flag, &debug_flag, 1, 1, 0, 0, 0, 0 }, { 'd', flag, &debug_flag, 1, 1, 0, 0, 0, 0 },
{ CHAR_MAX+1, string, &db_flags, 1, 1, 0, "basic", 0, "debug" }, { CHAR_MAX+1, string, &db_flags, 1, 1, 0, "basic", 0, "debug" },
#ifdef WINDOWS32 #ifdef WINDOWS32
{ 'D', flag, &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" }, { 'D', flag, &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" },
#endif #endif
{ 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", }, { 'e', flag, &env_overrides, 1, 1, 0, 0, 0, "environment-overrides", },
{ 'f', string, &makefiles, 0, 0, 0, 0, 0, "file" }, { 'f', filename, &makefiles, 0, 0, 0, 0, 0, "file" },
{ 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" }, { 'h', flag, &print_usage_flag, 0, 0, 0, 0, 0, "help" },
{ 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" }, { 'i', flag, &ignore_errors_flag, 1, 1, 0, 0, 0, "ignore-errors" },
{ 'I', string, &include_directories, 1, 1, 0, 0, 0, { 'I', filename, &include_directories, 1, 1, 0, 0, 0,
"include-dir" }, "include-dir" },
{ 'j', positive_int, &job_slots, 1, 1, 0, &inf_jobs, &default_job_slots, { 'j', positive_int, &job_slots, 1, 1, 0, &inf_jobs, &default_job_slots,
"jobs" }, "jobs" },
@ -398,7 +401,7 @@ static const struct command_switch switches[] =
{ 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, "check-symlink-times" }, { 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, "check-symlink-times" },
{ 'm', ignore, 0, 0, 0, 0, 0, 0, 0 }, { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 },
{ 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" }, { 'n', flag, &just_print_flag, 1, 1, 1, 0, 0, "just-print" },
{ 'o', string, &old_files, 0, 0, 0, 0, 0, "old-file" }, { 'o', filename, &old_files, 0, 0, 0, 0, 0, "old-file" },
{ 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" }, { 'p', flag, &print_data_base_flag, 1, 1, 0, 0, 0, "print-data-base" },
{ 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" }, { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" },
{ 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" }, { 'r', flag, &no_builtin_rules_flag, 1, 1, 0, 0, 0, "no-builtin-rules" },
@ -414,7 +417,7 @@ static const struct command_switch switches[] =
{ 'w', flag, &print_directory_flag, 1, 1, 0, 0, 0, "print-directory" }, { 'w', flag, &print_directory_flag, 1, 1, 0, 0, 0, "print-directory" },
{ CHAR_MAX+4, flag, &inhibit_print_directory_flag, 1, 1, 0, 0, 0, { CHAR_MAX+4, flag, &inhibit_print_directory_flag, 1, 1, 0, 0, 0,
"no-print-directory" }, "no-print-directory" },
{ 'W', string, &new_files, 0, 0, 0, 0, 0, "what-if" }, { 'W', filename, &new_files, 0, 0, 0, 0, 0, "what-if" },
{ CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0, { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0,
"warn-undefined-variables" }, "warn-undefined-variables" },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0 } { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
@ -543,17 +546,20 @@ initialize_global_hash_tables (void)
hash_init_function_table (); hash_init_function_table ();
} }
static struct file * static const char *
enter_command_line_file (char *name) expand_command_line_file (char *name)
{ {
const char *cp;
char *expanded = 0;
if (name[0] == '\0') if (name[0] == '\0')
fatal (NILF, _("empty string invalid as file name")); fatal (NILF, _("empty string invalid as file name"));
if (name[0] == '~') if (name[0] == '~')
{ {
char *expanded = tilde_expand (name); expanded = tilde_expand (name);
if (expanded != 0) if (expanded != 0)
name = expanded; /* Memory leak; I don't care. */ name = expanded;
} }
/* This is also done in parse_file_seq, so this is redundant /* This is also done in parse_file_seq, so this is redundant
@ -577,7 +583,12 @@ enter_command_line_file (char *name)
name[2] = '\0'; name[2] = '\0';
} }
return enter_file (xstrdup (name)); cp = strcache_add (name);
if (expanded)
free (expanded);
return cp;
} }
/* Toggle -d on receipt of SIGUSR1. */ /* Toggle -d on receipt of SIGUSR1. */
@ -593,7 +604,7 @@ debug_signal_handler (int sig UNUSED)
static void static void
decode_debug_flags (void) decode_debug_flags (void)
{ {
char **pp; const char **pp;
if (debug_flag) if (debug_flag)
db_level = DB_ALL; db_level = DB_ALL;
@ -728,9 +739,10 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo )
*/ */
int int
find_and_set_default_shell (char *token) find_and_set_default_shell (const char *token)
{ {
int sh_found = 0; int sh_found = 0;
char *atoken = 0;
char *search_token; char *search_token;
char *tokend; char *tokend;
PATH_VAR(sh_path); PATH_VAR(sh_path);
@ -739,8 +751,7 @@ find_and_set_default_shell (char *token)
if (!token) if (!token)
search_token = default_shell; search_token = default_shell;
else else
search_token = token; atoken = search_token = xstrdup (token);
/* If the user explicitly requests the DOS cmd shell, obey that request. /* If the user explicitly requests the DOS cmd shell, obey that request.
However, make sure that's what they really want by requiring the value However, make sure that's what they really want by requiring the value
@ -766,10 +777,10 @@ find_and_set_default_shell (char *token)
(token == NULL || !strcmp (search_token, default_shell))) { (token == NULL || !strcmp (search_token, default_shell))) {
/* no new information, path already set or known */ /* no new information, path already set or known */
sh_found = 1; sh_found = 1;
} else if (file_exists_p(search_token)) { } else if (file_exists_p (search_token)) {
/* search token path was found */ /* search token path was found */
sprintf(sh_path, "%s", search_token); sprintf (sh_path, "%s", search_token);
default_shell = xstrdup(w32ify(sh_path,0)); default_shell = xstrdup (w32ify (sh_path, 0));
DB (DB_VERBOSE, DB (DB_VERBOSE,
(_("find_and_set_shell setting default_shell = %s\n"), default_shell)); (_("find_and_set_shell setting default_shell = %s\n"), default_shell));
sh_found = 1; sh_found = 1;
@ -782,31 +793,31 @@ find_and_set_default_shell (char *token)
char *ep; char *ep;
p = v->value; p = v->value;
ep = strchr(p, PATH_SEPARATOR_CHAR); ep = strchr (p, PATH_SEPARATOR_CHAR);
while (ep && *ep) { while (ep && *ep) {
*ep = '\0'; *ep = '\0';
if (dir_file_exists_p(p, search_token)) { if (dir_file_exists_p (p, search_token)) {
sprintf(sh_path, "%s/%s", p, search_token); sprintf (sh_path, "%s/%s", p, search_token);
default_shell = xstrdup(w32ify(sh_path,0)); default_shell = xstrdup (w32ify (sh_path, 0));
sh_found = 1; sh_found = 1;
*ep = PATH_SEPARATOR_CHAR; *ep = PATH_SEPARATOR_CHAR;
/* terminate loop */ /* terminate loop */
p += strlen(p); p += strlen (p);
} else { } else {
*ep = PATH_SEPARATOR_CHAR; *ep = PATH_SEPARATOR_CHAR;
p = ++ep; p = ++ep;
} }
ep = strchr(p, PATH_SEPARATOR_CHAR); ep = strchr (p, PATH_SEPARATOR_CHAR);
} }
/* be sure to check last element of Path */ /* be sure to check last element of Path */
if (p && *p && dir_file_exists_p(p, search_token)) { if (p && *p && dir_file_exists_p (p, search_token)) {
sprintf(sh_path, "%s/%s", p, search_token); sprintf (sh_path, "%s/%s", p, search_token);
default_shell = xstrdup(w32ify(sh_path,0)); default_shell = xstrdup (w32ify (sh_path, 0));
sh_found = 1; sh_found = 1;
} }
@ -819,7 +830,7 @@ find_and_set_default_shell (char *token)
/* naive test */ /* naive test */
if (!unixy_shell && sh_found && if (!unixy_shell && sh_found &&
(strstr(default_shell, "sh") || strstr(default_shell, "SH"))) { (strstr (default_shell, "sh") || strstr (default_shell, "SH"))) {
unixy_shell = 1; unixy_shell = 1;
batch_mode_shell = 0; batch_mode_shell = 0;
} }
@ -828,6 +839,9 @@ find_and_set_default_shell (char *token)
batch_mode_shell = 1; batch_mode_shell = 1;
#endif #endif
if (atoken)
free (atoken);
return (sh_found); return (sh_found);
} }
#endif /* WINDOWS32 */ #endif /* WINDOWS32 */
@ -1228,7 +1242,7 @@ main (int argc, char **argv, char **envp)
decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS"));
#if 0 #if 0
/* People write things like: /* People write things like:
MFLAGS="CC=gcc -pipe" "CFLAGS=-g" MFLAGS="CC=gcc -pipe" "CFLAGS=-g"
and we set the -p, -i and -e switches. Doesn't seem quite right. */ and we set the -p, -i and -e switches. Doesn't seem quite right. */
decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS"));
#endif #endif
@ -1296,7 +1310,7 @@ main (int argc, char **argv, char **envp)
&& (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0)
# endif # endif
) )
argv[0] = concat (current_directory, "/", argv[0]); argv[0] = xstrdup (concat (current_directory, "/", argv[0]));
#else /* !__MSDOS__ */ #else /* !__MSDOS__ */
if (current_directory[0] != '\0' if (current_directory[0] != '\0'
&& argv[0] != 0 && argv[0][0] != '/' && strchr (argv[0], '/') != 0 && argv[0] != 0 && argv[0][0] != '/' && strchr (argv[0], '/') != 0
@ -1305,7 +1319,7 @@ main (int argc, char **argv, char **envp)
&& strchr (argv[0], '\\') != 0 && strchr (argv[0], '\\') != 0
#endif #endif
) )
argv[0] = concat (current_directory, "/", argv[0]); argv[0] = xstrdup (concat (current_directory, "/", argv[0]));
#endif /* !__MSDOS__ */ #endif /* !__MSDOS__ */
#endif /* WINDOWS32 */ #endif /* WINDOWS32 */
#endif #endif
@ -1370,14 +1384,7 @@ main (int argc, char **argv, char **envp)
unsigned int i; unsigned int i;
for (i = 0; directories->list[i] != 0; ++i) for (i = 0; directories->list[i] != 0; ++i)
{ {
char *dir = directories->list[i]; const char *dir = directories->list[i];
char *expanded = 0;
if (dir[0] == '~')
{
expanded = tilde_expand (dir);
if (expanded != 0)
dir = expanded;
}
#ifdef WINDOWS32 #ifdef WINDOWS32
/* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/'
But allow -C/ just in case someone wants that. */ But allow -C/ just in case someone wants that. */
@ -1390,8 +1397,6 @@ main (int argc, char **argv, char **envp)
#endif #endif
if (chdir (dir) < 0) if (chdir (dir) < 0)
pfatal_with_name (dir); pfatal_with_name (dir);
if (expanded)
free (expanded);
} }
} }
@ -1524,11 +1529,11 @@ main (int argc, char **argv, char **envp)
/* Replace the name that read_all_makefiles will /* Replace the name that read_all_makefiles will
see with the name of the temporary file. */ see with the name of the temporary file. */
makefiles->list[i] = xstrdup (stdin_nm); makefiles->list[i] = strcache_add (stdin_nm);
/* Make sure the temporary file will not be remade. */ /* Make sure the temporary file will not be remade. */
{ {
struct file *f = enter_file (stdin_nm); struct file *f = enter_file (strcache_add (stdin_nm));
f->updated = 1; f->updated = 1;
f->update_status = 0; f->update_status = 0;
f->command_state = cs_finished; f->command_state = cs_finished;
@ -1595,7 +1600,7 @@ main (int argc, char **argv, char **envp)
/* Define the default variables. */ /* Define the default variables. */
define_default_variables (); define_default_variables ();
default_file = enter_file (".DEFAULT"); default_file = enter_file (strcache_add (".DEFAULT"));
{ {
struct variable *v = define_variable (".DEFAULT_GOAL", 13, "", o_file, 0); struct variable *v = define_variable (".DEFAULT_GOAL", 13, "", o_file, 0);
@ -1660,7 +1665,7 @@ main (int argc, char **argv, char **envp)
if (jobserver_fds) if (jobserver_fds)
{ {
char *cp; const char *cp;
unsigned int ui; unsigned int ui;
for (ui=1; ui < jobserver_fds->idx; ++ui) for (ui=1; ui < jobserver_fds->idx; ++ui)
@ -1719,6 +1724,7 @@ main (int argc, char **argv, char **envp)
if (job_slots > 1) if (job_slots > 1)
{ {
char *cp;
char c = '+'; char c = '+';
if (pipe (job_fds) < 0 || (job_rfd = dup (job_fds[0])) < 0) if (pipe (job_fds) < 0 || (job_rfd = dup (job_fds[0])) < 0)
@ -1742,12 +1748,13 @@ main (int argc, char **argv, char **envp)
/* Fill in the jobserver_fds struct for our children. */ /* Fill in the jobserver_fds struct for our children. */
cp = xmalloc ((sizeof ("1024")*2)+1);
sprintf (cp, "%d,%d", job_fds[0], job_fds[1]);
jobserver_fds = (struct stringlist *) jobserver_fds = (struct stringlist *)
xmalloc (sizeof (struct stringlist)); xmalloc (sizeof (struct stringlist));
jobserver_fds->list = xmalloc (sizeof (char *)); jobserver_fds->list = xmalloc (sizeof (char *));
jobserver_fds->list[0] = xmalloc ((sizeof ("1024")*2)+1); jobserver_fds->list[0] = cp;
sprintf (jobserver_fds->list[0], "%d,%d", job_fds[0], job_fds[1]);
jobserver_fds->idx = 1; jobserver_fds->idx = 1;
jobserver_fds->max = 1; jobserver_fds->max = 1;
} }
@ -1798,10 +1805,10 @@ main (int argc, char **argv, char **envp)
if (old_files != 0) if (old_files != 0)
{ {
char **p; const char **p;
for (p = old_files->list; *p != 0; ++p) for (p = old_files->list; *p != 0; ++p)
{ {
struct file *f = enter_command_line_file (*p); struct file *f = enter_file (*p);
f->last_mtime = f->mtime_before_update = OLD_MTIME; f->last_mtime = f->mtime_before_update = OLD_MTIME;
f->updated = 1; f->updated = 1;
f->update_status = 0; f->update_status = 0;
@ -1811,10 +1818,10 @@ main (int argc, char **argv, char **envp)
if (!restarts && new_files != 0) if (!restarts && new_files != 0)
{ {
char **p; const char **p;
for (p = new_files->list; *p != 0; ++p) for (p = new_files->list; *p != 0; ++p)
{ {
struct file *f = enter_command_line_file (*p); struct file *f = enter_file (*p);
f->last_mtime = f->mtime_before_update = NEW_MTIME; f->last_mtime = f->mtime_before_update = NEW_MTIME;
} }
} }
@ -2000,9 +2007,10 @@ main (int argc, char **argv, char **envp)
{ {
char *p = &argv[i][2]; char *p = &argv[i][2];
if (*p == '\0') if (*p == '\0')
argv[++i] = makefiles->list[j]; /* This cast is OK since we never modify argv. */
argv[++i] = (char *) makefiles->list[j];
else else
argv[i] = concat ("-f", makefiles->list[j], ""); argv[i] = xstrdup (concat ("-f", makefiles->list[j], ""));
++j; ++j;
} }
} }
@ -2012,25 +2020,20 @@ main (int argc, char **argv, char **envp)
{ {
nargv = xmalloc ((nargc + 2) * sizeof (char *)); nargv = xmalloc ((nargc + 2) * sizeof (char *));
memcpy (nargv, argv, argc * sizeof (char *)); memcpy (nargv, argv, argc * sizeof (char *));
nargv[nargc++] = concat ("-o", stdin_nm, ""); nargv[nargc++] = xstrdup (concat ("-o", stdin_nm, ""));
nargv[nargc] = 0; nargv[nargc] = 0;
} }
if (directories != 0 && directories->idx > 0) if (directories != 0 && directories->idx > 0)
{ {
char bad; int bad = 1;
if (directory_before_chdir != 0) if (directory_before_chdir != 0)
{ {
if (chdir (directory_before_chdir) < 0) if (chdir (directory_before_chdir) < 0)
{
perror_with_name ("chdir", ""); perror_with_name ("chdir", "");
bad = 1;
}
else else
bad = 0; bad = 0;
} }
else
bad = 1;
if (bad) if (bad)
fatal (NILF, _("Couldn't change back to original directory.")); fatal (NILF, _("Couldn't change back to original directory."));
} }
@ -2142,10 +2145,10 @@ main (int argc, char **argv, char **envp)
/* If restarts is set we haven't set up -W files yet, so do that now. */ /* If restarts is set we haven't set up -W files yet, so do that now. */
if (restarts && new_files != 0) if (restarts && new_files != 0)
{ {
char **p; const char **p;
for (p = new_files->list; *p != 0; ++p) for (p = new_files->list; *p != 0; ++p)
{ {
struct file *f = enter_command_line_file (*p); struct file *f = enter_file (*p);
f->last_mtime = f->mtime_before_update = NEW_MTIME; f->last_mtime = f->mtime_before_update = NEW_MTIME;
} }
} }
@ -2184,7 +2187,7 @@ main (int argc, char **argv, char **envp)
if (ns->next != 0) if (ns->next != 0)
fatal (NILF, _(".DEFAULT_GOAL contains more than one target")); fatal (NILF, _(".DEFAULT_GOAL contains more than one target"));
default_goal_file = enter_file (ns->name); default_goal_file = enter_file (strcache_add (ns->name));
ns->name = 0; /* It was reused by enter_file(). */ ns->name = 0; /* It was reused by enter_file(). */
free_ns_chain (ns); free_ns_chain (ns);
@ -2287,6 +2290,7 @@ init_switches (void)
break; break;
case string: case string:
case filename:
case positive_int: case positive_int:
case floating: case floating:
if (short_option (switches[i].c)) if (short_option (switches[i].c))
@ -2342,7 +2346,7 @@ handle_non_switch_argument (char *arg, int env)
/* Not an option or variable definition; it must be a goal /* Not an option or variable definition; it must be a goal
target! Enter it as a file and add it to the dep chain of target! Enter it as a file and add it to the dep chain of
goals. */ goals. */
struct file *f = enter_command_line_file (arg); struct file *f = enter_file (strcache_add (expand_command_line_file (arg)));
f->cmd_target = 1; f->cmd_target = 1;
if (goals == 0) if (goals == 0)
@ -2361,7 +2365,7 @@ handle_non_switch_argument (char *arg, int env)
{ {
/* Add this target name to the MAKECMDGOALS variable. */ /* Add this target name to the MAKECMDGOALS variable. */
struct variable *gv; struct variable *gv;
char *value; const char *value;
gv = lookup_variable (STRING_SIZE_TUPLE ("MAKECMDGOALS")); gv = lookup_variable (STRING_SIZE_TUPLE ("MAKECMDGOALS"));
if (gv == 0) if (gv == 0)
@ -2370,13 +2374,15 @@ handle_non_switch_argument (char *arg, int env)
{ {
/* Paste the old and new values together */ /* Paste the old and new values together */
unsigned int oldlen, newlen; unsigned int oldlen, newlen;
char *vp;
oldlen = strlen (gv->value); oldlen = strlen (gv->value);
newlen = strlen (f->name); newlen = strlen (f->name);
value = alloca (oldlen + 1 + newlen + 1); vp = alloca (oldlen + 1 + newlen + 1);
memcpy (value, gv->value, oldlen); memcpy (vp, gv->value, oldlen);
value[oldlen] = ' '; vp[oldlen] = ' ';
memcpy (&value[oldlen + 1], f->name, newlen + 1); memcpy (&vp[oldlen + 1], f->name, newlen + 1);
value = vp;
} }
define_variable ("MAKECMDGOALS", 12, value, o_default, 0); define_variable ("MAKECMDGOALS", 12, value, o_default, 0);
} }
@ -2472,6 +2478,7 @@ decode_switches (int argc, char **argv, int env)
break; break;
case string: case string:
case filename:
if (!doit) if (!doit)
break; break;
@ -2500,7 +2507,10 @@ decode_switches (int argc, char **argv, int env)
sl->list = xrealloc (sl->list, sl->list = xrealloc (sl->list,
sl->max * sizeof (char *)); sl->max * sizeof (char *));
} }
sl->list[sl->idx++] = optarg; if (cs->type == filename)
sl->list[sl->idx++] = expand_command_line_file (optarg);
else
sl->list[sl->idx++] = optarg;
sl->list[sl->idx] = 0; sl->list[sl->idx] = 0;
break; break;
@ -2641,7 +2651,7 @@ decode_env_switches (char *envar, unsigned int len)
definition. Add a dash and pass it along to decode_switches. We definition. Add a dash and pass it along to decode_switches. We
need permanent storage for this in case decode_switches saves need permanent storage for this in case decode_switches saves
pointers into the value. */ pointers into the value. */
argv[1] = concat ("-", argv[1], ""); argv[1] = xstrdup (concat ("-", argv[1], ""));
/* Parse those words. */ /* Parse those words. */
decode_switches (argc, argv, 1); decode_switches (argc, argv, 1);
@ -2654,7 +2664,7 @@ decode_env_switches (char *envar, unsigned int len)
Allocating space for OUT twice the length of IN is always sufficient. */ Allocating space for OUT twice the length of IN is always sufficient. */
static char * static char *
quote_for_env (char *out, char *in) quote_for_env (char *out, const char *in)
{ {
while (*in != '\0') while (*in != '\0')
{ {
@ -2692,7 +2702,7 @@ define_makeflags (int all, int makefile)
{ {
struct flag *next; struct flag *next;
const struct command_switch *cs; const struct command_switch *cs;
char *arg; const char *arg;
}; };
struct flag *flags = 0; struct flag *flags = 0;
unsigned int flagslen = 0; unsigned int flagslen = 0;
@ -2716,9 +2726,6 @@ define_makeflags (int all, int makefile)
if (cs->toenv && (!makefile || !cs->no_makefile)) if (cs->toenv && (!makefile || !cs->no_makefile))
switch (cs->type) switch (cs->type)
{ {
default:
abort ();
case ignore: case ignore:
break; break;
@ -2775,21 +2782,25 @@ define_makeflags (int all, int makefile)
break; break;
#endif #endif
case filename:
case string: case string:
if (all) if (all)
{ {
struct stringlist *sl = *(struct stringlist **) cs->value_ptr; struct stringlist *sl = *(struct stringlist **) cs->value_ptr;
if (sl != 0) if (sl != 0)
{ {
/* Add the elements in reverse order, because /* Add the elements in reverse order, because all the flags
all the flags get reversed below; and the order get reversed below; and the order matters for some
matters for some switches (like -I). */ switches (like -I). */
register unsigned int i = sl->idx; unsigned int i = sl->idx;
while (i-- > 0) while (i-- > 0)
ADD_FLAG (sl->list[i], strlen (sl->list[i])); ADD_FLAG (sl->list[i], strlen (sl->list[i]));
} }
} }
break; break;
default:
abort ();
} }
flagslen += 4 + sizeof posixref; /* Four more for the possible " -- ". */ flagslen += 4 + sizeof posixref; /* Four more for the possible " -- ". */
@ -3073,6 +3084,8 @@ die (int status)
if (print_data_base_flag) if (print_data_base_flag)
print_data_base (); print_data_base ();
verify_file_data_base ();
clean_jobserver (status); clean_jobserver (status);
/* Try to move back to the original directory. This is essential on /* Try to move back to the original directory. This is essential on

View File

@ -226,7 +226,8 @@ po-check:
## ------------------------- ## ## ------------------------- ##
# This target creates the upload artifacts. # This target creates the upload artifacts.
# Sign it with my key. # Sign it with my key. If you don't have my key/passphrase then sorry,
# you're SOL! :)
GPG = gpg GPG = gpg
GPGFLAGS = -u 6338B6D4 GPGFLAGS = -u 6338B6D4
@ -234,21 +235,24 @@ GPGFLAGS = -u 6338B6D4
DIST_ARCHIVES_SIG = $(addsuffix .sig,$(DIST_ARCHIVES)) DIST_ARCHIVES_SIG = $(addsuffix .sig,$(DIST_ARCHIVES))
DIST_ARCHIVES_DIRECTIVE = $(addsuffix .directive.asc,$(DIST_ARCHIVES)) DIST_ARCHIVES_DIRECTIVE = $(addsuffix .directive.asc,$(DIST_ARCHIVES))
# A simple rule to test signing, etc.
.PHONY: distsign .PHONY: distsign
distsign: $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE) distsign: $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE)
$(DIST_ARCHIVES_DIRECTIVE): .directive.asc
cp $< $@
%.sig : % %.sig : %
@echo "Signing file '$<':" @echo "Signing file '$<':"
$(GPG) $(GPGFLAGS) -o $@ -b $< $(GPG) $(GPGFLAGS) -o "$@" -b "$<"
.directive.asc: %.directive.asc: %
@echo "Creating directive file '$@':" @echo "Creating directive file '$@':"
@echo 'directory: make' > .directive @( \
$(GPG) $(GPGFLAGS) -o $@ --clearsign .directive echo 'verstion: 1.1'; \
@rm -f .directive echo 'directory: make'; \
echo 'filename: $*'; \
echo 'comment: Official upload of GNU make version $(VERSION)'; \
) > "$*.directive"
$(GPG) $(GPGFLAGS) -o "$@" --clearsign "$*.directive"
@rm -f "$*.directive"
# Upload the artifacts # Upload the artifacts
@ -258,11 +262,11 @@ gnu-url = ftp-upload.gnu.org /incoming
UPLOADS = upload-alpha upload-ftp UPLOADS = upload-alpha upload-ftp
.PHONY: $(UPLOADS) .PHONY: $(UPLOADS)
$(UPLOADS): $(DIST_ARCHIVES) $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE) $(UPLOADS): $(DIST_ARCHIVES) $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE)
$(FTPPUT) $(gnu-url)/$(@:upload-%=%) $^ $(FTPPUT) "$(gnu-url)/$(@:upload-%=%)" $^
# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 # Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
# Free Software Foundation, Inc. # 2007 Free Software Foundation, Inc.
# This file is part of GNU Make. # This file is part of GNU Make.
# #
# GNU Make is free software; you can redistribute it and/or modify it under the # GNU Make is free software; you can redistribute it and/or modify it under the

15
make.h
View File

@ -334,8 +334,8 @@ int strcmpi (const char *,const char *);
void sync_Path_environment (void); void sync_Path_environment (void);
int kill (int pid, int sig); int kill (int pid, int sig);
char *end_of_token_w32 (char *s, char stopchar); char *end_of_token_w32 (const char *s, char stopchar);
int find_and_set_default_shell (char *token); int find_and_set_default_shell (const char *token);
/* indicates whether or not we have Bourne shell */ /* indicates whether or not we have Bourne shell */
extern int no_default_sh_exe; extern int no_default_sh_exe;
@ -385,7 +385,7 @@ char *concat (const char *, const char *, const char *);
void *xmalloc (unsigned int); void *xmalloc (unsigned int);
void *xrealloc (void *, unsigned int); void *xrealloc (void *, unsigned int);
char *xstrdup (const char *); char *xstrdup (const char *);
char *find_next_token (char **, unsigned int *); char *find_next_token (const char **, unsigned int *);
char *next_token (const char *); char *next_token (const char *);
char *end_of_token (const char *); char *end_of_token (const char *);
void collapse_continuations (char *); void collapse_continuations (char *);
@ -393,6 +393,7 @@ char *lindex (const char *, const char *, int);
int alpha_compare (const void *, const void *); int alpha_compare (const void *, const void *);
void print_spaces (unsigned int); void print_spaces (unsigned int);
char *find_percent (char *); char *find_percent (char *);
const char *find_percent_cached (const char **);
FILE *open_tmpfile (char **, const char *); FILE *open_tmpfile (char **, const char *);
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
@ -427,10 +428,10 @@ void install_default_implicit_rules (void);
void build_vpath_lists (void); void build_vpath_lists (void);
void construct_vpath_list (char *pattern, char *dirpath); void construct_vpath_list (char *pattern, char *dirpath);
int vpath_search (char **file, FILE_TIMESTAMP *mtime_ptr); const char *vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr);
int gpath_search (const char *file, unsigned int len); int gpath_search (const char *file, unsigned int len);
void construct_include_path (char **arg_dirs); void construct_include_path (const char **arg_dirs);
void user_access (void); void user_access (void);
void make_access (void); void make_access (void);
@ -585,5 +586,5 @@ extern int handling_fatal_signal;
NULL at the end of the directory--and _doesn't_ reset errno. So, we have NULL at the end of the directory--and _doesn't_ reset errno. So, we have
to do it ourselves here. */ to do it ourselves here. */
#define ENULLLOOP(_v,_c) do{ errno = 0; \ #define ENULLLOOP(_v,_c) do { errno = 0; (_v) = _c; } \
while (((_v)=_c)==0 && errno==EINTR); }while(0) while((_v)==0 && errno==EINTR)

101
misc.c
View File

@ -158,28 +158,31 @@ print_spaces (unsigned int n)
} }
/* Return a newly-allocated string whose contents /* Return a string whose contents concatenate those of s1, s2, s3.
concatenate those of s1, s2, s3. */ This string lives in static, re-used memory. */
char * char *
concat (const char *s1, const char *s2, const char *s3) concat (const char *s1, const char *s2, const char *s3)
{ {
unsigned int len1, len2, len3; unsigned int len1, len2, len3;
char *result; static unsigned int rlen = 0;
static char *result = NULL;
len1 = *s1 != '\0' ? strlen (s1) : 0; len1 = (s1 && *s1 != '\0') ? strlen (s1) : 0;
len2 = *s2 != '\0' ? strlen (s2) : 0; len2 = (s2 && *s2 != '\0') ? strlen (s2) : 0;
len3 = *s3 != '\0' ? strlen (s3) : 0; len3 = (s3 && *s3 != '\0') ? strlen (s3) : 0;
result = xmalloc (len1 + len2 + len3 + 1); if (len1 + len2 + len3 + 1 > rlen)
result = xrealloc (result, (rlen = len1 + len2 + len3 + 10));
if (*s1 != '\0') if (len1)
memcpy (result, s1, len1); memcpy (result, s1, len1);
if (*s2 != '\0') if (len2)
memcpy (result + len1, s2, len2); memcpy (result + len1, s2, len2);
if (*s3 != '\0') if (len3)
memcpy (result + len1 + len2, s3, len3); memcpy (result + len1 + len2, s3, len3);
*(result + len1 + len2 + len3) = '\0';
result[len1+len2+len3] = '\0';
return result; return result;
} }
@ -426,10 +429,10 @@ end_of_token (const char *s)
* Same as end_of_token, but take into account a stop character * Same as end_of_token, but take into account a stop character
*/ */
char * char *
end_of_token_w32 (char *s, char stopchar) end_of_token_w32 (const char *s, char stopchar)
{ {
register char *p = s; const char *p = s;
register int backslash = 0; int backslash = 0;
while (*p != '\0' && *p != stopchar while (*p != '\0' && *p != stopchar
&& (backslash || !isblank ((unsigned char)*p))) && (backslash || !isblank ((unsigned char)*p)))
@ -447,7 +450,7 @@ end_of_token_w32 (char *s, char stopchar)
backslash = 0; backslash = 0;
} }
return p; return (char *)p;
} }
#endif #endif
@ -461,22 +464,23 @@ next_token (const char *s)
return (char *)s; return (char *)s;
} }
/* Find the next token in PTR; return the address of it, and store the /* Find the next token in PTR; return the address of it, and store the length
length of the token into *LENGTHPTR if LENGTHPTR is not nil. */ of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end
of the token, so this function can be called repeatedly in a loop. */
char * char *
find_next_token (char **ptr, unsigned int *lengthptr) find_next_token (const char **ptr, unsigned int *lengthptr)
{ {
char *p = next_token (*ptr); const char *p = next_token (*ptr);
char *end;
if (*p == '\0') if (*p == '\0')
return 0; return 0;
*ptr = end = end_of_token (p); *ptr = end_of_token (p);
if (lengthptr != 0) if (lengthptr != 0)
*lengthptr = end - p; *lengthptr = *ptr - p;
return p;
return (char *)p;
} }
@ -496,12 +500,6 @@ alloc_dep ()
void void
free_dep (struct dep *d) free_dep (struct dep *d)
{ {
if (d->name != 0)
free (d->name);
if (d->stem != 0)
free (d->stem);
free (d); free (d);
} }
@ -511,20 +509,14 @@ free_dep (struct dep *d)
struct dep * struct dep *
copy_dep_chain (const struct dep *d) copy_dep_chain (const struct dep *d)
{ {
register struct dep *c;
struct dep *firstnew = 0; struct dep *firstnew = 0;
struct dep *lastnew = 0; struct dep *lastnew = 0;
while (d != 0) while (d != 0)
{ {
c = xmalloc (sizeof (struct dep)); struct dep *c = xmalloc (sizeof (struct dep));
memcpy (c, d, sizeof (struct dep)); memcpy (c, d, sizeof (struct dep));
if (c->name != 0)
c->name = xstrdup (c->name);
if (c->stem != 0)
c->stem = xstrdup (c->stem);
c->next = 0; c->next = 0;
if (firstnew == 0) if (firstnew == 0)
firstnew = lastnew = c; firstnew = lastnew = c;
@ -549,37 +541,20 @@ free_dep_chain (struct dep *d)
free_dep (df); free_dep (df);
} }
} }
/* Free a chain of `struct nameseq'. Each nameseq->name is freed /* Free a chain of struct nameseq.
as well. For `struct dep' chains use free_dep_chain. */ For struct dep chains use free_dep_chain. */
void void
free_ns_chain (struct nameseq *n) free_ns_chain (struct nameseq *ns)
{ {
register struct nameseq *tmp; while (ns != 0)
{
while (n != 0) struct nameseq *t = ns;
{ ns = ns->next;
if (n->name != 0) free (t);
free (n->name); }
tmp = n;
n = n->next;
free (tmp);
}
}
#ifdef iAPX286
/* The losing compiler on this machine can't handle this macro. */
char *
dep_name (struct dep *dep)
{
return dep->name == 0 ? dep->file->name : dep->name;
} }
#endif
#ifdef GETLOADAVG_PRIVILEGED #ifdef GETLOADAVG_PRIVILEGED

461
read.c
View File

@ -88,14 +88,12 @@ static struct conditionals *conditionals = &toplevel_conditionals;
/* Default directories to search for include files in */ /* Default directories to search for include files in */
static char *default_include_directories[] = static const char *default_include_directories[] =
{ {
#if defined(WINDOWS32) && !defined(INCLUDEDIR) #if defined(WINDOWS32) && !defined(INCLUDEDIR)
/* /* This completely up to the user when they install MSVC or other packages.
* This completely up to the user when they install MSVC or other packages. This is defined as a placeholder. */
* This is defined as a placeholder. # define INCLUDEDIR "."
*/
#define INCLUDEDIR "."
#endif #endif
INCLUDEDIR, INCLUDEDIR,
#ifndef _AMIGA #ifndef _AMIGA
@ -108,7 +106,7 @@ static char *default_include_directories[] =
/* List of directories to search for include files in */ /* List of directories to search for include files in */
static char **include_directories; static const char **include_directories;
/* Maximum length of an element of the above. */ /* Maximum length of an element of the above. */
@ -123,15 +121,15 @@ const struct floc *reading_file = 0;
static struct dep *read_makefiles = 0; static struct dep *read_makefiles = 0;
static int eval_makefile (char *filename, int flags); static int eval_makefile (const char *filename, int flags);
static int eval (struct ebuffer *buffer, int flags); static int eval (struct ebuffer *buffer, int flags);
static long readline (struct ebuffer *ebuf); static long readline (struct ebuffer *ebuf);
static void do_define (char *name, unsigned int namelen, static void do_define (char *name, unsigned int namelen,
enum variable_origin origin, struct ebuffer *ebuf); enum variable_origin origin, struct ebuffer *ebuf);
static int conditional_line (char *line, int len, const struct floc *flocp); static int conditional_line (char *line, int len, const struct floc *flocp);
static void record_files (struct nameseq *filenames, char *pattern, static void record_files (struct nameseq *filenames, const char *pattern,
char *pattern_percent, struct dep *deps, const char *pattern_percent, struct dep *deps,
unsigned int cmds_started, char *commands, unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon, unsigned int commands_idx, int two_colon,
const struct floc *flocp); const struct floc *flocp);
@ -147,7 +145,7 @@ static char *find_char_unquote (char *string, int stop1, int stop2,
/* Read in all the makefiles and return the chain of their names. */ /* Read in all the makefiles and return the chain of their names. */
struct dep * struct dep *
read_all_makefiles (char **makefiles) read_all_makefiles (const char **makefiles)
{ {
unsigned int num_makefiles = 0; unsigned int num_makefiles = 0;
@ -181,7 +179,7 @@ read_all_makefiles (char **makefiles)
MAKEFILES is updated for finding remaining tokens. */ MAKEFILES is updated for finding remaining tokens. */
p = value; p = value;
while ((name = find_next_token (&p, &length)) != 0) while ((name = find_next_token ((const char **)&p, &length)) != 0)
{ {
if (*p != '\0') if (*p != '\0')
*p++ = '\0'; *p++ = '\0';
@ -248,7 +246,7 @@ read_all_makefiles (char **makefiles)
for (p = default_makefiles; *p != 0; ++p) for (p = default_makefiles; *p != 0; ++p)
{ {
struct dep *d = alloc_dep (); struct dep *d = alloc_dep ();
d->file = enter_file (*p); d->file = enter_file (strcache_add (*p));
d->file->dontcare = 1; d->file->dontcare = 1;
/* Tell update_goal_chain to bail out as soon as this file is /* Tell update_goal_chain to bail out as soon as this file is
made, and main not to die if we can't make this file. */ made, and main not to die if we can't make this file. */
@ -296,17 +294,17 @@ restore_conditionals (struct conditionals *saved)
} }
static int static int
eval_makefile (char *filename, int flags) eval_makefile (const char *filename, int flags)
{ {
struct dep *deps; struct dep *deps;
struct ebuffer ebuf; struct ebuffer ebuf;
const struct floc *curfile; const struct floc *curfile;
char *expanded = 0; char *expanded = 0;
char *included = 0;
int makefile_errno; int makefile_errno;
int r; int r;
ebuf.floc.filenm = strcache_add (filename); filename = strcache_add (filename);
ebuf.floc.filenm = filename;
ebuf.floc.lineno = 1; ebuf.floc.lineno = 1;
if (ISDB (DB_VERBOSE)) if (ISDB (DB_VERBOSE))
@ -343,21 +341,17 @@ eval_makefile (char *filename, int flags)
search the included makefile search path for this makefile. */ search the included makefile search path for this makefile. */
if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/') if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/')
{ {
register unsigned int i; unsigned int i;
for (i = 0; include_directories[i] != 0; ++i) for (i = 0; include_directories[i] != 0; ++i)
{ {
included = concat (include_directories[i], "/", filename); const char *included = concat (include_directories[i], "/", filename);
ebuf.fp = fopen (included, "r"); ebuf.fp = fopen (included, "r");
if (ebuf.fp) if (ebuf.fp)
{ {
filename = included; filename = strcache_add (included);
break; break;
} }
free (included);
} }
/* If we're not using it, we already freed it above. */
if (filename != included)
included = 0;
} }
/* Add FILENAME to the chain of read makefiles. */ /* Add FILENAME to the chain of read makefiles. */
@ -366,7 +360,7 @@ eval_makefile (char *filename, int flags)
read_makefiles = deps; read_makefiles = deps;
deps->file = lookup_file (filename); deps->file = lookup_file (filename);
if (deps->file == 0) if (deps->file == 0)
deps->file = enter_file (xstrdup (filename)); deps->file = enter_file (filename);
filename = deps->file->name; filename = deps->file->name;
deps->changed = flags; deps->changed = flags;
if (flags & RM_DONTCARE) if (flags & RM_DONTCARE)
@ -374,8 +368,6 @@ eval_makefile (char *filename, int flags)
if (expanded) if (expanded)
free (expanded); free (expanded);
if (included)
free (included);
/* If the makefile can't be found at all, give up entirely. */ /* If the makefile can't be found at all, give up entirely. */
@ -464,7 +456,8 @@ eval (struct ebuffer *ebuf, int set_default)
struct dep *deps = 0; struct dep *deps = 0;
long nlines = 0; long nlines = 0;
int two_colon = 0; int two_colon = 0;
char *pattern = 0, *pattern_percent; const char *pattern = 0;
const char *pattern_percent;
struct floc *fstart; struct floc *fstart;
struct floc fi; struct floc fi;
@ -481,7 +474,7 @@ eval (struct ebuffer *ebuf, int set_default)
filenames = 0; \ filenames = 0; \
commands_idx = 0; \ commands_idx = 0; \
no_targets = 0; \ no_targets = 0; \
if (pattern) { free(pattern); pattern = 0; } \ pattern = 0; \
} while (0) } while (0)
pattern_percent = 0; pattern_percent = 0;
@ -708,14 +701,15 @@ eval (struct ebuffer *ebuf, int set_default)
else else
{ {
unsigned int l; unsigned int l;
const char *cp;
char *ap; char *ap;
/* Expand the line so we can use indirect and constructed /* Expand the line so we can use indirect and constructed
variable names in an export command. */ variable names in an export command. */
p2 = ap = allocated_variable_expand (p2); cp = ap = allocated_variable_expand (p2);
for (p = find_next_token (&p2, &l); p != 0; for (p = find_next_token (&cp, &l); p != 0;
p = find_next_token (&p2, &l)) p = find_next_token (&cp, &l))
{ {
v = lookup_variable (p, l); v = lookup_variable (p, l);
if (v == 0) if (v == 0)
@ -737,14 +731,15 @@ eval (struct ebuffer *ebuf, int set_default)
{ {
unsigned int l; unsigned int l;
struct variable *v; struct variable *v;
const char *cp;
char *ap; char *ap;
/* Expand the line so we can use indirect and constructed /* Expand the line so we can use indirect and constructed
variable names in an unexport command. */ variable names in an unexport command. */
p2 = ap = allocated_variable_expand (p2); cp = ap = allocated_variable_expand (p2);
for (p = find_next_token (&p2, &l); p != 0; for (p = find_next_token (&cp, &l); p != 0;
p = find_next_token (&p2, &l)) p = find_next_token (&cp, &l))
{ {
v = lookup_variable (p, l); v = lookup_variable (p, l);
if (v == 0) if (v == 0)
@ -761,14 +756,15 @@ eval (struct ebuffer *ebuf, int set_default)
skip_conditionals: skip_conditionals:
if (word1eq ("vpath")) if (word1eq ("vpath"))
{ {
const char *cp;
char *vpat; char *vpat;
unsigned int l; unsigned int l;
p2 = variable_expand (p2); cp = variable_expand (p2);
p = find_next_token (&p2, &l); p = find_next_token (&cp, &l);
if (p != 0) if (p != 0)
{ {
vpat = savestring (p, l); vpat = savestring (p, l);
p = find_next_token (&p2, &l); p = find_next_token (&cp, &l);
/* No searchpath means remove all previous /* No searchpath means remove all previous
selective VPATH's with the same pattern. */ selective VPATH's with the same pattern. */
} }
@ -822,7 +818,7 @@ eval (struct ebuffer *ebuf, int set_default)
while (files != 0) while (files != 0)
{ {
struct nameseq *next = files->next; struct nameseq *next = files->next;
char *name = files->name; const char *name = files->name;
int r; int r;
free (files); free (files);
@ -832,7 +828,6 @@ eval (struct ebuffer *ebuf, int set_default)
| (noerror ? RM_DONTCARE : 0))); | (noerror ? RM_DONTCARE : 0)));
if (!r && !noerror) if (!r && !noerror)
error (fstart, "%s: %s", name, strerror (errno)); error (fstart, "%s: %s", name, strerror (errno));
free (name);
} }
/* Restore conditional state. */ /* Restore conditional state. */
@ -1148,8 +1143,8 @@ eval (struct ebuffer *ebuf, int set_default)
fatal (fstart, _("missing target pattern")); fatal (fstart, _("missing target pattern"));
else if (target->next != 0) else if (target->next != 0)
fatal (fstart, _("multiple target patterns")); fatal (fstart, _("multiple target patterns"));
pattern_percent = find_percent_cached (&target->name);
pattern = target->name; pattern = target->name;
pattern_percent = find_percent (pattern);
if (pattern_percent == 0) if (pattern_percent == 0)
fatal (fstart, _("target pattern contains no `%%'")); fatal (fstart, _("target pattern contains no `%%'"));
free (target); free (target);
@ -1166,7 +1161,7 @@ eval (struct ebuffer *ebuf, int set_default)
{ {
/* Put all the prerequisites here; they'll be parsed later. */ /* Put all the prerequisites here; they'll be parsed later. */
deps = alloc_dep (); deps = alloc_dep ();
deps->name = savestring (beg, end - beg + 1); deps->name = strcache_add_len (beg, end - beg + 1);
} }
else else
deps = 0; deps = 0;
@ -1208,7 +1203,7 @@ eval (struct ebuffer *ebuf, int set_default)
if (**default_goal_name == '\0' && set_default) if (**default_goal_name == '\0' && set_default)
{ {
char* name; const char *name;
struct dep *d; struct dep *d;
struct nameseq *t = filenames; struct nameseq *t = filenames;
@ -1769,9 +1764,9 @@ record_target_var (struct nameseq *filenames, char *defn,
for (; filenames != 0; filenames = nextf) for (; filenames != 0; filenames = nextf)
{ {
struct variable *v; struct variable *v;
register char *name = filenames->name; const char *name = filenames->name;
char *fname; const char *fname;
char *percent; const char *percent;
struct pattern_var *p; struct pattern_var *p;
nextf = filenames->next; nextf = filenames->next;
@ -1779,7 +1774,7 @@ record_target_var (struct nameseq *filenames, char *defn,
/* If it's a pattern target, then add it to the pattern-specific /* If it's a pattern target, then add it to the pattern-specific
variable list. */ variable list. */
percent = find_percent (name); percent = find_percent_cached (&name);
if (percent) if (percent)
{ {
/* Get a reference for this pattern-specific variable struct. */ /* Get a reference for this pattern-specific variable struct. */
@ -1807,7 +1802,7 @@ record_target_var (struct nameseq *filenames, char *defn,
this situation. */ this situation. */
f = lookup_file (name); f = lookup_file (name);
if (!f) if (!f)
f = enter_file (name); f = enter_file (strcache_add (name));
else if (f->double_colon) else if (f->double_colon)
f = f->double_colon; f = f->double_colon;
@ -1844,10 +1839,6 @@ record_target_var (struct nameseq *filenames, char *defn,
v->append = 0; v->append = 0;
} }
} }
/* Free name if not needed further. */
if (name != fname && (name < fname || name > fname + strlen (fname)))
free (name);
} }
} }
@ -1863,15 +1854,16 @@ record_target_var (struct nameseq *filenames, char *defn,
that are not incorporated into other data structures. */ that are not incorporated into other data structures. */
static void static void
record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, record_files (struct nameseq *filenames, const char *pattern,
struct dep *deps, unsigned int cmds_started, char *commands, const char *pattern_percent, struct dep *deps,
unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon, unsigned int commands_idx, int two_colon,
const struct floc *flocp) const struct floc *flocp)
{ {
struct nameseq *nextf; struct nameseq *nextf;
int implicit = 0; int implicit = 0;
unsigned int max_targets = 0, target_idx = 0; unsigned int max_targets = 0, target_idx = 0;
char **targets = 0, **target_percents = 0; const char **targets = 0, **target_percents = 0;
struct commands *cmds; struct commands *cmds;
/* If we've already snapped deps, that means we're in an eval being /* If we've already snapped deps, that means we're in an eval being
@ -1894,10 +1886,10 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
for (; filenames != 0; filenames = nextf) for (; filenames != 0; filenames = nextf)
{ {
char *name = filenames->name; const char *name = filenames->name;
struct file *f; struct file *f;
struct dep *this = 0; struct dep *this = 0;
char *implicit_percent; const char *implicit_percent;
nextf = filenames->next; nextf = filenames->next;
free (filenames); free (filenames);
@ -1910,17 +1902,17 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
else if (streq (name, ".SECONDEXPANSION")) else if (streq (name, ".SECONDEXPANSION"))
second_expansion = 1; second_expansion = 1;
implicit_percent = find_percent (name); implicit_percent = find_percent_cached (&name);
implicit |= implicit_percent != 0; implicit |= implicit_percent != 0;
if (implicit && pattern != 0)
fatal (flocp, _("mixed implicit and static pattern rules"));
if (implicit && implicit_percent == 0)
fatal (flocp, _("mixed implicit and normal rules"));
if (implicit) if (implicit)
{ {
if (pattern != 0)
fatal (flocp, _("mixed implicit and static pattern rules"));
if (implicit_percent == 0)
fatal (flocp, _("mixed implicit and normal rules"));
if (targets == 0) if (targets == 0)
{ {
max_targets = 5; max_targets = 5;
@ -1960,7 +1952,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
{ {
/* Single-colon. Combine these dependencies /* Single-colon. Combine these dependencies
with others in file's existing record, if any. */ with others in file's existing record, if any. */
f = enter_file (name); f = enter_file (strcache_add (name));
if (f->double_colon) if (f->double_colon)
fatal (flocp, fatal (flocp,
@ -2066,7 +2058,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
if (f != 0 && f->is_target && !f->double_colon) if (f != 0 && f->is_target && !f->double_colon)
fatal (flocp, fatal (flocp,
_("target file `%s' has both : and :: entries"), f->name); _("target file `%s' has both : and :: entries"), f->name);
f = enter_file (name); f = enter_file (strcache_add (name));
/* If there was an existing entry and it was a double-colon entry, /* If there was an existing entry and it was a double-colon entry,
enter_file will have returned a new one, making it the prev enter_file will have returned a new one, making it the prev
pointer of the old one, and setting its double_colon pointer to pointer of the old one, and setting its double_colon pointer to
@ -2085,25 +2077,19 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
commands. */ commands. */
if (pattern) if (pattern)
{ {
static char *percent = "%"; static const char *percent = "%";
char *buffer = variable_expand (""); char *buffer = variable_expand ("");
char *o = patsubst_expand (buffer, name, pattern, percent, char *o = patsubst_expand_pat (buffer, name, pattern, percent,
pattern_percent+1, percent+1); pattern_percent+1, percent+1);
f->stem = savestring (buffer, o - buffer); f->stem = strcache_add_len (buffer, o - buffer);
if (this) if (this)
{ {
this->staticpattern = 1; this->staticpattern = 1;
this->stem = xstrdup (f->stem); this->stem = f->stem;
} }
} }
/* Free name if not needed further. */ name = f->name;
if (f != 0 && name != f->name
&& (name < f->name || name > f->name + strlen (f->name)))
{
free (name);
name = f->name;
}
/* If this target is a default target, update DEFAULT_GOAL_FILE. */ /* If this target is a default target, update DEFAULT_GOAL_FILE. */
if (streq (*default_goal_name, name) if (streq (*default_goal_name, name)
@ -2114,12 +2100,10 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
if (implicit) if (implicit)
{ {
targets[target_idx] = 0;
target_percents[target_idx] = 0;
if (deps) if (deps)
deps->need_2nd_expansion = second_expansion; deps->need_2nd_expansion = second_expansion;
create_pattern_rule (targets, target_percents, two_colon, deps, cmds, 1); create_pattern_rule (targets, target_percents, target_idx,
free (target_percents); two_colon, deps, cmds, 1);
} }
} }
@ -2137,7 +2121,7 @@ find_char_unquote (char *string, int stop1, int stop2, int blank,
int ignorevars) int ignorevars)
{ {
unsigned int string_len = 0; unsigned int string_len = 0;
register char *p = string; char *p = string;
if (ignorevars) if (ignorevars)
ignorevars = '$'; ignorevars = '$';
@ -2230,6 +2214,82 @@ find_percent (char *pattern)
{ {
return find_char_unquote (pattern, '%', 0, 0, 0); return find_char_unquote (pattern, '%', 0, 0, 0);
} }
/* Search STRING for an unquoted % and handle quoting. Returns a pointer to
the % or NULL if no % was found.
This version is used with strings in the string cache: if there's a need to
modify the string a new version will be added to the string cache and
*STRING will be set to that. */
const char *
find_percent_cached (const char **string)
{
const char *p = *string;
char *new = 0;
int slen;
/* If the first char is a % return now. This lets us avoid extra tests
inside the loop. */
if (*p == '%')
return p;
while (1)
{
while (*p != '\0' && *p != '%')
++p;
if (*p == '\0')
break;
/* See if this % is escaped with a backslash; if not we're done. */
if (p[-1] != '\\')
break;
{
/* Search for more backslashes. */
char *pv;
int i = -2;
while (&p[i] >= *string && p[i] == '\\')
--i;
++i;
/* At this point we know we'll need to allocate a new string.
Make a copy if we haven't yet done so. */
if (! new)
{
slen = strlen (*string);
new = alloca (slen + 1);
memcpy (new, *string, slen + 1);
p = new + (p - *string);
*string = new;
}
/* At this point *string, p, and new all point into the same string.
Get a non-const version of p so we can modify new. */
pv = new + (p - *string);
/* The number of backslashes is now -I.
Copy P over itself to swallow half of them. */
memmove (&pv[i], &pv[i/2], (slen - (pv - new)) - (i/2) + 1);
p += i/2;
/* If the backslashes quoted each other; the % was unquoted. */
if (i % 2 == 0)
break;
}
}
/* If we had to change STRING, add it to the strcache. */
if (new)
{
*string = strcache_add (*string);
p = *string + (p - new);
}
/* If we didn't find a %, return NULL. Otherwise return a ptr to it. */
return (*p == '\0') ? NULL : p;
}
/* Parse a string into a sequence of filenames represented as a /* Parse a string into a sequence of filenames represented as a
chain of struct nameseq's in reverse order and return that chain. chain of struct nameseq's in reverse order and return that chain.
@ -2250,8 +2310,6 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
struct nameseq *new = 0; struct nameseq *new = 0;
struct nameseq *new1, *lastnew1; struct nameseq *new1, *lastnew1;
char *p = *stringp; char *p = *stringp;
char *q;
char *name;
#ifdef VMS #ifdef VMS
# define VMS_COMMA ',' # define VMS_COMMA ','
@ -2261,6 +2319,9 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
while (1) while (1)
{ {
const char *name;
char *q;
/* Skip whitespace; see if any more names are left. */ /* Skip whitespace; see if any more names are left. */
p = next_token (p); p = next_token (p);
if (*p == '\0') if (*p == '\0')
@ -2268,7 +2329,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
if (*p == stopchar) if (*p == stopchar)
break; break;
/* Yes, find end of next name. */ /* There are, so find the end of the next name. */
q = p; q = p;
p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0); p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0);
#ifdef VMS #ifdef VMS
@ -2280,9 +2341,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
if (stopchar == ':' && p && *p == ':' if (stopchar == ':' && p && *p == ':'
&& !(isspace ((unsigned char)p[1]) || !p[1] && !(isspace ((unsigned char)p[1]) || !p[1]
|| isspace ((unsigned char)p[-1]))) || isspace ((unsigned char)p[-1])))
{
p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0); p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0);
}
#endif #endif
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* For DOS paths, skip a "C:\..." or a "C:/..." until we find the /* For DOS paths, skip a "C:\..." or a "C:/..." until we find the
@ -2316,14 +2375,12 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
if (q == p) if (q == p)
/* ".///" was stripped to "". */ /* ".///" was stripped to "". */
#ifdef VMS #if defined(VMS)
continue; continue;
#elif defined(_AMIGA)
name = "";
#else #else
#ifdef _AMIGA name = "./";
name = savestring ("", 0);
#else
name = savestring ("./", 2);
#endif
#endif #endif
else else
#ifdef VMS #ifdef VMS
@ -2347,11 +2404,11 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
} }
*q2++ = *q1++; *q2++ = *q1++;
} }
name = savestring (qbase, p1 - qbase); name = strcache_add_len (qbase, p1 - qbase);
free (qbase); free (qbase);
} }
#else #else
name = savestring (q, p - q); name = strcache_add_len (q, p - q);
#endif #endif
/* Add it to the front of the chain. */ /* Add it to the front of the chain. */
@ -2407,7 +2464,6 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
/* N was just "lib(", part of something like "lib( a b)". /* N was just "lib(", part of something like "lib( a b)".
Edit it out of the chain and free its storage. */ Edit it out of the chain and free its storage. */
lastn->next = n->next; lastn->next = n->next;
free (n->name);
free (n); free (n);
/* LASTN->next is the new stopping elt for the loop below. */ /* LASTN->next is the new stopping elt for the loop below. */
n = lastn->next; n = lastn->next;
@ -2415,9 +2471,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
else else
{ {
/* Replace N's name with the full archive reference. */ /* Replace N's name with the full archive reference. */
name = concat (libname, paren, ")"); n->name = strcache_add (concat (libname, paren, ")"));
free (n->name);
n->name = name;
} }
if (new1->name[1] == '\0') if (new1->name[1] == '\0')
@ -2430,15 +2484,12 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
lastnew1->next = new1->next; lastnew1->next = new1->next;
lastn = new1; lastn = new1;
new1 = new1->next; new1 = new1->next;
free (lastn->name);
free (lastn); free (lastn);
} }
else else
{ {
/* Replace also NEW1->name, which already has closing `)'. */ /* Replace also NEW1->name, which already has closing `)'. */
name = concat (libname, new1->name, ""); new1->name = strcache_add (concat (libname, new1->name, ""));
free (new1->name);
new1->name = name;
new1 = new1->next; new1 = new1->next;
} }
@ -2448,9 +2499,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
while (new1 != n) while (new1 != n)
{ {
name = concat (libname, new1->name, ")"); new1->name = strcache_add (concat (libname, new1->name, ")"));
free (new1->name);
new1->name = name;
lastnew1 = new1; lastnew1 = new1;
new1 = new1->next; new1 = new1->next;
} }
@ -2818,104 +2867,112 @@ get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length)
from the arguments and the default list. */ from the arguments and the default list. */
void void
construct_include_path (char **arg_dirs) construct_include_path (const char **arg_dirs)
{ {
register unsigned int i;
#ifdef VAXC /* just don't ask ... */ #ifdef VAXC /* just don't ask ... */
stat_t stbuf; stat_t stbuf;
#else #else
struct stat stbuf; struct stat stbuf;
#endif #endif
/* Table to hold the dirs. */ const char **dirs;
const char **cpp;
unsigned int idx;
unsigned int defsize = (sizeof (default_include_directories) /* Compute the number of pointers we need in the table. */
/ sizeof (default_include_directories[0])); idx = sizeof (default_include_directories) / sizeof (const char *);
unsigned int max = 5; if (arg_dirs)
char **dirs = xmalloc ((5 + defsize) * sizeof (char *)); for (cpp = arg_dirs; *cpp != 0; ++cpp)
unsigned int idx = 0; ++idx;
#ifdef __MSDOS__ #ifdef __MSDOS__
defsize++; /* Add one for $DJDIR. */
++idx;
#endif #endif
/* First consider any dirs specified with -I switches. dirs = xmalloc (idx * sizeof (const char *));
Ignore dirs that don't exist. */
if (arg_dirs != 0) idx = 0;
max_incl_len = 0;
/* First consider any dirs specified with -I switches.
Ignore any that don't exist. Remember the maximum string length. */
if (arg_dirs)
while (*arg_dirs != 0) while (*arg_dirs != 0)
{ {
char *dir = *arg_dirs++; const char *dir = *(arg_dirs++);
char *expanded = 0;
int e; int e;
if (dir[0] == '~') if (dir[0] == '~')
{ {
char *expanded = tilde_expand (dir); expanded = tilde_expand (dir);
if (expanded != 0) if (expanded != 0)
dir = expanded; dir = expanded;
} }
EINTRLOOP (e, stat (dir, &stbuf)); EINTRLOOP (e, stat (dir, &stbuf));
if (e == 0 && S_ISDIR (stbuf.st_mode)) if (e == 0 && S_ISDIR (stbuf.st_mode))
{ {
if (idx == max - 1) unsigned int len = strlen (dir);
{ /* If dir name is written with trailing slashes, discard them. */
max += 5; while (len > 1 && dir[len - 1] == '/')
dirs = xrealloc (dirs, (max + defsize) * sizeof (char *)); --len;
} if (len > max_incl_len)
dirs[idx++] = dir; max_incl_len = len;
} dirs[idx++] = strcache_add_len (dir, len);
else if (dir != arg_dirs[-1]) }
free (dir);
if (expanded)
free (expanded);
} }
/* Now add at the end the standard default dirs. */ /* Now add the standard default dirs at the end. */
#ifdef __MSDOS__ #ifdef __MSDOS__
{ {
/* The environment variable $DJDIR holds the root of the /* The environment variable $DJDIR holds the root of the DJGPP directory
DJGPP directory tree; add ${DJDIR}/include. */ tree; add ${DJDIR}/include. */
struct variable *djdir = lookup_variable ("DJDIR", 5); struct variable *djdir = lookup_variable ("DJDIR", 5);
if (djdir) if (djdir)
{ {
char *defdir = xmalloc (strlen (djdir->value) + 8 + 1); unsigned int len = strlen (djdir->value) + 8;
char *defdir = alloca (len + 1);
strcat (strcpy (defdir, djdir->value), "/include"); strcat (strcpy (defdir, djdir->value), "/include");
dirs[idx++] = defdir; dirs[idx++] = strcache_add (defdir);
if (len > max_incl_len)
max_incl_len = len;
} }
} }
#endif #endif
for (i = 0; default_include_directories[i] != 0; ++i) for (cpp = default_include_directories; *cpp != 0; ++cpp)
{ {
int e; int e;
EINTRLOOP (e, stat (default_include_directories[i], &stbuf)); EINTRLOOP (e, stat (*cpp, &stbuf));
if (e == 0 && S_ISDIR (stbuf.st_mode)) if (e == 0 && S_ISDIR (stbuf.st_mode))
dirs[idx++] = default_include_directories[i]; {
unsigned int len = strlen (*cpp);
/* If dir name is written with trailing slashes, discard them. */
while (len > 1 && (*cpp)[len - 1] == '/')
--len;
if (len > max_incl_len)
max_incl_len = len;
dirs[idx++] = strcache_add_len (*cpp, len - 1);
}
} }
dirs[idx] = 0; dirs[idx] = 0;
/* Now compute the maximum length of any name in it. Also add each /* Now add each dir to the .INCLUDE_DIRS variable. */
dir to the .INCLUDE_DIRS variable. */
max_incl_len = 0; for (cpp = dirs; *cpp != 0; ++cpp)
for (i = 0; i < idx; ++i) do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp,
{ o_default, f_append, 0);
unsigned int len = strlen (dirs[i]);
/* If dir name is written with a trailing slash, discard it. */
if (dirs[i][len - 1] == '/')
/* We can't just clobber a null in because it may have come from
a literal string and literal strings may not be writable. */
dirs[i] = savestring (dirs[i], len - 1);
if (len > max_incl_len)
max_incl_len = len;
/* Append to .INCLUDE_DIRS. */
do_variable_definition (NILF, ".INCLUDE_DIRS", dirs[i],
o_default, f_append, 0);
}
include_directories = dirs; include_directories = dirs;
} }
@ -2924,7 +2981,7 @@ construct_include_path (char **arg_dirs)
Return a newly malloc'd string or 0. */ Return a newly malloc'd string or 0. */
char * char *
tilde_expand (char *name) tilde_expand (const char *name)
{ {
#ifndef VMS #ifndef VMS
if (name[1] == '/' || name[1] == '\0') if (name[1] == '/' || name[1] == '\0')
@ -2949,7 +3006,7 @@ tilde_expand (char *name)
free (home_dir); free (home_dir);
home_dir = getenv ("HOME"); home_dir = getenv ("HOME");
} }
#if !defined(_AMIGA) && !defined(WINDOWS32) # if !defined(_AMIGA) && !defined(WINDOWS32)
if (home_dir == 0 || home_dir[0] == '\0') if (home_dir == 0 || home_dir[0] == '\0')
{ {
extern char *getlogin (); extern char *getlogin ();
@ -2962,16 +3019,16 @@ tilde_expand (char *name)
home_dir = p->pw_dir; home_dir = p->pw_dir;
} }
} }
#endif /* !AMIGA && !WINDOWS32 */ # endif /* !AMIGA && !WINDOWS32 */
if (home_dir != 0) if (home_dir != 0)
{ {
char *new = concat (home_dir, "", name + 1); char *new = xstrdup (concat (home_dir, "", name + 1));
if (is_variable) if (is_variable)
free (home_dir); free (home_dir);
return new; return new;
} }
} }
#if !defined(_AMIGA) && !defined(WINDOWS32) # if !defined(_AMIGA) && !defined(WINDOWS32)
else else
{ {
struct passwd *pwent; struct passwd *pwent;
@ -2984,12 +3041,12 @@ tilde_expand (char *name)
if (userend == 0) if (userend == 0)
return xstrdup (pwent->pw_dir); return xstrdup (pwent->pw_dir);
else else
return concat (pwent->pw_dir, "/", userend + 1); return xstrdup (concat (pwent->pw_dir, "/", userend + 1));
} }
else if (userend != 0) else if (userend != 0)
*userend = '/'; *userend = '/';
} }
#endif /* !AMIGA && !WINDOWS32 */ # endif /* !AMIGA && !WINDOWS32 */
#endif /* !VMS */ #endif /* !VMS */
return 0; return 0;
} }
@ -3007,9 +3064,9 @@ tilde_expand (char *name)
struct nameseq * struct nameseq *
multi_glob (struct nameseq *chain, unsigned int size) multi_glob (struct nameseq *chain, unsigned int size)
{ {
extern void dir_setup_glob (); void dir_setup_glob (glob_t *);
register struct nameseq *new = 0; struct nameseq *new = 0;
register struct nameseq *old; struct nameseq *old;
struct nameseq *nexto; struct nameseq *nexto;
glob_t gl; glob_t gl;
@ -3017,44 +3074,37 @@ multi_glob (struct nameseq *chain, unsigned int size)
for (old = chain; old != 0; old = nexto) for (old = chain; old != 0; old = nexto)
{ {
const char *gname;
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
char *memname; char *arname = 0;
char *memname = 0;
#endif #endif
nexto = old->next; nexto = old->next;
gname = old->name;
if (old->name[0] == '~') if (gname[0] == '~')
{ {
char *newname = tilde_expand (old->name); char *newname = tilde_expand (old->name);
if (newname != 0) if (newname != 0)
{ gname = newname;
free (old->name);
old->name = newname;
}
} }
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
if (ar_name (old->name)) if (ar_name (gname))
{ {
/* OLD->name is an archive member reference. /* OLD->name is an archive member reference. Replace it with the
Replace it with the archive file name, archive file name, and save the member name in MEMNAME. We will
and save the member name in MEMNAME. glob on the archive name and then reattach MEMNAME later. */
We will glob on the archive name and then ar_parse_name (gname, &arname, &memname);
reattach MEMNAME later. */ gname = arname;
char *arname;
ar_parse_name (old->name, &arname, &memname);
free (old->name);
old->name = arname;
} }
else
memname = 0;
#endif /* !NO_ARCHIVES */ #endif /* !NO_ARCHIVES */
switch (glob (old->name, GLOB_NOCHECK|GLOB_ALTDIRFUNC, NULL, &gl)) switch (glob (gname, GLOB_NOCHECK|GLOB_ALTDIRFUNC, NULL, &gl))
{ {
case 0: /* Success. */ case 0: /* Success. */
{ {
register int i = gl.gl_pathc; int i = gl.gl_pathc;
while (i-- > 0) while (i-- > 0)
{ {
#ifndef NO_ARCHIVES #ifndef NO_ARCHIVES
@ -3063,21 +3113,22 @@ multi_glob (struct nameseq *chain, unsigned int size)
/* Try to glob on MEMNAME within the archive. */ /* Try to glob on MEMNAME within the archive. */
struct nameseq *found struct nameseq *found
= ar_glob (gl.gl_pathv[i], memname, size); = ar_glob (gl.gl_pathv[i], memname, size);
if (found == 0) if (! found)
{ {
/* No matches. Use MEMNAME as-is. */ /* No matches. Use MEMNAME as-is. */
unsigned int alen = strlen (gl.gl_pathv[i]); unsigned int alen = strlen (gl.gl_pathv[i]);
unsigned int mlen = strlen (memname); unsigned int mlen = strlen (memname);
char *name;
struct nameseq *elt = xmalloc (size); struct nameseq *elt = xmalloc (size);
if (size > sizeof (struct nameseq)) memset (elt, '\0', size);
memset (((char *)elt)+sizeof (struct nameseq), '\0',
size - sizeof (struct nameseq)); name = alloca (alen + 1 + mlen + 2);
elt->name = xmalloc (alen + 1 + mlen + 2); memcpy (name, gl.gl_pathv[i], alen);
memcpy (elt->name, gl.gl_pathv[i], alen); name[alen] = '(';
elt->name[alen] = '('; memcpy (name+alen+1, memname, mlen);
memcpy (&elt->name[alen + 1], memname, mlen); name[alen + 1 + mlen] = ')';
elt->name[alen + 1 + mlen] = ')'; name[alen + 1 + mlen + 1] = '\0';
elt->name[alen + 1 + mlen + 1] = '\0'; elt->name = strcache_add (name);
elt->next = new; elt->next = new;
new = elt; new = elt;
} }
@ -3093,23 +3144,18 @@ multi_glob (struct nameseq *chain, unsigned int size)
f->next = new; f->next = new;
new = found; new = found;
} }
free (memname);
} }
else else
#endif /* !NO_ARCHIVES */ #endif /* !NO_ARCHIVES */
{ {
struct nameseq *elt = xmalloc (size); struct nameseq *elt = xmalloc (size);
if (size > sizeof (struct nameseq)) memset (elt, '\0', size);
memset (((char *)elt)+sizeof (struct nameseq), '\0', elt->name = strcache_add (gl.gl_pathv[i]);
size - sizeof (struct nameseq));
elt->name = xstrdup (gl.gl_pathv[i]);
elt->next = new; elt->next = new;
new = elt; new = elt;
} }
} }
globfree (&gl); globfree (&gl);
free (old->name);
free (old); free (old);
break; break;
} }
@ -3123,6 +3169,11 @@ multi_glob (struct nameseq *chain, unsigned int size)
new = old; new = old;
break; break;
} }
#ifndef NO_ARCHIVES
if (arname)
free (arname);
#endif
} }
return new; return new;

View File

@ -66,8 +66,8 @@ static int check_dep (struct file *file, unsigned int depth,
FILE_TIMESTAMP this_mtime, int *must_make_ptr); FILE_TIMESTAMP this_mtime, int *must_make_ptr);
static int touch_file (struct file *file); static int touch_file (struct file *file);
static void remake_file (struct file *file); static void remake_file (struct file *file);
static FILE_TIMESTAMP name_mtime (char *name); static FILE_TIMESTAMP name_mtime (const char *name);
static int library_search (char **lib, FILE_TIMESTAMP *mtime_ptr); static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
/* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing /* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing
@ -913,7 +913,7 @@ notice_finished_file (struct file *file)
We do this instead of just invalidating the cached time We do this instead of just invalidating the cached time
so that a vpath_search can happen. Otherwise, it would so that a vpath_search can happen. Otherwise, it would
never be done because the target is already updated. */ never be done because the target is already updated. */
(void) f_mtime (d->file, 0); f_mtime (d->file, 0);
} }
else if (file->update_status == -1) else if (file->update_status == -1)
/* Nothing was done for FILE, but it needed nothing done. /* Nothing was done for FILE, but it needed nothing done.
@ -1152,7 +1152,6 @@ f_mtime (struct file *file, int search)
char *arname, *memname; char *arname, *memname;
struct file *arfile; struct file *arfile;
int arname_used = 0;
time_t member_date; time_t member_date;
/* Find the archive's name. */ /* Find the archive's name. */
@ -1162,10 +1161,7 @@ f_mtime (struct file *file, int search)
Also allow for its name to be changed via VPATH search. */ Also allow for its name to be changed via VPATH search. */
arfile = lookup_file (arname); arfile = lookup_file (arname);
if (arfile == 0) if (arfile == 0)
{ arfile = enter_file (strcache_add (arname));
arfile = enter_file (arname);
arname_used = 1;
}
mtime = f_mtime (arfile, search); mtime = f_mtime (arfile, search);
check_renamed (arfile); check_renamed (arfile);
if (search && strcmp (arfile->hname, arname)) if (search && strcmp (arfile->hname, arname))
@ -1176,20 +1172,11 @@ f_mtime (struct file *file, int search)
char *name; char *name;
unsigned int arlen, memlen; unsigned int arlen, memlen;
if (!arname_used) arlen = strlen (arfile->hname);
{
free (arname);
arname_used = 1;
}
arname = arfile->hname;
arlen = strlen (arname);
memlen = strlen (memname); memlen = strlen (memname);
/* free (file->name); */
name = xmalloc (arlen + 1 + memlen + 2); name = xmalloc (arlen + 1 + memlen + 2);
memcpy (name, arname, arlen); memcpy (name, arfile->hname, arlen);
name[arlen] = '('; name[arlen] = '(';
memcpy (name + arlen + 1, memname, memlen); memcpy (name + arlen + 1, memname, memlen);
name[arlen + 1 + memlen] = ')'; name[arlen + 1 + memlen] = ')';
@ -1204,9 +1191,7 @@ f_mtime (struct file *file, int search)
check_renamed (file); check_renamed (file);
} }
if (!arname_used) free (arname);
free (arname);
free (memname);
file->low_resolution_time = 1; file->low_resolution_time = 1;
@ -1227,11 +1212,11 @@ f_mtime (struct file *file, int search)
if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath) if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
{ {
/* If name_mtime failed, search VPATH. */ /* If name_mtime failed, search VPATH. */
char *name = file->name; const char *name = vpath_search (file->name, &mtime);
if (vpath_search (&name, &mtime) if (name
/* Last resort, is it a library (-lxxx)? */ /* Last resort, is it a library (-lxxx)? */
|| (name[0] == '-' && name[1] == 'l' || (file->name[0] == '-' && file->name[1] == 'l'
&& library_search (&name, &mtime))) && (name = library_search (file->name, &mtime)) != 0))
{ {
if (mtime != UNKNOWN_MTIME) if (mtime != UNKNOWN_MTIME)
/* vpath_search and library_search store UNKNOWN_MTIME /* vpath_search and library_search store UNKNOWN_MTIME
@ -1350,7 +1335,7 @@ f_mtime (struct file *file, int search)
much cleaner. */ much cleaner. */
static FILE_TIMESTAMP static FILE_TIMESTAMP
name_mtime (char *name) name_mtime (const char *name)
{ {
FILE_TIMESTAMP mtime; FILE_TIMESTAMP mtime;
struct stat st; struct stat st;
@ -1444,8 +1429,8 @@ name_mtime (char *name)
suitable library file in the system library directories and the VPATH suitable library file in the system library directories and the VPATH
directories. */ directories. */
static int static const char *
library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
{ {
static char *dirs[] = static char *dirs[] =
{ {
@ -1466,14 +1451,15 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr)
static char *libpatterns = NULL; static char *libpatterns = NULL;
char *libname = &(*lib)[2]; /* Name without the `-l'. */ const char *libname = lib+2; /* Name without the '-l'. */
FILE_TIMESTAMP mtime; FILE_TIMESTAMP mtime;
/* Loop variables for the libpatterns value. */ /* Loop variables for the libpatterns value. */
char *p, *p2; char *p;
const char *p2;
unsigned int len; unsigned int len;
char *file, **dp; char **dp;
/* If we don't have libpatterns, get it. */ /* If we don't have libpatterns, get it. */
if (!libpatterns) if (!libpatterns)
@ -1522,20 +1508,18 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr)
mtime = name_mtime (libbuf); mtime = name_mtime (libbuf);
if (mtime != NONEXISTENT_MTIME) if (mtime != NONEXISTENT_MTIME)
{ {
*lib = xstrdup (libbuf);
if (mtime_ptr != 0) if (mtime_ptr != 0)
*mtime_ptr = mtime; *mtime_ptr = mtime;
return 1; return strcache_add (libbuf);
} }
/* Now try VPATH search on that. */ /* Now try VPATH search on that. */
file = libbuf; {
if (vpath_search (&file, mtime_ptr)) const char *file = vpath_search (libbuf, mtime_ptr);
{ if (file)
*lib = file; return file;
return 1; }
}
/* Now try the standard set of directories. */ /* Now try the standard set of directories. */
@ -1562,10 +1546,9 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr)
mtime = name_mtime (buf); mtime = name_mtime (buf);
if (mtime != NONEXISTENT_MTIME) if (mtime != NONEXISTENT_MTIME)
{ {
*lib = xstrdup (buf);
if (mtime_ptr != 0) if (mtime_ptr != 0)
*mtime_ptr = mtime; *mtime_ptr = mtime;
return 1; return strcache_add (buf);
} }
} }
} }

241
rule.c
View File

@ -17,6 +17,9 @@ GNU Make; see the file COPYING. If not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "make.h" #include "make.h"
#include <assert.h>
#include "dep.h" #include "dep.h"
#include "filedef.h" #include "filedef.h"
#include "job.h" #include "job.h"
@ -69,7 +72,7 @@ count_implicit_rule_limits (void)
{ {
char *name; char *name;
int namelen; int namelen;
register struct rule *rule, *lastrule; struct rule *rule, *lastrule;
num_pattern_rules = max_pattern_targets = max_pattern_deps = 0; num_pattern_rules = max_pattern_targets = max_pattern_deps = 0;
max_pattern_dep_length = 0; max_pattern_dep_length = 0;
@ -81,32 +84,27 @@ count_implicit_rule_limits (void)
while (rule != 0) while (rule != 0)
{ {
unsigned int ndeps = 0; unsigned int ndeps = 0;
register struct dep *dep; struct dep *dep;
struct rule *next = rule->next; struct rule *next = rule->next;
unsigned int ntargets;
++num_pattern_rules; ++num_pattern_rules;
ntargets = 0; if (rule->num > max_pattern_targets)
while (rule->targets[ntargets] != 0) max_pattern_targets = rule->num;
++ntargets;
if (ntargets > max_pattern_targets)
max_pattern_targets = ntargets;
for (dep = rule->deps; dep != 0; dep = dep->next) for (dep = rule->deps; dep != 0; dep = dep->next)
{ {
unsigned int len = strlen (dep->name); unsigned int len = strlen (dep->name);
#ifdef VMS #ifdef VMS
char *p = strrchr (dep->name, ']'); const char *p = strrchr (dep->name, ']');
char *p2; const char *p2;
if (p == 0) if (p == 0)
p = strrchr (dep->name, ':'); p = strrchr (dep->name, ':');
p2 = p != 0 ? strchr (dep->name, '%') : 0; p2 = p != 0 ? strchr (dep->name, '%') : 0;
#else #else
char *p = strrchr (dep->name, '/'); const char *p = strrchr (dep->name, '/');
char *p2 = p != 0 ? strchr (dep->name, '%') : 0; const char *p2 = p != 0 ? strchr (dep->name, '%') : 0;
#endif #endif
ndeps++; ndeps++;
@ -121,10 +119,8 @@ count_implicit_rule_limits (void)
++p; ++p;
if (p - dep->name > namelen) if (p - dep->name > namelen)
{ {
if (name != 0)
free (name);
namelen = p - dep->name; namelen = p - dep->name;
name = xmalloc (namelen + 1); name = xrealloc (name, namelen + 1);
} }
memcpy (name, dep->name, p - dep->name); memcpy (name, dep->name, p - dep->name);
name[p - dep->name] = '\0'; name[p - dep->name] = '\0';
@ -158,98 +154,103 @@ count_implicit_rule_limits (void)
If SOURCE is nil, it means there should be no deps. */ If SOURCE is nil, it means there should be no deps. */
static void static void
convert_suffix_rule (char *target, char *source, struct commands *cmds) convert_suffix_rule (const char *target, const char *source,
struct commands *cmds)
{ {
char *targname, *targpercent, *depname; const char **names, **percents;
char **names, **percents;
struct dep *deps; struct dep *deps;
unsigned int len;
names = xmalloc (sizeof (const char *));
percents = xmalloc (sizeof (const char *));
if (target == 0) if (target == 0)
/* Special case: TARGET being nil means we are defining a
`.X.a' suffix rule; the target pattern is always `(%.o)'. */
{ {
/* Special case: TARGET being nil means we are defining a `.X.a' suffix
rule; the target pattern is always `(%.o)'. */
#ifdef VMS #ifdef VMS
targname = savestring ("(%.obj)", 7); *names = strcache_add_len ("(%.obj)", 7);
#else #else
targname = savestring ("(%.o)", 5); *names = strcache_add_len ("(%.o)", 5);
#endif #endif
targpercent = targname + 1; *percents = *names + 1;
} }
else else
{ {
/* Construct the target name. */ /* Construct the target name. */
len = strlen (target); unsigned int len = strlen (target);
targname = xmalloc (1 + len + 1); char *p = alloca (1 + len + 1);
targname[0] = '%'; p[0] = '%';
memcpy (targname + 1, target, len + 1); memcpy (p + 1, target, len + 1);
targpercent = targname; *names = strcache_add_len (p, len + 1);
*percents = *names;
} }
names = xmalloc (2 * sizeof (char *));
percents = alloca (2 * sizeof (char *));
names[0] = targname;
percents[0] = targpercent;
names[1] = percents[1] = 0;
if (source == 0) if (source == 0)
deps = 0; deps = 0;
else else
{ {
/* Construct the dependency name. */ /* Construct the dependency name. */
len = strlen (source); unsigned int len = strlen (source);
depname = xmalloc (1 + len + 1); char *p = alloca (1 + len + 1);
depname[0] = '%'; p[0] = '%';
memcpy (depname + 1, source, len + 1); memcpy (p + 1, source, len + 1);
deps = alloc_dep (); deps = alloc_dep ();
deps->name = depname; deps->name = strcache_add_len (p, len + 1);
} }
create_pattern_rule (names, percents, 0, deps, cmds, 0); create_pattern_rule (names, percents, 1, 0, deps, cmds, 0);
} }
/* Convert old-style suffix rules to pattern rules. /* Convert old-style suffix rules to pattern rules.
All rules for the suffixes on the .SUFFIXES list All rules for the suffixes on the .SUFFIXES list are converted and added to
are converted and added to the chain of pattern rules. */ the chain of pattern rules. */
void void
convert_to_pattern (void) convert_to_pattern (void)
{ {
register struct dep *d, *d2; struct dep *d, *d2;
register struct file *f; char *rulename;
register char *rulename;
register unsigned int slen, s2len;
/* Compute maximum length of all the suffixes. */ /* We will compute every potential suffix rule (.x.y) from the list of
suffixes in the .SUFFIXES target's dependencies and see if it exists.
First find the longest of the suffixes. */
maxsuffix = 0; maxsuffix = 0;
for (d = suffix_file->deps; d != 0; d = d->next) for (d = suffix_file->deps; d != 0; d = d->next)
{ {
register unsigned int namelen = strlen (dep_name (d)); unsigned int l = strlen (dep_name (d));
if (namelen > maxsuffix) if (l > maxsuffix)
maxsuffix = namelen; maxsuffix = l;
} }
/* Space to construct the suffix rule target name. */
rulename = alloca ((maxsuffix * 2) + 1); rulename = alloca ((maxsuffix * 2) + 1);
for (d = suffix_file->deps; d != 0; d = d->next) for (d = suffix_file->deps; d != 0; d = d->next)
{ {
unsigned int slen;
/* Make a rule that is just the suffix, with no deps or commands. /* Make a rule that is just the suffix, with no deps or commands.
This rule exists solely to disqualify match-anything rules. */ This rule exists solely to disqualify match-anything rules. */
convert_suffix_rule (dep_name (d), 0, 0); convert_suffix_rule (dep_name (d), 0, 0);
f = d->file; if (d->file->cmds != 0)
if (f->cmds != 0)
/* Record a pattern for this suffix's null-suffix rule. */ /* Record a pattern for this suffix's null-suffix rule. */
convert_suffix_rule ("", dep_name (d), f->cmds); convert_suffix_rule ("", dep_name (d), d->file->cmds);
/* Record a pattern for each of this suffix's two-suffix rules. */ /* Add every other suffix to this one and see if it exists as a
two-suffix rule. */
slen = strlen (dep_name (d)); slen = strlen (dep_name (d));
memcpy (rulename, dep_name (d), slen); memcpy (rulename, dep_name (d), slen);
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{ {
struct file *f;
unsigned int s2len;
s2len = strlen (dep_name (d2)); s2len = strlen (dep_name (d2));
/* Can't build something from itself. */
if (slen == s2len && streq (dep_name (d), dep_name (d2))) if (slen == s2len && streq (dep_name (d), dep_name (d2)))
continue; continue;
@ -273,19 +274,18 @@ convert_to_pattern (void)
} }
/* Install the pattern rule RULE (whose fields have been filled in) /* Install the pattern rule RULE (whose fields have been filled in) at the end
at the end of the list (so that any rules previously defined of the list (so that any rules previously defined will take precedence).
will take precedence). If this rule duplicates a previous one If this rule duplicates a previous one (identical target and dependencies),
(identical target and dependencies), the old one is replaced the old one is replaced if OVERRIDE is nonzero, otherwise this new one is
if OVERRIDE is nonzero, otherwise this new one is thrown out. thrown out. When an old rule is replaced, the new one is put at the end of
When an old rule is replaced, the new one is put at the end of the the list. Return nonzero if RULE is used; zero if not. */
list. Return nonzero if RULE is used; zero if not. */
int static int
new_pattern_rule (struct rule *rule, int override) new_pattern_rule (struct rule *rule, int override)
{ {
register struct rule *r, *lastrule; struct rule *r, *lastrule;
register unsigned int i, j; unsigned int i, j;
rule->in_use = 0; rule->in_use = 0;
rule->terminal = 0; rule->terminal = 0;
@ -295,15 +295,15 @@ new_pattern_rule (struct rule *rule, int override)
/* Search for an identical rule. */ /* Search for an identical rule. */
lastrule = 0; lastrule = 0;
for (r = pattern_rules; r != 0; lastrule = r, r = r->next) for (r = pattern_rules; r != 0; lastrule = r, r = r->next)
for (i = 0; rule->targets[i] != 0; ++i) for (i = 0; i < rule->num; ++i)
{ {
for (j = 0; r->targets[j] != 0; ++j) for (j = 0; j < r->num; ++j)
if (!streq (rule->targets[i], r->targets[j])) if (!streq (rule->targets[i], r->targets[j]))
break; break;
if (r->targets[j] == 0) /* If all the targets matched... */
/* All the targets matched. */ if (j == r->num)
{ {
register struct dep *d, *d2; struct dep *d, *d2;
for (d = rule->deps, d2 = r->deps; for (d = rule->deps, d2 = r->deps;
d != 0 && d2 != 0; d = d->next, d2 = d2->next) d != 0 && d2 != 0; d = d->next, d2 = d2->next)
if (!streq (dep_name (d), dep_name (d2))) if (!streq (dep_name (d), dep_name (d2)))
@ -359,29 +359,21 @@ new_pattern_rule (struct rule *rule, int override)
void void
install_pattern_rule (struct pspec *p, int terminal) install_pattern_rule (struct pspec *p, int terminal)
{ {
register struct rule *r; struct rule *r;
char *ptr; char *ptr;
r = xmalloc (sizeof (struct rule)); r = xmalloc (sizeof (struct rule));
r->targets = xmalloc (2 * sizeof (char *)); r->num = 1;
r->suffixes = xmalloc (2 * sizeof (char *)); r->targets = xmalloc (sizeof (const char *));
r->lens = xmalloc (2 * sizeof (unsigned int)); r->suffixes = xmalloc (sizeof (const char *));
r->lens = xmalloc (sizeof (unsigned int));
r->targets[1] = 0;
r->suffixes[1] = 0;
r->lens[1] = 0;
r->lens[0] = strlen (p->target); r->lens[0] = strlen (p->target);
/* These will all be string literals, but we malloc space for r->targets[0] = p->target;
them anyway because somebody might want to free them later on. */ r->suffixes[0] = find_percent_cached (&r->targets[0]);
r->targets[0] = savestring (p->target, r->lens[0]); assert (r->suffixes[0] != NULL);
r->suffixes[0] = find_percent (r->targets[0]); ++r->suffixes[0];
if (r->suffixes[0] == 0)
/* Programmer-out-to-lunch error. */
abort ();
else
++r->suffixes[0];
ptr = p->dep; ptr = p->dep;
r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0', r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0',
@ -410,21 +402,12 @@ static void
freerule (struct rule *rule, struct rule *lastrule) freerule (struct rule *rule, struct rule *lastrule)
{ {
struct rule *next = rule->next; struct rule *next = rule->next;
register unsigned int i; struct dep *dep;
register struct dep *dep;
for (i = 0; rule->targets[i] != 0; ++i)
free (rule->targets[i]);
dep = rule->deps; dep = rule->deps;
while (dep) while (dep)
{ {
struct dep *t; struct dep *t = dep->next;
t = dep->next;
/* We might leak dep->name here, but I'm not sure how to fix this: I
think that pointer might be shared (e.g., in the file hash?) */
dep->name = 0; /* Make sure free_dep does not free name. */
free_dep (dep); free_dep (dep);
dep = t; dep = t;
} }
@ -457,51 +440,36 @@ freerule (struct rule *rule, struct rule *lastrule)
last_pattern_rule = lastrule; last_pattern_rule = lastrule;
} }
/* Create a new pattern rule with the targets in the nil-terminated /* Create a new pattern rule with the targets in the nil-terminated array
array TARGETS. If TARGET_PERCENTS is not nil, it is an array of TARGETS. TARGET_PERCENTS is an array of pointers to the % in each element
pointers into the elements of TARGETS, where the `%'s are. of TARGETS. N is the number of items in the array (not counting the nil
The new rule has dependencies DEPS and commands from COMMANDS. element). The new rule has dependencies DEPS and commands from COMMANDS.
It is a terminal rule if TERMINAL is nonzero. This rule overrides It is a terminal rule if TERMINAL is nonzero. This rule overrides
identical rules with different commands if OVERRIDE is nonzero. identical rules with different commands if OVERRIDE is nonzero.
The storage for TARGETS and its elements is used and must not be freed The storage for TARGETS and its elements and TARGET_PERCENTS is used and
until the rule is destroyed. The storage for TARGET_PERCENTS is not used; must not be freed until the rule is destroyed. */
it may be freed. */
void void
create_pattern_rule (char **targets, char **target_percents, create_pattern_rule (const char **targets, const char **target_percents,
int terminal, struct dep *deps, unsigned int n, int terminal, struct dep *deps,
struct commands *commands, int override) struct commands *commands, int override)
{ {
unsigned int max_targets, i; unsigned int i;
struct rule *r = xmalloc (sizeof (struct rule)); struct rule *r = xmalloc (sizeof (struct rule));
r->num = n;
r->cmds = commands; r->cmds = commands;
r->deps = deps; r->deps = deps;
r->targets = targets; r->targets = targets;
r->suffixes = target_percents;
r->lens = xmalloc (n * sizeof (unsigned int));
max_targets = 2; for (i = 0; i < n; ++i)
r->lens = xmalloc (2 * sizeof (unsigned int));
r->suffixes = xmalloc (2 * sizeof (char *));
for (i = 0; targets[i] != 0; ++i)
{ {
if (i == max_targets - 1)
{
max_targets += 5;
r->lens = xrealloc (r->lens, max_targets * sizeof (unsigned int));
r->suffixes = xrealloc (r->suffixes, max_targets * sizeof (char *));
}
r->lens[i] = strlen (targets[i]); r->lens[i] = strlen (targets[i]);
r->suffixes[i] = (target_percents == 0 ? find_percent (targets[i]) assert (r->suffixes[i] != NULL);
: target_percents[i]) + 1; ++r->suffixes[i];
if (r->suffixes[i] == 0)
abort ();
}
if (i < max_targets - 1)
{
r->lens = xrealloc (r->lens, (i + 1) * sizeof (unsigned int));
r->suffixes = xrealloc (r->suffixes, (i + 1) * sizeof (char *));
} }
if (new_pattern_rule (r, override)) if (new_pattern_rule (r, override))
@ -513,16 +481,13 @@ create_pattern_rule (char **targets, char **target_percents,
static void /* Useful to call from gdb. */ static void /* Useful to call from gdb. */
print_rule (struct rule *r) print_rule (struct rule *r)
{ {
register unsigned int i; unsigned int i;
register struct dep *d; struct dep *d;
for (i = 0; r->targets[i] != 0; ++i) for (i = 0; i < r->num; ++i)
{ {
fputs (r->targets[i], stdout); fputs (r->targets[i], stdout);
if (r->targets[i + 1] != 0) putchar ((i + 1 == r->num) ? ':' : ' ');
putchar (' ');
else
putchar (':');
} }
if (r->terminal) if (r->terminal)
putchar (':'); putchar (':');
@ -538,8 +503,8 @@ print_rule (struct rule *r)
void void
print_rule_data_base (void) print_rule_data_base (void)
{ {
register unsigned int rules, terminal; unsigned int rules, terminal;
register struct rule *r; struct rule *r;
puts (_("\n# Implicit Rules")); puts (_("\n# Implicit Rules"));

15
rule.h
View File

@ -16,16 +16,18 @@ 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 GNU Make; see the file COPYING. If not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
/* Structure used for pattern rules. */
/* Structure used for pattern (implicit) rules. */
struct rule struct rule
{ {
struct rule *next; struct rule *next;
char **targets; /* Targets of the rule. */ const char **targets; /* Targets of the rule. */
unsigned int *lens; /* Lengths of each target. */ unsigned int *lens; /* Lengths of each target. */
char **suffixes; /* Suffixes (after `%') of each target. */ const char **suffixes; /* Suffixes (after `%') of each target. */
struct dep *deps; /* Dependencies of the rule. */ struct dep *deps; /* Dependencies of the rule. */
struct commands *cmds; /* Commands to execute. */ struct commands *cmds; /* Commands to execute. */
unsigned short num; /* Number of targets. */
char terminal; /* If terminal (double-colon). */ char terminal; /* If terminal (double-colon). */
char in_use; /* If in use by a parent pattern_search. */ char in_use; /* If in use by a parent pattern_search. */
}; };
@ -49,10 +51,9 @@ extern struct file *suffix_file;
extern unsigned int maxsuffix; extern unsigned int maxsuffix;
void install_pattern_rule (struct pspec *p, int terminal);
int new_pattern_rule (struct rule *rule, int override);
void count_implicit_rule_limits (void); void count_implicit_rule_limits (void);
void convert_to_pattern (void); void convert_to_pattern (void);
void create_pattern_rule (char **targets, char **target_percents, void install_pattern_rule (struct pspec *p, int terminal);
int terminal, struct dep *deps, void create_pattern_rule (const char **targets, const char **target_percents,
unsigned int num, int terminal, struct dep *deps,
struct commands *commands, int override); struct commands *commands, int override);

View File

@ -20,8 +20,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
#include "hash.h" #include "hash.h"
/* The size (in bytes) of each cache buffer. */ /* The size (in bytes) of each cache buffer.
#define CACHE_BUFFER_SIZE (4096) Try to pick something that will map well into the heap. */
#define CACHE_BUFFER_SIZE (8192 - 16)
/* A string cached here will never be freed, so we don't need to worry about /* A string cached here will never be freed, so we don't need to worry about
@ -39,6 +40,11 @@ struct strcache {
static int bufsize = CACHE_BUFFER_SIZE; static int bufsize = CACHE_BUFFER_SIZE;
static struct strcache *strcache = NULL; static struct strcache *strcache = NULL;
/* Add a new buffer to the cache. Add it at the front to reduce search time.
This can also increase the overhead, since it's less likely that older
buffers will be filled in. However, GNU make has so many smaller strings
that this doesn't seem to be much of an issue in practice.
*/
static struct strcache * static struct strcache *
new_cache() new_cache()
{ {
@ -61,9 +67,9 @@ add_string(const char *str, int len)
struct strcache *sp; struct strcache *sp;
const char *res; const char *res;
/* If the string we want is too large to fit into a single buffer, then we're /* If the string we want is too large to fit into a single buffer, then
screwed; nothing will ever fit! Change the maximum size of the cache to we're screwed; nothing will ever fit! Change the maximum size of the
be big enough. */ cache to be big enough. */
if (len > bufsize) if (len > bufsize)
bufsize = len * 2; bufsize = len * 2;
@ -113,6 +119,7 @@ str_hash_cmp (const void *x, const void *y)
} }
static struct hash_table strings; static struct hash_table strings;
static unsigned long total_adds = 0;
static const char * static const char *
add_hash (const char *str, int len) add_hash (const char *str, int len)
@ -121,6 +128,9 @@ add_hash (const char *str, int len)
char *const *slot = (char *const *) hash_find_slot (&strings, str); char *const *slot = (char *const *) hash_find_slot (&strings, str);
const char *key = *slot; const char *key = *slot;
/* Count the total number of adds we performed. */
++total_adds;
if (!HASH_VACANT (key)) if (!HASH_VACANT (key))
return key; return key;
@ -179,7 +189,7 @@ strcache_setbufsize(int size)
void void
strcache_init (void) strcache_init (void)
{ {
hash_init (&strings, 1000, str_hash_1, str_hash_2, str_hash_cmp); hash_init (&strings, 8000, str_hash_1, str_hash_2, str_hash_cmp);
} }
@ -191,32 +201,46 @@ strcache_print_stats (const char *prefix)
int numbuffs = 0, numstrs = 0; int numbuffs = 0, numstrs = 0;
int totsize = 0, avgsize, maxsize = 0, minsize = bufsize; int totsize = 0, avgsize, maxsize = 0, minsize = bufsize;
int totfree = 0, avgfree, maxfree = 0, minfree = bufsize; int totfree = 0, avgfree, maxfree = 0, minfree = bufsize;
const struct strcache *sp; int lastused = 0, lastfree = 0;
for (sp = strcache; sp != NULL; sp = sp->next) if (strcache)
{ {
int bf = sp->bytesfree; const struct strcache *sp;
int sz = (sp->end - sp->buffer) + bf;
++numbuffs; /* Count the first buffer separately since it's not full. */
numstrs += sp->count; lastused = strcache->end - strcache->buffer;
lastfree = strcache->bytesfree;
totsize += sz; for (sp = strcache->next; sp != NULL; sp = sp->next)
maxsize = (sz > maxsize ? sz : maxsize); {
minsize = (sz < minsize ? sz : minsize); int bf = sp->bytesfree;
int sz = sp->end - sp->buffer;
totfree += bf; ++numbuffs;
maxfree = (bf > maxfree ? bf : maxfree); numstrs += sp->count;
minfree = (bf < minfree ? bf : minfree);
totsize += sz;
maxsize = (sz > maxsize ? sz : maxsize);
minsize = (sz < minsize ? sz : minsize);
totfree += bf;
maxfree = (bf > maxfree ? bf : maxfree);
minfree = (bf < minfree ? bf : minfree);
}
} }
avgsize = numbuffs ? (int)(totsize / numbuffs) : 0; avgsize = numbuffs ? (int)(totsize / numbuffs) : 0;
avgfree = numbuffs ? (int)(totfree / numbuffs) : 0; avgfree = numbuffs ? (int)(totfree / numbuffs) : 0;
printf (_("\n%s # of strings in strcache: %d\n"), prefix, numstrs); printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"),
printf (_("%s # of strcache buffers: %d\n"), prefix, numbuffs); prefix, numstrs, total_adds, (total_adds - numstrs));
printf (_("%s strcache size: total = %d / max = %d / min = %d / avg = %d\n"), printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"),
prefix, totsize, maxsize, minsize, avgsize); prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize));
printf (_("%s strcache free: total = %d / max = %d / min = %d / avg = %d\n"), printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
prefix, totfree, maxfree, minfree, avgfree); prefix, totsize, lastused, maxsize, minsize, avgsize);
printf (_("%s strcache free: total = %d (%d) / max = %d / min = %d / avg = %d\n"),
prefix, totfree, lastfree, maxfree, minfree, avgfree);
fputs (_("\n# strcache hash-table stats:\n# "), stdout);
hash_print_stats (&strings, stdout);
} }

View File

@ -190,7 +190,8 @@ sub run_make_with_options {
sub print_usage sub print_usage
{ {
&print_standard_usage ("run_make_tests", "[-make_path make_pathname]"); &print_standard_usage ("run_make_tests",
"[-make_path make_pathname] [-valgrind]",);
} }
sub print_help sub print_help

View File

@ -10,9 +10,9 @@ $dir = cwd;
$dir =~ s,.*/([^/]+)$,../$1,; $dir =~ s,.*/([^/]+)$,../$1,;
# TEST #1: Make sure that multiple patterns where the same target # TEST #0: Make sure that multiple patterns where the same target
# can be built are searched even if the first one fails # can be built are searched even if the first one fails
# to match properly. # to match properly.
# #
run_make_test(' run_make_test('
@ -45,7 +45,7 @@ a: void
'', '',
''); '');
# TEST #2: make sure files that are built via implicit rules are marked # TEST #1: make sure files that are built via implicit rules are marked
# as targets (Savannah bug #12202). # as targets (Savannah bug #12202).
# #
run_make_test(' run_make_test('
@ -69,7 +69,7 @@ foo.in: ; @:
foo.out'); foo.out');
# TEST #3: make sure intermidite files that also happened to be # TEST #2: make sure intermediate files that also happened to be
# prerequisites are not removed (Savannah bug #12267). # prerequisites are not removed (Savannah bug #12267).
# #
run_make_test(' run_make_test('
@ -96,7 +96,7 @@ $dir/foo.o");
unlink("$dir/foo.c"); unlink("$dir/foo.c");
# TEST #4: make sure precious flag is set properly for targets # TEST #3: make sure precious flag is set properly for targets
# that are built via implicit rules (Savannah bug #13218). # that are built via implicit rules (Savannah bug #13218).
# #
run_make_test(' run_make_test('
@ -116,7 +116,7 @@ $(dir)/foo.bar:
unlink("$dir/foo.bar"); unlink("$dir/foo.bar");
# TEST #5: make sure targets of a macthed implicit pattern rule never # TEST #4: make sure targets of a matched implicit pattern rule are
# never considered intermediate (Savannah bug #13022). # never considered intermediate (Savannah bug #13022).
# #
run_make_test(' run_make_test('

View File

@ -547,12 +547,10 @@ sub print_standard_usage
local($plname,@moreusage) = @_; local($plname,@moreusage) = @_;
local($line); local($line);
print "Usage: perl $plname [testname] [-verbose] [-detail] [-keep]\n"; print "usage:\t$plname [testname] [-verbose] [-detail] [-keep]\n";
print " [-profile] [-usage] [-help] " print "\t\t\t[-profile] [-usage] [-help] [-debug]\n";
. "[-debug]\n"; foreach (@moreusage) {
foreach $line (@moreusage) print "\t\t\t$_\n";
{
print " $line\n";
} }
} }

View File

@ -42,7 +42,7 @@ static struct pattern_var *last_pattern_var;
/* Create a new pattern-specific variable struct. */ /* Create a new pattern-specific variable struct. */
struct pattern_var * struct pattern_var *
create_pattern_var (char *target, char *suffix) create_pattern_var (const char *target, const char *suffix)
{ {
register struct pattern_var *p = xmalloc (sizeof (struct pattern_var)); register struct pattern_var *p = xmalloc (sizeof (struct pattern_var));
@ -63,14 +63,14 @@ create_pattern_var (char *target, char *suffix)
/* Look up a target in the pattern-specific variable list. */ /* Look up a target in the pattern-specific variable list. */
static struct pattern_var * static struct pattern_var *
lookup_pattern_var (struct pattern_var *start, char *target) lookup_pattern_var (struct pattern_var *start, const char *target)
{ {
struct pattern_var *p; struct pattern_var *p;
unsigned int targlen = strlen(target); unsigned int targlen = strlen(target);
for (p = start ? start->next : pattern_vars; p != 0; p = p->next) for (p = start ? start->next : pattern_vars; p != 0; p = p->next)
{ {
char *stem; const char *stem;
unsigned int stemlen; unsigned int stemlen;
if (p->len > targlen) if (p->len > targlen)
@ -962,7 +962,7 @@ target_environment (struct file *file)
strcmp(v->name, "PATH") == 0) strcmp(v->name, "PATH") == 0)
convert_Path_to_windows32(value, ';'); convert_Path_to_windows32(value, ';');
#endif #endif
*result++ = concat (v->name, "=", value); *result++ = xstrdup (concat (v->name, "=", value));
free (value); free (value);
} }
else else
@ -972,7 +972,7 @@ target_environment (struct file *file)
strcmp(v->name, "PATH") == 0) strcmp(v->name, "PATH") == 0)
convert_Path_to_windows32(v->value, ';'); convert_Path_to_windows32(v->value, ';');
#endif #endif
*result++ = concat (v->name, "=", v->value); *result++ = xstrdup (concat (v->name, "=", v->value));
} }
} }
@ -990,10 +990,11 @@ target_environment (struct file *file)
struct variable * struct variable *
do_variable_definition (const struct floc *flocp, const char *varname, do_variable_definition (const struct floc *flocp, const char *varname,
char *value, enum variable_origin origin, const char *value, enum variable_origin origin,
enum variable_flavor flavor, int target_var) enum variable_flavor flavor, int target_var)
{ {
char *p, *alloc_value = NULL; const char *p;
char *alloc_value = NULL;
struct variable *v; struct variable *v;
int append = 0; int append = 0;
int conditional = 0; int conditional = 0;
@ -1058,7 +1059,8 @@ do_variable_definition (const struct floc *flocp, const char *varname,
/* Paste the old and new values together in VALUE. */ /* Paste the old and new values together in VALUE. */
unsigned int oldlen, vallen; unsigned int oldlen, vallen;
char *val; const char *val;
char *tp;
val = value; val = value;
if (v->recursive) if (v->recursive)
@ -1075,10 +1077,11 @@ do_variable_definition (const struct floc *flocp, const char *varname,
oldlen = strlen (v->value); oldlen = strlen (v->value);
vallen = strlen (val); vallen = strlen (val);
p = alloca (oldlen + 1 + vallen + 1); tp = alloca (oldlen + 1 + vallen + 1);
memcpy (p, v->value, oldlen); memcpy (tp, v->value, oldlen);
p[oldlen] = ' '; tp[oldlen] = ' ';
memcpy (&p[oldlen + 1], val, vallen + 1); memcpy (&tp[oldlen + 1], val, vallen + 1);
p = tp;
} }
} }
} }
@ -1106,20 +1109,19 @@ do_variable_definition (const struct floc *flocp, const char *varname,
/* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */ /* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */
if (__dosexec_find_on_path (p, NULL, shellpath)) if (__dosexec_find_on_path (p, NULL, shellpath))
{ {
char *p; char *tp;
for (tp = shellpath; *tp; tp++)
if (*tp == '\\')
*tp = '/';
for (p = shellpath; *p; p++)
{
if (*p == '\\')
*p = '/';
}
v = define_variable_loc (varname, strlen (varname), v = define_variable_loc (varname, strlen (varname),
shellpath, origin, flavor == f_recursive, shellpath, origin, flavor == f_recursive,
flocp); flocp);
} }
else else
{ {
char *shellbase, *bslash; const char *shellbase, *bslash;
struct variable *pathv = lookup_variable ("PATH", 4); struct variable *pathv = lookup_variable ("PATH", 4);
char *path_string; char *path_string;
char *fake_env[2]; char *fake_env[2];
@ -1147,13 +1149,12 @@ do_variable_definition (const struct floc *flocp, const char *varname,
fake_env[1] = 0; fake_env[1] = 0;
if (__dosexec_find_on_path (shellbase, fake_env, shellpath)) if (__dosexec_find_on_path (shellbase, fake_env, shellpath))
{ {
char *p; char *tp;
for (tp = shellpath; *tp; tp++)
if (*tp == '\\')
*tp = '/';
for (p = shellpath; *p; p++)
{
if (*p == '\\')
*p = '/';
}
v = define_variable_loc (varname, strlen (varname), v = define_variable_loc (varname, strlen (varname),
shellpath, origin, shellpath, origin,
flavor == f_recursive, flocp); flavor == f_recursive, flocp);
@ -1473,7 +1474,7 @@ print_variable_data_base (void)
/* Print all the local variables of FILE. */ /* Print all the local variables of FILE. */
void void
print_file_variables (struct file *file) print_file_variables (const struct file *file)
{ {
if (file->variables != 0) if (file->variables != 0)
print_variable_set (file->variables->set, "# "); print_variable_set (file->variables->set, "# ");
@ -1500,7 +1501,7 @@ sync_Path_environment (void)
* Create something WINDOWS32 world can grok * Create something WINDOWS32 world can grok
*/ */
convert_Path_to_windows32 (path, ';'); convert_Path_to_windows32 (path, ';');
environ_path = concat ("PATH", "=", path); environ_path = xstrdup (concat ("PATH", "=", path));
putenv (environ_path); putenv (environ_path);
free (path); free (path);
} }

View File

@ -99,9 +99,9 @@ struct variable_set_list
struct pattern_var struct pattern_var
{ {
struct pattern_var *next; struct pattern_var *next;
char *target; const char *suffix;
const char *target;
unsigned int len; unsigned int len;
char *suffix;
struct variable variable; struct variable variable;
}; };
@ -123,10 +123,13 @@ void restore_variable_buffer (char *buf, unsigned int len);
/* function.c */ /* function.c */
int handle_function (char **op, const char **stringp); int handle_function (char **op, const char **stringp);
int pattern_matches (const char *pattern, const char *percent, const char *str); int pattern_matches (const char *pattern, const char *percent, const char *str);
char *subst_expand (char *o, char *text, char *subst, char *replace, char *subst_expand (char *o, const char *text, const char *subst,
unsigned int slen, unsigned int rlen, int by_word); const char *replace, unsigned int slen, unsigned int rlen,
char *patsubst_expand (char *o, char *text, char *pattern, char *replace, int by_word);
char *pattern_percent, char *replace_percent); char *patsubst_expand_pat (char *o, const char *text, const char *pattern,
const char *replace, const char *pattern_percent,
const char *replace_percent);
char *patsubst_expand (char *o, const char *text, char *pattern, char *replace);
/* expand.c */ /* expand.c */
char *recursively_expand_for_file (struct variable *v, struct file *file); char *recursively_expand_for_file (struct variable *v, struct file *file);
@ -139,12 +142,12 @@ struct variable_set_list *push_new_variable_scope (void);
void pop_variable_scope (void); void pop_variable_scope (void);
void define_automatic_variables (void); void define_automatic_variables (void);
void initialize_file_variables (struct file *file, int reading); void initialize_file_variables (struct file *file, int reading);
void print_file_variables (struct file *file); void print_file_variables (const struct file *file);
void print_variable_set (struct variable_set *set, char *prefix); void print_variable_set (struct variable_set *set, char *prefix);
void merge_variable_set_lists (struct variable_set_list **to_list, void merge_variable_set_lists (struct variable_set_list **to_list,
struct variable_set_list *from_list); struct variable_set_list *from_list);
struct variable *do_variable_definition (const struct floc *flocp, struct variable *do_variable_definition (const struct floc *flocp,
const char *name, char *value, const char *name, const char *value,
enum variable_origin origin, enum variable_origin origin,
enum variable_flavor flavor, enum variable_flavor flavor,
int target_var); int target_var);
@ -198,7 +201,8 @@ struct variable *define_variable_in_set (const char *name, unsigned int length,
char **target_environment (struct file *file); char **target_environment (struct file *file);
struct pattern_var *create_pattern_var (char *target, char *suffix); struct pattern_var *create_pattern_var (const char *target,
const char *suffix);
extern int export_all_variables; extern int export_all_variables;

171
vpath.c
View File

@ -48,12 +48,10 @@ static struct vpath *general_vpath;
static struct vpath *gpaths; static struct vpath *gpaths;
static int selective_vpath_search (struct vpath *path, char **file,
FILE_TIMESTAMP *mtime_ptr);
/* Reverse the chain of selective VPATH lists so they /* Reverse the chain of selective VPATH lists so they will be searched in the
will be searched in the order given in the makefiles order given in the makefiles and construct the list from the VPATH
and construct the list from the VPATH variable. */ variable. */
void void
build_vpath_lists () build_vpath_lists ()
@ -284,8 +282,8 @@ construct_vpath_list (char *pattern, char *dirpath)
/* Set up the members. */ /* Set up the members. */
path->pattern = strcache_add (pattern); path->pattern = strcache_add (pattern);
path->percent = path->pattern + (percent - pattern);
path->patlen = strlen (pattern); path->patlen = strlen (pattern);
path->percent = percent ? path->pattern + (percent - pattern) : 0;
} }
else else
/* There were no entries, so free whatever space we allocated. */ /* There were no entries, so free whatever space we allocated. */
@ -308,57 +306,23 @@ gpath_search (const char *file, unsigned int len)
return 0; return 0;
} }
/* Search the VPATH list whose pattern matches *FILE for a directory
where the name pointed to by FILE exists. If it is found, we set *FILE to
the newly malloc'd name of the existing file, *MTIME_PTR (if MTIME_PTR is
not NULL) to its modtime (or zero if no stat call was done), and return 1.
Otherwise we return 0. */
int /* Search the given VPATH list for a directory where the name pointed to by
vpath_search (char **file, FILE_TIMESTAMP *mtime_ptr) FILE exists. If it is found, we return a cached name of the existing file
{ and set *MTIME_PTR (if MTIME_PTR is not NULL) to its modtime (or zero if no
struct vpath *v; stat call was done). Otherwise we return NULL. */
/* If there are no VPATH entries or FILENAME starts at the root, static const char *
there is nothing we can do. */ selective_vpath_search (struct vpath *path, const char *file,
if (**file == '/'
#ifdef HAVE_DOS_PATHS
|| **file == '\\'
|| (*file)[1] == ':'
#endif
|| (vpaths == 0 && general_vpath == 0))
return 0;
for (v = vpaths; v != 0; v = v->next)
if (pattern_matches (v->pattern, v->percent, *file))
if (selective_vpath_search (v, file, mtime_ptr))
return 1;
if (general_vpath != 0
&& selective_vpath_search (general_vpath, file, mtime_ptr))
return 1;
return 0;
}
/* Search the given VPATH list for a directory where the name pointed
to by FILE exists. If it is found, we set *FILE to the newly malloc'd
name of the existing file, *MTIME_PTR (if MTIME_PTR is not NULL) to
its modtime (or zero if no stat call was done), and we return 1.
Otherwise we return 0. */
static int
selective_vpath_search (struct vpath *path, char **file,
FILE_TIMESTAMP *mtime_ptr) FILE_TIMESTAMP *mtime_ptr)
{ {
int not_target; int not_target;
char *name, *n; char *name;
char *filename; const char *n;
const char *filename;
const char **vpath = path->searchpath; const char **vpath = path->searchpath;
unsigned int maxvpath = path->maxlen; unsigned int maxvpath = path->maxlen;
register unsigned int i; unsigned int i;
unsigned int flen, vlen, name_dplen; unsigned int flen, vlen, name_dplen;
int exists = 0; int exists = 0;
@ -366,73 +330,73 @@ selective_vpath_search (struct vpath *path, char **file,
If and only if it is NOT a target, we will accept prospective If and only if it is NOT a target, we will accept prospective
files that don't exist but are mentioned in a makefile. */ files that don't exist but are mentioned in a makefile. */
{ {
struct file *f = lookup_file (*file); struct file *f = lookup_file (file);
not_target = f == 0 || !f->is_target; not_target = f == 0 || !f->is_target;
} }
flen = strlen (*file); flen = strlen (file);
/* Split *FILE into a directory prefix and a name-within-directory. /* Split *FILE into a directory prefix and a name-within-directory.
NAME_DPLEN gets the length of the prefix; FILENAME gets the NAME_DPLEN gets the length of the prefix; FILENAME gets the pointer to
pointer to the name-within-directory and FLEN is its length. */ the name-within-directory and FLEN is its length. */
n = strrchr (*file, '/'); n = strrchr (file, '/');
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* We need the rightmost slash or backslash. */ /* We need the rightmost slash or backslash. */
{ {
char *bslash = strrchr(*file, '\\'); const char *bslash = strrchr(file, '\\');
if (!n || bslash > n) if (!n || bslash > n)
n = bslash; n = bslash;
} }
#endif #endif
name_dplen = n != 0 ? n - *file : 0; name_dplen = n != 0 ? n - file : 0;
filename = name_dplen > 0 ? n + 1 : *file; filename = name_dplen > 0 ? n + 1 : file;
if (name_dplen > 0) if (name_dplen > 0)
flen -= name_dplen + 1; flen -= name_dplen + 1;
/* Allocate enough space for the biggest VPATH entry, /* Get enough space for the biggest VPATH entry, a slash, the directory
a slash, the directory prefix that came with *FILE, prefix that came with FILE, another slash (although this one may not
another slash (although this one may not always be always be necessary), the filename, and a null terminator. */
necessary), the filename, and a null terminator. */ name = alloca (maxvpath + 1 + name_dplen + 1 + flen + 1);
name = xmalloc (maxvpath + 1 + name_dplen + 1 + flen + 1);
/* Try each VPATH entry. */ /* Try each VPATH entry. */
for (i = 0; vpath[i] != 0; ++i) for (i = 0; vpath[i] != 0; ++i)
{ {
int exists_in_cache = 0; int exists_in_cache = 0;
char *p;
n = name; p = name;
/* Put the next VPATH entry into NAME at N and increment N past it. */ /* Put the next VPATH entry into NAME at P and increment P past it. */
vlen = strlen (vpath[i]); vlen = strlen (vpath[i]);
memcpy (n, vpath[i], vlen); memcpy (p, vpath[i], vlen);
n += vlen; p += vlen;
/* Add the directory prefix already in *FILE. */ /* Add the directory prefix already in *FILE. */
if (name_dplen > 0) if (name_dplen > 0)
{ {
#ifndef VMS #ifndef VMS
*n++ = '/'; *p++ = '/';
#endif #endif
memcpy (n, *file, name_dplen); memcpy (p, file, name_dplen);
n += name_dplen; p += name_dplen;
} }
#ifdef HAVE_DOS_PATHS #ifdef HAVE_DOS_PATHS
/* Cause the next if to treat backslash and slash alike. */ /* Cause the next if to treat backslash and slash alike. */
if (n != name && n[-1] == '\\' ) if (p != name && p[-1] == '\\' )
n[-1] = '/'; p[-1] = '/';
#endif #endif
/* Now add the name-within-directory at the end of NAME. */ /* Now add the name-within-directory at the end of NAME. */
#ifndef VMS #ifndef VMS
if (n != name && n[-1] != '/') if (p != name && p[-1] != '/')
{ {
*n = '/'; *p = '/';
memcpy (n + 1, filename, flen + 1); memcpy (p + 1, filename, flen + 1);
} }
else else
#endif #endif
memcpy (n, filename, flen + 1); memcpy (p, filename, flen + 1);
/* Check if the file is mentioned in a makefile. If *FILE is not /* Check if the file is mentioned in a makefile. If *FILE is not
a target, that is enough for us to decide this file exists. a target, that is enough for us to decide this file exists.
@ -479,7 +443,7 @@ selective_vpath_search (struct vpath *path, char **file,
#else #else
/* Clobber a null into the name at the last slash. /* Clobber a null into the name at the last slash.
Now NAME is the name of the directory to look in. */ Now NAME is the name of the directory to look in. */
*n = '\0'; *p = '\0';
/* We know the directory is in the hash table now because either /* We know the directory is in the hash table now because either
construct_vpath_list or the code just above put it there. construct_vpath_list or the code just above put it there.
@ -500,7 +464,7 @@ selective_vpath_search (struct vpath *path, char **file,
#ifndef VMS #ifndef VMS
/* Put the slash back in NAME. */ /* Put the slash back in NAME. */
*n = '/'; *p = '/';
#endif #endif
if (exists_in_cache) /* Makefile-mentioned file need not exist. */ if (exists_in_cache) /* Makefile-mentioned file need not exist. */
@ -523,21 +487,56 @@ selective_vpath_search (struct vpath *path, char **file,
} }
/* We have found a file. /* We have found a file.
Store the name we found into *FILE for the caller. */ If we get here and mtime_ptr hasn't been set, record
*file = savestring (name, (n + 1 - name) + flen);
/* If we get here and mtime_ptr hasn't been set, record
UNKNOWN_MTIME to indicate this. */ UNKNOWN_MTIME to indicate this. */
if (mtime_ptr != 0) if (mtime_ptr != 0)
*mtime_ptr = UNKNOWN_MTIME; *mtime_ptr = UNKNOWN_MTIME;
free (name); /* Store the name we found and return it. */
return 1;
return strcache_add_len (name, (p + 1 - name) + flen);
} }
} }
free (name); return 0;
}
/* Search the VPATH list whose pattern matches FILE for a directory where FILE
exists. If it is found, return the cached name of an existing file, and
set *MTIME_PTR (if MTIME_PTR is not NULL) to its modtime (or zero if no
stat call was done). Otherwise we return 0. */
const char *
vpath_search (const char *file, FILE_TIMESTAMP *mtime_ptr)
{
struct vpath *v;
/* If there are no VPATH entries or FILENAME starts at the root,
there is nothing we can do. */
if (file[0] == '/'
#ifdef HAVE_DOS_PATHS
|| file[0] == '\\' || file[1] == ':'
#endif
|| (vpaths == 0 && general_vpath == 0))
return 0;
for (v = vpaths; v != 0; v = v->next)
if (pattern_matches (v->pattern, v->percent, file))
{
const char *p = selective_vpath_search (v, file, mtime_ptr);
if (p)
return p;
}
if (general_vpath != 0)
{
const char *p = selective_vpath_search (general_vpath, file, mtime_ptr);
if (p)
return p;
}
return 0; return 0;
} }