diff options
author | Paul Smith <psmith@gnu.org> | 2007-03-20 03:02:26 +0000 |
---|---|---|
committer | Paul Smith <psmith@gnu.org> | 2007-03-20 03:02:26 +0000 |
commit | 6ccf33cdbdfda2aea5d51e4d4991881c74d853d1 (patch) | |
tree | ce963770c6d0dc0428a6bce65d96da4b710e2831 | |
parent | e4da30858037b431880263676e8f90b1f8412a38 (diff) | |
download | gunmake-6ccf33cdbdfda2aea5d51e4d4991881c74d853d1.tar.gz |
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.
-rw-r--r-- | ChangeLog | 24 | ||||
-rw-r--r-- | ar.c | 63 | ||||
-rw-r--r-- | commands.c | 4 | ||||
-rw-r--r-- | default.c | 10 | ||||
-rw-r--r-- | dep.h | 15 | ||||
-rw-r--r-- | dir.c | 22 | ||||
-rw-r--r-- | expand.c | 8 | ||||
-rw-r--r-- | file.c | 410 | ||||
-rw-r--r-- | filedef.h | 18 | ||||
-rw-r--r-- | function.c | 366 | ||||
-rw-r--r-- | implicit.c | 119 | ||||
-rw-r--r-- | job.c | 4 | ||||
-rw-r--r-- | main.c | 177 | ||||
-rw-r--r-- | maintMakefile | 28 | ||||
-rw-r--r-- | make.h | 15 | ||||
-rw-r--r-- | misc.c | 101 | ||||
-rw-r--r-- | read.c | 457 | ||||
-rw-r--r-- | remake.c | 67 | ||||
-rw-r--r-- | rule.c | 241 | ||||
-rw-r--r-- | rule.h | 15 | ||||
-rw-r--r-- | strcache.c | 72 | ||||
-rwxr-xr-x | tests/run_make_tests.pl | 3 | ||||
-rw-r--r-- | tests/scripts/features/patternrules | 14 | ||||
-rw-r--r-- | tests/test_driver.pl | 10 | ||||
-rw-r--r-- | variable.c | 55 | ||||
-rw-r--r-- | variable.h | 22 | ||||
-rw-r--r-- | vpath.c | 171 |
27 files changed, 1266 insertions, 1245 deletions
@@ -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> * strcache.c (strcache_add_len): Don't allocate a new buffer unless the string is not already nil-terminated. Technically this 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 - 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'. @@ -24,6 +45,7 @@ * vmsify.c: Constification. Hard to test this but I hope I didn't screw it up! * vpath.c: Partial constification. + * w32/pathstuff.c: Partial constification. 2006-11-16 Eli Zaretskii <eliz@gnu.org> @@ -50,19 +50,19 @@ ar_name (const char *name) /* 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; - put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */ + Creates one allocated string containing both names, pointed to by ARNAME_P. + MEMNAME_P points to the member. */ void 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 = savestring (name, p - name); - - if (memname_p != 0) - *memname_p = savestring (p + 1, end - (p + 1)); + *arname_p = xstrdup (name); + p = strchr (*arname_p, '('); + *(p++) = '\0'; + p[strlen(p) - 1] = '\0'; + *memname_p = p; } @@ -86,7 +86,6 @@ ar_member_date (const char *name) { char *arname; char *memname; - int arname_used = 0; long int val; ar_parse_name (name, &arname, &memname); @@ -102,10 +101,7 @@ ar_member_date (const char *name) struct file *arfile; arfile = lookup_file (arname); if (arfile == 0 && file_exists_p (arname)) - { - arfile = enter_file (arname); - arname_used = 1; - } + arfile = enter_file (strcache_add (arname)); if (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); - if (!arname_used) - free (arname); - free (memname); + free (arname); return (val <= 0 ? (time_t) -1 : (time_t) val); } @@ -134,23 +128,16 @@ int ar_touch (const char *name) { char *arname, *memname; - int arname_used = 0; - register int val; + int val; ar_parse_name (name, &arname, &memname); /* 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; - arfile = lookup_file (arname); - if (arfile == 0) - { - arfile = enter_file (arname); - arname_used = 1; - } - - (void) f_mtime (arfile, 0); + arfile = enter_file (strcache_add (arname)); + f_mtime (arfile, 0); } val = 1; @@ -177,9 +164,7 @@ ar_touch (const char *name) _("touch: Bad return code from ar_member_touch on `%s'"), name); } - if (!arname_used) - free (arname); - free (memname); + free (arname); return val; } @@ -189,7 +174,7 @@ ar_touch (const char *name) struct ar_glob_state { - char *arname; + const char *arname; const char *pattern; unsigned int size; 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. */ struct nameseq *new = xmalloc (state->size); - new->name = concat (state->arname, mem, ")"); + new->name = strcache_add (concat (state->arname, mem, ")")); new->next = state->chain; state->chain = new; ++state->n; @@ -260,8 +245,9 @@ struct nameseq * ar_glob (const char *arname, const char *member_pattern, unsigned int size) { struct ar_glob_state state; - char **names; struct nameseq *n; + const char **names; + char *name; unsigned int i; 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. ar_glob_match will accumulate them in STATE.chain. */ i = strlen (arname); - state.arname = alloca (i + 2); - memcpy (state.arname, arname, i); - state.arname[i] = '('; - state.arname[i + 1] = '\0'; + name = alloca (i + 2); + memcpy (name, arname, i); + name[i] = '('; + name[i + 1] = '\0'; + state.arname = name; state.pattern = member_pattern; state.size = size; state.chain = 0; @@ -284,7 +271,7 @@ ar_glob (const char *arname, const char *member_pattern, unsigned int size) return 0; /* Now put the names into a vector for sorting. */ - names = alloca (state.n * sizeof (char *)); + names = alloca (state.n * sizeof (const char *)); i = 0; for (n = state.chain; n != 0; n = n->next) names[i++] = n->name; @@ -97,12 +97,12 @@ set_file_variables (struct file *file) 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)); 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; } } @@ -522,23 +522,23 @@ static const char *default_variables[] = void set_default_suffixes (void) { - suffix_file = enter_file (".SUFFIXES"); + suffix_file = enter_file (strcache_add (".SUFFIXES")); if (no_builtin_rules_flag) - (void) define_variable ("SUFFIXES", 8, "", o_default, 0); + define_variable ("SUFFIXES", 8, "", o_default, 0); else { char *p = default_suffixes; suffix_file->deps = (struct dep *) multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), 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 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. */ void @@ -551,7 +551,7 @@ install_default_suffix_rules (void) 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. */ if (f->cmds == 0) { @@ -36,8 +36,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ struct dep { struct dep *next; - char *name; - char *stem; + const char *name; + const char *stem; struct file *file; unsigned int changed : 8; unsigned int ignore_mtime : 1; @@ -51,7 +51,7 @@ struct dep struct nameseq { struct nameseq *next; - char *name; + const char *name; }; @@ -61,25 +61,20 @@ struct nameseq *parse_file_seq (); #else struct nameseq *parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip); #endif -char *tilde_expand (char *name); +char *tilde_expand (const char *name); #ifndef NO_ARCHIVES struct nameseq *ar_glob (const char *arname, const char *member_pattern, unsigned int size); #endif -#ifndef iAPX286 #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); void free_dep (struct dep *d); struct dep *copy_dep_chain (const struct dep *d); void free_dep_chain (struct dep *d); 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 update_goal_chain (struct dep *goals); void uniquize_deps (struct dep *); @@ -1124,29 +1124,28 @@ open_dirstream (const char *directory) static struct dirent * read_dirstream (__ptr_t stream) { + static char *buf; + 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; - static char *buf; - static unsigned int bufsz; 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) { - /* The glob interface wants a `struct dirent', - so mock one up. */ + /* The glob interface wants a `struct dirent', so mock one up. */ struct dirent *d; 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; - if (sizeof *d - sizeof d->d_name + len > bufsz) - bufsz = sizeof *d - sizeof d->d_name + len; - buf = xmalloc (bufsz); + if (sz > bufsz) + bufsz = sz; + buf = xrealloc (buf, bufsz); } d = (struct dirent *) buf; #ifdef __MINGW32__ @@ -1200,7 +1199,6 @@ local_stat (const char *path, struct stat *buf) void dir_setup_glob (glob_t *gl) { - /* Bogus sunos4 compiler complains (!) about & before functions. */ gl->gl_opendir = open_dirstream; gl->gl_readdir = read_dirstream; gl->gl_closedir = ansi_free; @@ -360,7 +360,9 @@ variable_expand_string (char *line, const char *string, long length) if (ppercent) { ++ppercent; - rpercent = 0; + rpercent = find_percent (replace); + if (rpercent) + ++rpercent; } else { @@ -370,8 +372,8 @@ variable_expand_string (char *line, const char *string, long length) --replace; } - o = patsubst_expand (o, value, pattern, replace, - ppercent, rpercent); + o = patsubst_expand_pat (o, value, pattern, replace, + ppercent, rpercent); if (v->recursive) free (value); @@ -69,16 +69,16 @@ static int all_secondary = 0; /* Access the hash table of all file records. lookup_file given a name, return the struct file * for that name, - or nil if there is none. - enter_file similar, but create one if there is none. */ + or nil if there is none. +*/ struct file * -lookup_file (char *name) +lookup_file (const char *name) { - register struct file *f; + struct file *f; struct file file_key; #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - char *lname, *ln; + char *lname; #endif assert (*name != '\0'); @@ -90,8 +90,9 @@ lookup_file (char *name) # ifndef WANT_CASE_SENSITIVE_TARGETS if (*name != '.') { - char *n; - lname = xmalloc (strlen (name) + 1); + const char *n; + char *ln; + lname = xstrdup (name); for (n = name, ln = lname; *n != '\0'; ++n, ++ln) *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; *ln = '\0'; @@ -112,15 +113,13 @@ lookup_file (char *name) if (*name == '\0') /* It was all slashes after a dot. */ -#ifdef VMS +#if defined(VMS) name = "[]"; -#else -#ifdef _AMIGA +#elif defined(_AMIGA) name = ""; #else name = "./"; -#endif /* AMIGA */ -#endif /* VMS */ +#endif file_key.hname = name; f = hash_find_item (&files, &file_key); @@ -128,39 +127,41 @@ lookup_file (char *name) if (*name != '.') free (lname); #endif + 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 * -enter_file (char *name) +enter_file (const char *name) { - register struct file *f; - register struct file *new; - register struct file **file_slot; + struct file *f; + struct file *new; + struct file **file_slot; struct file file_key; -#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - char *lname, *ln; -#endif assert (*name != '\0'); + assert (strcache_iscached (name)); #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) if (*name != '.') { - char *n; - lname = xmalloc (strlen (name) + 1); + const char *n; + char *lname, *ln; + lname = xstrdup (name); for (n = name, ln = lname; *n != '\0'; ++n, ++ln) - { - if (isupper ((unsigned char)*n)) - *ln = tolower ((unsigned char)*n); - else - *ln = *n; - } + if (isupper ((unsigned char)*n)) + *ln = tolower ((unsigned char)*n); + else + *ln = *n; - *ln = 0; - /* Creates a possible leak, old value of name is unreachable, but I - currently don't know how to fix it. */ - name = lname; + *ln = '\0'; + name = strcache_add (lname); + free (lname); } #endif @@ -168,13 +169,7 @@ enter_file (char *name) file_slot = (struct file **) hash_find_slot (&files, &file_key); f = *file_slot; if (! HASH_VACANT (f) && !f->double_colon) - { -#if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - if (*name != '.') - free (lname); -#endif - return f; - } + return f; new = xmalloc (sizeof (struct file)); memset (new, '\0', sizeof (struct file)); @@ -197,27 +192,12 @@ enter_file (char *name) 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 the `hname' member, since it must be put in a new hash bucket, and possibly merged with an existing file called NAME. */ 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_slot; @@ -225,108 +205,130 @@ rehash_file (struct file *from_file, char *to_hname) struct file *deleted_file; struct file *f; + /* If it's already that name, we're done. */ file_key.hname = to_hname; - if (0 == file_hash_cmp (from_file, &file_key)) + if (! file_hash_cmp (from_file, &file_key)) return; + /* Find the end of the renamed list for the "from" file. */ file_key.hname = from_file->hname; while (from_file->renamed != 0) from_file = from_file->renamed; if (file_hash_cmp (from_file, &file_key)) - /* hname changed unexpectedly */ + /* hname changed unexpectedly!! */ abort (); + /* Remove the "from" file from the hash. */ deleted_file = hash_delete (&files, from_file); if (deleted_file != from_file) /* from_file isn't the one stored in files */ abort (); + /* Find where the newly renamed file will go in the hash. */ file_key.hname = to_hname; file_slot = (struct file **) hash_find_slot (&files, &file_key); to_file = *file_slot; + /* Change the hash name for this file. */ from_file->hname = to_hname; for (f = from_file->double_colon; f != 0; f = f->prev) f->hname = to_hname; + /* If the new name doesn't exist yet just set it to the renamed file. */ if (HASH_VACANT (to_file)) - hash_insert_at (&files, from_file, file_slot); - else { - /* TO_FILE already exists under TO_HNAME. - We must retain TO_FILE and merge FROM_FILE into it. */ + hash_insert_at (&files, from_file, file_slot); + return; + } - 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); - } - } + /* TO_FILE already exists under TO_HNAME. + We must retain TO_FILE and merge FROM_FILE into it. */ - /* Merge the dependencies of the two files. */ + 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); + } + } - if (to_file->deps == 0) - to_file->deps = from_file->deps; - else - { - register struct dep *deps = to_file->deps; - while (deps->next != 0) - deps = deps->next; - deps->next = from_file->deps; - } + /* Merge the dependencies of the two files. */ - merge_variable_set_lists (&to_file->variables, from_file->variables); + if (to_file->deps == 0) + to_file->deps = from_file->deps; + else + { + struct dep *deps = to_file->deps; + while (deps->next != 0) + deps = deps->next; + deps->next = from_file->deps; + } - 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'"), - 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; - } + merge_variable_set_lists (&to_file->variables, from_file->variables); + + 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'"), + 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; + 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; + to_file->mtime_before_update = from_file->mtime_before_update; #define MERGE(field) to_file->field |= from_file->field - MERGE (precious); - MERGE (tried_implicit); - MERGE (updating); - MERGE (updated); - MERGE (is_target); - MERGE (cmd_target); - MERGE (phony); - MERGE (ignore_vpath); + MERGE (precious); + MERGE (tried_implicit); + MERGE (updating); + MERGE (updated); + MERGE (is_target); + MERGE (cmd_target); + MERGE (phony); + MERGE (ignore_vpath); #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 remove_intermediates (int sig) { - register struct file **file_slot; - register struct file **file_end; + struct file **file_slot; + struct file **file_end; int doneany = 0; /* 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++) if (! HASH_VACANT (*file_slot)) { - register struct file *f = *file_slot; + struct file *f = *file_slot; /* Is this file eligible for automatic deletion? 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 @@ -444,7 +446,6 @@ parse_prereqs (char *p) return new; } - /* Set the intermediate flag. */ static void @@ -460,7 +461,7 @@ expand_deps (struct file *f) { struct dep *d; struct dep *old = f->deps; - char *file_stem = f->stem; + const char *file_stem = f->stem; unsigned int last_dep_has_cmds = f->updating; int initialized = 0; @@ -476,9 +477,13 @@ expand_deps (struct file *f) continue; /* 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) - p = d->name; + { + p = variable_expand (""); + variable_buffer_output (p, d->name, strlen (d->name) + 1); + } else { /* 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); - free (d->name); - d->name = savestring (buffer, o - buffer); + d->name = strcache_add_len (buffer, o - buffer); d->staticpattern = 0; /* Clear staticpattern so that we don't re-expand %s below. */ } @@ -525,48 +529,47 @@ expand_deps (struct file *f) plain prerequisite names. */ if (new && d->staticpattern) { - char *pattern = "%"; + const char *pattern = "%"; char *buffer = variable_expand (""); struct dep *dp = new, *dl = 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) { + char *o; + /* We have to handle empty stems specially, because that would be equivalent to $(patsubst %,dp->name,) which will always be empty. */ 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, - dp->name, pattern+1, - percent+1); - if (o == buffer) - dp->name[0] = '\0'; - else - { - free (dp->name); - dp->name = savestring (buffer, o - buffer); - } + memmove (percent, percent+1, strlen (percent)); + o = variable_buffer_output (buffer, nm, strlen (nm) + 1); } + 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 (dp->name[0] == '\0') + if (buffer[0] == '\0') { struct dep *df = dp; if (dp == new) dp = new = new->next; else dp = dl->next = dp->next; - /* @@ Are we leaking df->name here? */ - df->name = 0; free_dep (df); continue; } + + /* Save the name. */ + dp->name = strcache_add_len (buffer, o - buffer); } dl = dp; dp = dp->next; @@ -579,8 +582,6 @@ expand_deps (struct file *f) d1->file = lookup_file (d1->name); if (d1->file == 0) d1->file = enter_file (d1->name); - else - free (d1->name); d1->name = 0; d1->staticpattern = 0; d1->need_2nd_expansion = 0; @@ -635,27 +636,25 @@ snap_deps (void) struct file **file_slot; struct file **file_end; - /* Perform second expansion and enter each dependency - name as a file. */ + /* Perform second expansion and enter each dependency name as a file. */ - /* Expand .SUFFIXES first; it's dependencies are used for - $$* calculation. */ + /* Expand .SUFFIXES first; it's dependencies are used for $$* calculation. */ for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev) expand_deps (f); - /* We must use hash_dump (), because within this loop - we might add new files to the table, possibly causing - an in-situ table expansion. */ + /* For every target that's not .SUFFIXES, expand its dependencies. + We must use hash_dump (), because within this loop we might add new files + to the table, possibly causing an in-situ table expansion. */ file_slot_0 = (struct file **) hash_dump (&files, 0, 0); file_end = file_slot_0 + files.ht_fill; for (file_slot = file_slot_0; file_slot < file_end; file_slot++) for (f = *file_slot; f != 0; f = f->prev) - { - if (strcmp (f->name, ".SUFFIXES") != 0) - expand_deps (f); - } + if (strcmp (f->name, ".SUFFIXES") != 0) + expand_deps (f); free (file_slot_0); + /* Now manage all the special targets. */ + for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) @@ -678,35 +677,26 @@ snap_deps (void) } for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev) - { - /* .INTERMEDIATE with deps listed - marks those deps as intermediate files. */ - for (d = f->deps; d != 0; d = d->next) - for (f2 = d->file; f2 != 0; f2 = f2->prev) - f2->intermediate = 1; - /* .INTERMEDIATE with no deps does nothing. - Marking all files as intermediates is useless - since the goal targets would be deleted after they are built. */ - } + /* Mark .INTERMEDIATE deps as intermediate files. */ + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->intermediate = 1; + /* .INTERMEDIATE with no deps does nothing. + Marking all files as intermediates is useless since the goal targets + would be deleted after they are built. */ for (f = lookup_file (".SECONDARY"); f != 0; f = f->prev) - { - /* .SECONDARY with deps listed - marks those deps as intermediate files - in that they don't get rebuilt if not actually needed; - but unlike real intermediate files, - these are not deleted after make finishes. */ - if (f->deps) - for (d = f->deps; d != 0; d = d->next) - for (f2 = d->file; f2 != 0; f2 = f2->prev) - f2->intermediate = f2->secondary = 1; - /* .SECONDARY with no deps listed marks *all* files that way. */ - else - { - all_secondary = 1; - hash_map (&files, set_intermediate); - } - } + /* Mark .SECONDARY deps as both intermediate and secondary. */ + if (f->deps) + for (d = f->deps; d != 0; d = d->next) + for (f2 = d->file; f2 != 0; f2 = f2->prev) + f2->intermediate = f2->secondary = 1; + /* .SECONDARY with no deps listed marks *all* files that way. */ + else + { + all_secondary = 1; + hash_map (&files, set_intermediate); + } f = lookup_file (".EXPORT_ALL_VARIABLES"); if (f != 0 && f->is_target) @@ -853,11 +843,10 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) sprintf (p, "%lu", (unsigned long) t); p += strlen (p); - /* Append nanoseconds as a fraction, but remove trailing zeros. - We don't know the actual timestamp resolution, since clock_getres - applies only to local times, whereas this timestamp might come - from a remote filesystem. So removing trailing zeros is the - best guess that we can do. */ + /* Append nanoseconds as a fraction, but remove trailing zeros. We don't + know the actual timestamp resolution, since clock_getres applies only to + local times, whereas this timestamp might come from a remote filesystem. + So removing trailing zeros is the best guess that we can do. */ sprintf (p, ".%09d", FILE_TIMESTAMP_NS (ts)); p += strlen (p) - 1; while (*p == '0') @@ -872,7 +861,7 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) static void print_file (const void *item) { - struct file *f = (struct file *) item; + const struct file *f = item; struct dep *d; struct dep *ood = 0; @@ -993,6 +982,39 @@ print_file_data_base (void) fputs (_("\n# files hash-table stats:\n# "), 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) @@ -25,14 +25,14 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ struct file { - char *name; - char *hname; /* Hashed filename */ - char *vpath; /* VPATH/vpath pathname */ + const char *name; + const char *hname; /* Hashed filename */ + const char *vpath; /* VPATH/vpath pathname */ struct dep *deps; /* all dependencies, including duplicates */ struct commands *cmds; /* Commands to execute for this target. */ int command_flags; /* Flags OR'd in for cmds; see commands.h. */ - char *stem; /* Implicit stem, if an implicit - rule has been used */ + const char *stem; /* Implicit stem, if an implicit + rule has been used */ struct dep *also_make; /* Targets that are made by making this. */ FILE_TIMESTAMP last_mtime; /* File's modtime, if already known. */ 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; -struct file *lookup_file (char *name); -struct file *enter_file (char *name); +struct file *lookup_file (const char *name); +struct file *enter_file (const char *name); struct dep *parse_prereqs (char *prereqs); void remove_intermediates (int sig); void snap_deps (void); -void rename_file (struct file *file, char *name); -void rehash_file (struct file *file, char *name); +void rename_file (struct file *file, const char *name); +void rehash_file (struct file *file, const char *name); void set_command_state (struct file *file, enum cmd_state state); void notice_finished_file (struct file *file); void init_hash_files (void); @@ -74,11 +74,11 @@ static struct hash_table function_table; whitespace-delimited words. */ 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) { - char *t = text; - char *p; + const char *t = text; + const char *p; 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); /* Advance T past the string to be replaced. */ - { - char *nt = p + slen; - t = nt; - } + t = p + slen; } while (*t != '\0'); return o; @@ -144,24 +141,16 @@ subst_expand (char *o, char *text, char *subst, char *replace, */ char * -patsubst_expand (char *o, char *text, char *pattern, char *replace, - char *pattern_percent, char *replace_percent) +patsubst_expand_pat (char *o, const char *text, + const char *pattern, const char *replace, + const char *pattern_percent, const char *replace_percent) { unsigned int pattern_prepercent_len, pattern_postpercent_len; unsigned int replace_prepercent_len, replace_postpercent_len; - char *t; + const char *t; unsigned int len; 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 compute these lengths more than once. */ if (replace_percent) @@ -176,12 +165,6 @@ patsubst_expand (char *o, char *text, char *pattern, char *replace, } if (!pattern_percent) - { - pattern_percent = find_percent (pattern); - if (pattern_percent) - ++pattern_percent; - } - if (!pattern_percent) /* With no % in the pattern, this is just a simple substitution. */ return subst_expand (o, text, pattern, replace, strlen (pattern), strlen (replace), 1); @@ -251,6 +234,32 @@ patsubst_expand (char *o, char *text, char *pattern, char *replace, 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. */ @@ -343,8 +352,8 @@ string_glob (char *line) { static char *result = 0; static unsigned int length; - register struct nameseq *chain; - register unsigned int idx; + struct nameseq *chain; + unsigned int idx; chain = multi_glob (parse_file_seq (&line, '\0', sizeof (struct nameseq), @@ -363,7 +372,7 @@ string_glob (char *line) idx = 0; while (chain != 0) { - register char *name = chain->name; + const char *name = chain->name; unsigned int len = strlen (name); struct nameseq *next = chain->next; @@ -383,8 +392,6 @@ string_glob (char *line) idx += len; result[idx++] = ' '; } - - free (name); } /* Kill the last space and terminate the string. */ @@ -403,7 +410,7 @@ string_glob (char *line) static char * 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; } @@ -417,10 +424,10 @@ func_join (char *o, char **argv, const char *funcname UNUSED) by the corresponding word of the second argument. If the two arguments have a different number of words, the excess words are just output separated by blanks. */ - register char *tp; - register char *pp; - char *list1_iterator = argv[0]; - char *list2_iterator = argv[1]; + const char *tp; + const char *pp; + const char *list1_iterator = argv[0]; + const char *list2_iterator = argv[1]; do { unsigned int len1, len2; @@ -452,7 +459,7 @@ static char * func_origin (char *o, char **argv, const char *funcname UNUSED) { /* 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) o = variable_buffer_output (o, "undefined", 9); else @@ -491,7 +498,7 @@ func_origin (char *o, char **argv, const char *funcname UNUSED) static char * 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) o = variable_buffer_output (o, "undefined", 9); @@ -519,8 +526,8 @@ static char * func_notdir_suffix (char *o, char **argv, const char *funcname) { /* Expand the argument. */ - char *list_iterator = argv[0]; - char *p2 =0; + const char *list_iterator = argv[0]; + const char *p2; int doneany =0; unsigned int len=0; @@ -528,7 +535,7 @@ func_notdir_suffix (char *o, char **argv, const char *funcname) int is_notdir = !is_suffix; while ((p2 = find_next_token (&list_iterator, &len)) != 0) { - char *p = p2 + len; + const char *p = p2 + len; while (p >= p2 && (!is_suffix || *p != '.')) @@ -563,13 +570,12 @@ func_notdir_suffix (char *o, char **argv, const char *funcname) doneany = 1; } } + if (doneany) /* Kill last space. */ --o; - return o; - } @@ -577,68 +583,68 @@ static char * func_basename_dir (char *o, char **argv, const char *funcname) { /* Expand the argument. */ - char *p3 = argv[0]; - char *p2=0; + const char *p3 = argv[0]; + const char *p2; int doneany=0; unsigned int len=0; - char *p=0; + int is_basename= streq (funcname, "basename"); int is_dir= !is_basename; while ((p2 = find_next_token (&p3, &len)) != 0) - { - p = p2 + len; - while (p >= p2 && (!is_basename || *p != '.')) - { - if (IS_PATHSEP (*p)) - break; - --p; - } + { + const char *p = p2 + len; + while (p >= p2 && (!is_basename || *p != '.')) + { + if (IS_PATHSEP (*p)) + break; + --p; + } - if (p >= p2 && (is_dir)) - o = variable_buffer_output (o, p2, ++p - p2); - else if (p >= p2 && (*p == '.')) - o = variable_buffer_output (o, p2, p - p2); + if (p >= p2 && (is_dir)) + o = variable_buffer_output (o, p2, ++p - p2); + else if (p >= p2 && (*p == '.')) + o = variable_buffer_output (o, p2, p - p2); #ifdef HAVE_DOS_PATHS - /* Handle the "d:foobar" case */ - else if (p2[0] && p2[1] == ':' && is_dir) - o = variable_buffer_output (o, p2, 2); + /* Handle the "d:foobar" case */ + else if (p2[0] && p2[1] == ':' && is_dir) + o = variable_buffer_output (o, p2, 2); #endif - else if (is_dir) + else if (is_dir) #ifdef VMS - o = variable_buffer_output (o, "[]", 2); + o = variable_buffer_output (o, "[]", 2); #else #ifndef _AMIGA - o = variable_buffer_output (o, "./", 2); + o = variable_buffer_output (o, "./", 2); #else - ; /* Just a nop... */ + ; /* Just a nop... */ #endif /* AMIGA */ #endif /* !VMS */ - else - /* The entire name is the basename. */ - o = variable_buffer_output (o, p2, len); + else + /* The entire name is the basename. */ + o = variable_buffer_output (o, p2, len); - o = variable_buffer_output (o, " ", 1); - doneany = 1; - } - if (doneany) - /* Kill last space. */ - --o; + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + if (doneany) + /* Kill last space. */ + --o; - return o; + return o; } static char * func_addsuffix_addprefix (char *o, char **argv, const char *funcname) { int fixlen = strlen (argv[0]); - char *list_iterator = argv[1]; + const char *list_iterator = argv[1]; int is_addprefix = streq (funcname, "addprefix"); int is_addsuffix = !is_addprefix; int doneany = 0; - char *p; + const char *p; unsigned int len; 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) { unsigned int i; - char *words = argv[0]; /* Use a temp variable for find_next_token */ - char *p = find_next_token (&words, &i); + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p = find_next_token (&words, &i); if (p != 0) o = variable_buffer_output (o, p, i); @@ -686,9 +692,9 @@ static char * func_lastword (char *o, char **argv, const char *funcname UNUSED) { unsigned int i; - char *words = argv[0]; /* Use a temp variable for find_next_token */ - char *p = 0; - char *t; + const char *words = argv[0]; /* Use a temp variable for find_next_token */ + const char *p; + const char *t; while ((t = find_next_token (&words, &i))) p = t; @@ -703,7 +709,7 @@ static char * func_words (char *o, char **argv, const char *funcname UNUSED) { int i = 0; - char *word_iterator = argv[0]; + const char *word_iterator = argv[0]; char buf[20]; 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); o = variable_buffer_output (o, buf, strlen (buf)); - return o; } @@ -751,19 +756,18 @@ check_numeric (const char *s, const char *msg) static char * func_word (char *o, char **argv, const char *funcname UNUSED) { - char *end_p=0; - int i=0; - char *p=0; + const char *end_p; + const char *p; + int i; /* Check the first argument. */ check_numeric (argv[0], _("non-numeric first argument to `word' function")); - i = atoi (argv[0]); + i = atoi (argv[0]); if (i == 0) fatal (*expanding_var, _("first argument to `word' function must be greater than 0")); - end_p = argv[1]; while ((p = find_next_token (&end_p, 0)) != 0) if (--i == 0) @@ -795,8 +799,8 @@ func_wordlist (char *o, char **argv, const char *funcname UNUSED) if (count > 0) { - char *p; - char *end_p = argv[2]; + const char *p; + const char *end_p = argv[2]; /* Find the beginning of the "start"th word. */ 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; } -static char* +static char * func_findstring (char *o, char **argv, const char *funcname UNUSED) { /* 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. */ char *varname = expand_argument (argv[0], NULL); char *list = expand_argument (argv[1], NULL); - char *body = argv[2]; + const char *body = argv[2]; int doneany = 0; - char *list_iterator = list; - char *p; + const char *list_iterator = list; + const char *p; unsigned int len; - register struct variable *var; + struct variable *var; push_new_variable_scope (); 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 save = p[len]; - - p[len] = '\0'; - free (var->value); - var->value = xstrdup ((char*) p); - p[len] = save; - } + free (var->value); + var->value = savestring (p, len); 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; int is_filter = streq (funcname, "filter"); - char *pat_iterator = argv[0]; - char *word_iterator = argv[1]; + const char *pat_iterator = argv[0]; + const char *word_iterator = argv[1]; int literals = 0; int words = 0; int hashing = 0; @@ -985,7 +983,8 @@ func_filter_filterout (char *o, char **argv, const char *funcname) hashing = (literals >= 2 && (literals * words) >= 10); 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) { 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; a_word_key.str = pp->str; 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) { wp->matched |= 1; @@ -1049,13 +1048,13 @@ func_filter_filterout (char *o, char **argv, const char *funcname) static char * func_strip (char *o, char **argv, const char *funcname UNUSED) { - char *p = argv[0]; - int doneany =0; + const char *p = argv[0]; + int doneany = 0; while (*p != '\0') { int i=0; - char *word_start=0; + const char *word_start; while (isspace ((unsigned char)*p)) ++p; @@ -1072,6 +1071,7 @@ func_strip (char *o, char **argv, const char *funcname UNUSED) if (doneany) /* Kill the last space. */ --o; + return o; } @@ -1130,46 +1130,61 @@ func_error (char *o, char **argv, const char *funcname) static char * func_sort (char *o, char **argv, const char *funcname UNUSED) { - char **words = 0; - int nwords = 0; - register int wordi = 0; - - /* Chop ARGV[0] into words and put them in WORDS. */ - char *t = argv[0]; + const char *t; + char **words; + int wordi; char *p; unsigned int len; int i; - while ((p = find_next_token (&t, &len)) != 0) + /* Find the maximum number of words we'll have. */ + t = argv[0]; + wordi = 1; + while (*t != '\0') { - if (wordi >= nwords - 1) - { - nwords = (2 * nwords) + 5; - words = xrealloc (words, nwords * sizeof (char *)); - } - words[wordi++] = savestring (p, len); + char c = *(t++); + + if (! isspace ((unsigned char)c)) + continue; + + ++wordi; + + while (isspace ((unsigned char)*t)) + ++t; } - if (!wordi) - return o; + words = xmalloc (wordi * sizeof (char *)); - /* Now sort the list of words. */ - qsort (words, wordi, sizeof (char *), alpha_compare); + /* Now assign pointers to each string in the array. */ + t = argv[0]; + wordi = 0; + while ((p = find_next_token (&t, &len)) != 0) + { + ++t; + p[len] = '\0'; + words[wordi++] = p; + } - /* Now write the sorted list. */ - for (i = 0; i < wordi; ++i) + if (wordi) { - len = strlen (words[i]); - if (i == wordi - 1 || strlen (words[i + 1]) != len - || strcmp (words[i], words[i + 1])) + /* Now sort the list of words. */ + qsort (words, wordi, sizeof (char *), alpha_compare); + + /* Now write the sorted list, uniquified. */ + for (i = 0; i < wordi; ++i) { - o = variable_buffer_output (o, words[i], len); - o = variable_buffer_output (o, " ", 1); + len = strlen (words[i]); + 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); @@ -1215,11 +1230,9 @@ func_if (char *o, char **argv, const char *funcname UNUSED) argv += 1 + !result; - if (argv[0]) + if (*argv) { - char *expansion; - - expansion = expand_argument (argv[0], NULL); + char *expansion = expand_argument (*argv, NULL); o = variable_buffer_output (o, expansion, strlen (expansion)); @@ -1336,7 +1349,6 @@ func_and (char *o, char **argv, const char *funcname UNUSED) static char * func_wildcard (char *o, char **argv, const char *funcname UNUSED) { - #ifdef _AMIGA o = wildcard_expansion (argv[0], o); #else @@ -1576,22 +1588,20 @@ msdos_openpipe (int* pipedes, int *pidp, char *text) static char * func_shell (char *o, char **argv, const char *funcname UNUSED) { - char* batch_filename = NULL; + char *batch_filename = NULL; #ifdef __MSDOS__ FILE *fpipe; #endif char **command_argv; - char *error_prefix; + const char *error_prefix; char **envp; int pipedes[2]; int pid; #ifndef __MSDOS__ /* Construct the argument list. */ - command_argv = construct_command_argv (argv[0], - (char **) NULL, (struct file *) 0, - &batch_filename); + command_argv = construct_command_argv (argv[0], NULL, NULL, &batch_filename); if (command_argv == 0) return o; #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 calling environment. + See Savannah bug #10593. + envp = target_environment (NILF); */ @@ -1611,35 +1623,31 @@ func_shell (char *o, char **argv, const char *funcname UNUSED) /* For error messages. */ if (reading_file && reading_file->filenm) { - error_prefix = alloca (strlen (reading_file->filenm)+11+4); - sprintf (error_prefix, - "%s:%lu: ", reading_file->filenm, reading_file->lineno); + char *p = alloca (strlen (reading_file->filenm)+11+4); + sprintf (p, "%s:%lu: ", reading_file->filenm, reading_file->lineno); + error_prefix = p; } else error_prefix = ""; -#ifdef 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 - -#elif defined(__MSDOS__) - +#if defined(__MSDOS__) fpipe = msdos_openpipe (pipedes, &pid, argv[0]); if (pipedes[0] < 0) { perror_with_name (error_prefix, "pipe"); 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 - if (pipe (pipedes) < 0) { perror_with_name (error_prefix, "pipe"); @@ -1647,7 +1655,6 @@ func_shell (char *o, char **argv, const char *funcname UNUSED) } # ifdef __EMX__ - /* close some handles that are unnecessary for the child process */ CLOSE_ON_EXEC(pipedes[1]); 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); if (pid < 0) perror_with_name (error_prefix, "spawn"); - # else /* ! __EMX__ */ - pid = vfork (); if (pid < 0) perror_with_name (error_prefix, "fork"); else if (pid == 0) child_execute_job (0, pipedes[1], command_argv, envp); else - # endif - #endif { /* We are the parent. */ @@ -1863,7 +1866,7 @@ func_eq (char *o, char **argv, char *funcname) static char * func_not (char *o, char **argv, char *funcname) { - char *s = argv[0]; + const char *s = argv[0]; int result = 0; while (isspace ((unsigned char)*s)) s++; @@ -1956,8 +1959,8 @@ static char * func_realpath (char *o, char **argv, const char *funcname UNUSED) { /* Expand the argument. */ - char *p = argv[0]; - char *path = 0; + const char *p = argv[0]; + const char *path = 0; int doneany = 0; unsigned int len = 0; PATH_VAR (in); @@ -1970,14 +1973,13 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED) strncpy (in, path, len); in[len] = '\0'; - if - ( + if ( #ifdef HAVE_REALPATH - realpath (in, out) + realpath (in, out) #else - abspath (in, out) + abspath (in, out) #endif - ) + ) { o = variable_buffer_output (o, out, strlen (out)); o = variable_buffer_output (o, " ", 1); @@ -1990,15 +1992,15 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED) if (doneany) --o; - return o; + return o; } static char * func_abspath (char *o, char **argv, const char *funcname UNUSED) { /* Expand the argument. */ - char *p = argv[0]; - char *path = 0; + const char *p = argv[0]; + const char *path = 0; int doneany = 0; unsigned int len = 0; PATH_VAR (in); @@ -2024,7 +2026,7 @@ func_abspath (char *o, char **argv, const char *funcname UNUSED) if (doneany) --o; - return o; + return o; } /* 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? */ entry_p = lookup_function (fname); - if (entry_p) { /* How many arguments do we have? */ for (i=0; argv[i+1]; ++i) ; - return expand_builtin_function (o, i, argv+1, entry_p); } @@ -68,9 +68,9 @@ try_implicit_rule (struct file *file, unsigned int depth) struct idep { 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 */ - 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 ignore_mtime; /* ignore_mtime flag */ }; @@ -83,18 +83,6 @@ free_idep_chain (struct idep *p) for (; p != 0; p = n) { 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); } } @@ -105,9 +93,9 @@ free_idep_chain (struct idep *p) length of the word. */ 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; /* Skip any leading whitespace. */ @@ -178,7 +166,7 @@ get_next_word (char *buffer, unsigned int *length) if (length) *length = p - beg; - return beg; + return (char *)beg; } /* 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) { /* 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. */ unsigned int namelen = strlen (filename); @@ -225,7 +213,7 @@ pattern_search (struct file *file, int archive, char *depname = alloca (namelen + max_pattern_dep_length); /* 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 fullstemlen = 0; @@ -258,8 +246,6 @@ pattern_search (struct file *file, int archive, struct rule *rule; struct dep *dep, *expl_d; - char *p, *vname; - struct idep *d; struct idep **id_ptr; struct dep **d_ptr; @@ -318,10 +304,10 @@ pattern_search (struct file *file, int archive, continue; } - for (ti = 0; rule->targets[ti] != 0; ++ti) + for (ti = 0; ti < rule->num; ++ti) { - char *target = rule->targets[ti]; - char *suffix = rule->suffixes[ti]; + const char *target = rule->targets[ti]; + const char *suffix = rule->suffixes[ti]; int check_lastslash; /* 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) { 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') - 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 @@ -486,6 +473,7 @@ pattern_search (struct file *file, int archive, for (dep = rule->deps; dep != 0; dep = dep->next) { unsigned int len; + char *p; char *p2; unsigned int order_only = 0; /* Set if '|' was seen. */ @@ -614,14 +602,10 @@ pattern_search (struct file *file, int archive, if (add_dir) { - char *n = d->name; - - d->name = xmalloc (strlen (n) + l + 1); - - memcpy (d->name, filename, l); - memcpy (d->name + l, n, strlen (n) + 1); - - free (n); + char *n = alloca (strlen (d->name) + l + 1); + memcpy (n, filename, l); + memcpy (n+l, d->name, strlen (d->name) + 1); + d->name = strcache_add (n); } if (had_stem) @@ -653,7 +637,7 @@ pattern_search (struct file *file, int archive, for (d = deps; d != 0; d = d->next) { - char *name = d->name; + const char *name = d->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 "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ - vname = name; - if (vpath_search (&vname, (FILE_TIMESTAMP *) 0)) - { - DBS (DB_IMPLICIT, - (_("Found prerequisite `%s' as VPATH `%s'\n"), - name, - vname)); - - free (vname); - continue; - } + { + const char *vname = vpath_search (name, 0); + if (vname) + { + DBS (DB_IMPLICIT, + (_("Found prerequisite `%s' as VPATH `%s'\n"), + name, vname)); + continue; + } + } /* 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, recursions + 1)) { - d->intermediate_file = intermediate_file; d->intermediate_pattern = intermediate_file->name; - - intermediate_file->name = xstrdup (name); + intermediate_file->name = strcache_add (name); + d->intermediate_file = intermediate_file; intermediate_file = 0; continue; @@ -819,7 +801,7 @@ pattern_search (struct file *file, int archive, for (d = deps; d != 0; d = d->next) { - register char *s; + const char *s; if (d->intermediate_file != 0) { @@ -839,7 +821,7 @@ pattern_search (struct file *file, int archive, if (f != 0) f->precious = 1; else - f = enter_file (imf->name); + f = enter_file (strcache_add (imf->name)); f->deps = imf->deps; f->cmds = imf->cmds; @@ -859,9 +841,6 @@ pattern_search (struct file *file, int archive, for (dep = f->deps; dep != 0; dep = dep->next) { 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->file->tried_implicit |= dep->changed; } @@ -875,17 +854,10 @@ pattern_search (struct file *file, int archive, { dep->file = lookup_file (s); if (dep->file == 0) - /* enter_file consumes S's storage. */ 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 - { - dep->name = s; - } + dep->name = s; 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 on the stack for an intermediate file. */ - file->stem = savestring (stem, stemlen); + file->stem = strcache_add_len (stem, stemlen); fullstemlen = stemlen; } else { int dirlen = (lastslash + 1) - filename; + char *sp; /* We want to prepend the directory from the original FILENAME onto the stem. */ fullstemlen = dirlen + stemlen; - file->stem = xmalloc (fullstemlen + 1); - memcpy (file->stem, filename, dirlen); - memcpy (file->stem + dirlen, stem, stemlen); - file->stem[fullstemlen] = '\0'; + sp = alloca (fullstemlen + 1); + memcpy (sp, filename, dirlen); + memcpy (sp + dirlen, stem, stemlen); + sp[fullstemlen] = '\0'; + file->stem = strcache_add (sp); } 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 `also_make' member. */ - if (rule->targets[1] != 0) - for (ri = 0; rule->targets[ri] != 0; ++ri) + if (rule->num > 1) + for (ri = 0; ri < rule->num; ++ri) if (ri != matches[foundrule]) { + char *p = alloca (rule->lens[ri] + fullstemlen + 1); struct file *f; struct dep *new = alloc_dep (); /* GKM FIMXE: handle '|' here too */ - new->name = p = xmalloc (rule->lens[ri] + fullstemlen + 1); memcpy (p, rule->targets[ri], 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; memcpy (p, rule->suffixes[ri], rule->lens[ri] - (rule->suffixes[ri] - rule->targets[ri])+1); + new->name = strcache_add (p); new->file = enter_file (new->name); new->next = file->also_make; @@ -374,8 +374,8 @@ _is_unixy_shell (const char *path) Append "(ignored)" if IGNORED is nonzero. */ static void -child_error (char *target_name, int exit_code, int exit_sig, int coredump, - int ignored) +child_error (const char *target_name, + int exit_code, int exit_sig, int coredump, int ignored) { if (ignored && silent_flag) return; @@ -67,6 +67,8 @@ void print_rule_data_base (void); void print_file_data_base (void); void print_vpath_data_base (void); +void verify_file_data_base (void); + #if defined HAVE_WAITPID || defined HAVE_WAIT3 # define HAVE_WAIT_NOHANG #endif @@ -87,7 +89,7 @@ static void print_version (void); static void decode_switches (int argc, char **argv, int env); static void decode_env_switches (char *envar, unsigned int len); 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); @@ -102,6 +104,7 @@ struct command_switch flag, /* Turn int flag on. */ flag_off, /* Turn int flag off. */ string, /* One string per switch. */ + filename, /* A string containing a file name. */ positive_int, /* A positive integer. */ floating, /* A floating-point number (double). */ ignore /* Ignored. */ @@ -128,7 +131,7 @@ struct command_switch 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 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', 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 }, { CHAR_MAX+1, string, &db_flags, 1, 1, 0, "basic", 0, "debug" }, #ifdef WINDOWS32 { 'D', flag, &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" }, #endif { '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" }, { '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" }, { 'j', positive_int, &job_slots, 1, 1, 0, &inf_jobs, &default_job_slots, "jobs" }, @@ -398,7 +401,7 @@ static const struct command_switch switches[] = { 'L', flag, &check_symlink_flag, 1, 1, 0, 0, 0, "check-symlink-times" }, { 'm', ignore, 0, 0, 0, 0, 0, 0, 0 }, { '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" }, { 'q', flag, &question_flag, 1, 1, 1, 0, 0, "question" }, { '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" }, { CHAR_MAX+4, flag, &inhibit_print_directory_flag, 1, 1, 0, 0, 0, "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, "warn-undefined-variables" }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 } @@ -543,17 +546,20 @@ initialize_global_hash_tables (void) hash_init_function_table (); } -static struct file * -enter_command_line_file (char *name) +static const char * +expand_command_line_file (char *name) { + const char *cp; + char *expanded = 0; + if (name[0] == '\0') fatal (NILF, _("empty string invalid as file name")); if (name[0] == '~') { - char *expanded = tilde_expand (name); + expanded = tilde_expand (name); 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 @@ -577,7 +583,12 @@ enter_command_line_file (char *name) name[2] = '\0'; } - return enter_file (xstrdup (name)); + cp = strcache_add (name); + + if (expanded) + free (expanded); + + return cp; } /* Toggle -d on receipt of SIGUSR1. */ @@ -593,7 +604,7 @@ debug_signal_handler (int sig UNUSED) static void decode_debug_flags (void) { - char **pp; + const char **pp; if (debug_flag) db_level = DB_ALL; @@ -728,9 +739,10 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo ) */ int -find_and_set_default_shell (char *token) +find_and_set_default_shell (const char *token) { int sh_found = 0; + char *atoken = 0; char *search_token; char *tokend; PATH_VAR(sh_path); @@ -739,8 +751,7 @@ find_and_set_default_shell (char *token) if (!token) search_token = default_shell; else - search_token = token; - + atoken = search_token = xstrdup (token); /* 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 @@ -766,10 +777,10 @@ find_and_set_default_shell (char *token) (token == NULL || !strcmp (search_token, default_shell))) { /* no new information, path already set or known */ sh_found = 1; - } else if (file_exists_p(search_token)) { + } else if (file_exists_p (search_token)) { /* search token path was found */ - sprintf(sh_path, "%s", search_token); - default_shell = xstrdup(w32ify(sh_path,0)); + sprintf (sh_path, "%s", search_token); + default_shell = xstrdup (w32ify (sh_path, 0)); DB (DB_VERBOSE, (_("find_and_set_shell setting default_shell = %s\n"), default_shell)); sh_found = 1; @@ -782,31 +793,31 @@ find_and_set_default_shell (char *token) char *ep; p = v->value; - ep = strchr(p, PATH_SEPARATOR_CHAR); + ep = strchr (p, PATH_SEPARATOR_CHAR); while (ep && *ep) { *ep = '\0'; - if (dir_file_exists_p(p, search_token)) { - sprintf(sh_path, "%s/%s", p, search_token); - default_shell = xstrdup(w32ify(sh_path,0)); + if (dir_file_exists_p (p, search_token)) { + sprintf (sh_path, "%s/%s", p, search_token); + default_shell = xstrdup (w32ify (sh_path, 0)); sh_found = 1; *ep = PATH_SEPARATOR_CHAR; /* terminate loop */ - p += strlen(p); + p += strlen (p); } else { *ep = PATH_SEPARATOR_CHAR; p = ++ep; } - ep = strchr(p, PATH_SEPARATOR_CHAR); + ep = strchr (p, PATH_SEPARATOR_CHAR); } /* be sure to check last element of Path */ - if (p && *p && dir_file_exists_p(p, search_token)) { - sprintf(sh_path, "%s/%s", p, search_token); - default_shell = xstrdup(w32ify(sh_path,0)); + if (p && *p && dir_file_exists_p (p, search_token)) { + sprintf (sh_path, "%s/%s", p, search_token); + default_shell = xstrdup (w32ify (sh_path, 0)); sh_found = 1; } @@ -819,7 +830,7 @@ find_and_set_default_shell (char *token) /* naive test */ if (!unixy_shell && sh_found && - (strstr(default_shell, "sh") || strstr(default_shell, "SH"))) { + (strstr (default_shell, "sh") || strstr (default_shell, "SH"))) { unixy_shell = 1; batch_mode_shell = 0; } @@ -828,6 +839,9 @@ find_and_set_default_shell (char *token) batch_mode_shell = 1; #endif + if (atoken) + free (atoken); + return (sh_found); } #endif /* WINDOWS32 */ @@ -1228,7 +1242,7 @@ main (int argc, char **argv, char **envp) decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); #if 0 /* 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. */ decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif @@ -1296,7 +1310,7 @@ main (int argc, char **argv, char **envp) && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) # endif ) - argv[0] = concat (current_directory, "/", argv[0]); + argv[0] = xstrdup (concat (current_directory, "/", argv[0])); #else /* !__MSDOS__ */ if (current_directory[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 #endif ) - argv[0] = concat (current_directory, "/", argv[0]); + argv[0] = xstrdup (concat (current_directory, "/", argv[0])); #endif /* !__MSDOS__ */ #endif /* WINDOWS32 */ #endif @@ -1370,14 +1384,7 @@ main (int argc, char **argv, char **envp) unsigned int i; for (i = 0; directories->list[i] != 0; ++i) { - char *dir = directories->list[i]; - char *expanded = 0; - if (dir[0] == '~') - { - expanded = tilde_expand (dir); - if (expanded != 0) - dir = expanded; - } + const char *dir = directories->list[i]; #ifdef WINDOWS32 /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' But allow -C/ just in case someone wants that. */ @@ -1390,8 +1397,6 @@ main (int argc, char **argv, char **envp) #endif if (chdir (dir) < 0) 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 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. */ { - struct file *f = enter_file (stdin_nm); + struct file *f = enter_file (strcache_add (stdin_nm)); f->updated = 1; f->update_status = 0; f->command_state = cs_finished; @@ -1595,7 +1600,7 @@ main (int argc, char **argv, char **envp) /* Define the 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); @@ -1660,7 +1665,7 @@ main (int argc, char **argv, char **envp) if (jobserver_fds) { - char *cp; + const char *cp; unsigned int ui; for (ui=1; ui < jobserver_fds->idx; ++ui) @@ -1719,6 +1724,7 @@ main (int argc, char **argv, char **envp) if (job_slots > 1) { + char *cp; char c = '+'; 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. */ + cp = xmalloc ((sizeof ("1024")*2)+1); + sprintf (cp, "%d,%d", job_fds[0], job_fds[1]); + jobserver_fds = (struct stringlist *) xmalloc (sizeof (struct stringlist)); jobserver_fds->list = xmalloc (sizeof (char *)); - jobserver_fds->list[0] = xmalloc ((sizeof ("1024")*2)+1); - - sprintf (jobserver_fds->list[0], "%d,%d", job_fds[0], job_fds[1]); + jobserver_fds->list[0] = cp; jobserver_fds->idx = 1; jobserver_fds->max = 1; } @@ -1798,10 +1805,10 @@ main (int argc, char **argv, char **envp) if (old_files != 0) { - char **p; + const char **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->updated = 1; f->update_status = 0; @@ -1811,10 +1818,10 @@ main (int argc, char **argv, char **envp) if (!restarts && new_files != 0) { - char **p; + const char **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; } } @@ -2000,9 +2007,10 @@ main (int argc, char **argv, char **envp) { char *p = &argv[i][2]; if (*p == '\0') - argv[++i] = makefiles->list[j]; + /* This cast is OK since we never modify argv. */ + argv[++i] = (char *) makefiles->list[j]; else - argv[i] = concat ("-f", makefiles->list[j], ""); + argv[i] = xstrdup (concat ("-f", makefiles->list[j], "")); ++j; } } @@ -2012,25 +2020,20 @@ main (int argc, char **argv, char **envp) { nargv = xmalloc ((nargc + 2) * sizeof (char *)); memcpy (nargv, argv, argc * sizeof (char *)); - nargv[nargc++] = concat ("-o", stdin_nm, ""); + nargv[nargc++] = xstrdup (concat ("-o", stdin_nm, "")); nargv[nargc] = 0; } if (directories != 0 && directories->idx > 0) { - char bad; + int bad = 1; if (directory_before_chdir != 0) { if (chdir (directory_before_chdir) < 0) - { perror_with_name ("chdir", ""); - bad = 1; - } else bad = 0; } - else - bad = 1; if (bad) 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 && new_files != 0) { - char **p; + const char **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; } } @@ -2184,7 +2187,7 @@ main (int argc, char **argv, char **envp) if (ns->next != 0) 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(). */ free_ns_chain (ns); @@ -2287,6 +2290,7 @@ init_switches (void) break; case string: + case filename: case positive_int: case floating: 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 target! Enter it as a file and add it to the dep chain of 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; if (goals == 0) @@ -2361,7 +2365,7 @@ handle_non_switch_argument (char *arg, int env) { /* Add this target name to the MAKECMDGOALS variable. */ struct variable *gv; - char *value; + const char *value; gv = lookup_variable (STRING_SIZE_TUPLE ("MAKECMDGOALS")); if (gv == 0) @@ -2370,13 +2374,15 @@ handle_non_switch_argument (char *arg, int env) { /* Paste the old and new values together */ unsigned int oldlen, newlen; + char *vp; oldlen = strlen (gv->value); newlen = strlen (f->name); - value = alloca (oldlen + 1 + newlen + 1); - memcpy (value, gv->value, oldlen); - value[oldlen] = ' '; - memcpy (&value[oldlen + 1], f->name, newlen + 1); + vp = alloca (oldlen + 1 + newlen + 1); + memcpy (vp, gv->value, oldlen); + vp[oldlen] = ' '; + memcpy (&vp[oldlen + 1], f->name, newlen + 1); + value = vp; } define_variable ("MAKECMDGOALS", 12, value, o_default, 0); } @@ -2472,6 +2478,7 @@ decode_switches (int argc, char **argv, int env) break; case string: + case filename: if (!doit) break; @@ -2500,7 +2507,10 @@ decode_switches (int argc, char **argv, int env) sl->list = xrealloc (sl->list, 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; 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 need permanent storage for this in case decode_switches saves pointers into the value. */ - argv[1] = concat ("-", argv[1], ""); + argv[1] = xstrdup (concat ("-", argv[1], "")); /* Parse those words. */ 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. */ static char * -quote_for_env (char *out, char *in) +quote_for_env (char *out, const char *in) { while (*in != '\0') { @@ -2692,7 +2702,7 @@ define_makeflags (int all, int makefile) { struct flag *next; const struct command_switch *cs; - char *arg; + const char *arg; }; struct flag *flags = 0; unsigned int flagslen = 0; @@ -2716,9 +2726,6 @@ define_makeflags (int all, int makefile) if (cs->toenv && (!makefile || !cs->no_makefile)) switch (cs->type) { - default: - abort (); - case ignore: break; @@ -2775,21 +2782,25 @@ define_makeflags (int all, int makefile) break; #endif + case filename: case string: if (all) { struct stringlist *sl = *(struct stringlist **) cs->value_ptr; if (sl != 0) { - /* Add the elements in reverse order, because - all the flags get reversed below; and the order - matters for some switches (like -I). */ - register unsigned int i = sl->idx; + /* Add the elements in reverse order, because all the flags + get reversed below; and the order matters for some + switches (like -I). */ + unsigned int i = sl->idx; while (i-- > 0) ADD_FLAG (sl->list[i], strlen (sl->list[i])); } } break; + + default: + abort (); } flagslen += 4 + sizeof posixref; /* Four more for the possible " -- ". */ @@ -3073,6 +3084,8 @@ die (int status) if (print_data_base_flag) print_data_base (); + verify_file_data_base (); + clean_jobserver (status); /* Try to move back to the original directory. This is essential on diff --git a/maintMakefile b/maintMakefile index 4599e15..6cef280 100644 --- a/maintMakefile +++ b/maintMakefile @@ -226,7 +226,8 @@ po-check: ## ------------------------- ## # 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 GPGFLAGS = -u 6338B6D4 @@ -234,21 +235,24 @@ GPGFLAGS = -u 6338B6D4 DIST_ARCHIVES_SIG = $(addsuffix .sig,$(DIST_ARCHIVES)) DIST_ARCHIVES_DIRECTIVE = $(addsuffix .directive.asc,$(DIST_ARCHIVES)) +# A simple rule to test signing, etc. .PHONY: distsign distsign: $(DIST_ARCHIVES_SIG) $(DIST_ARCHIVES_DIRECTIVE) -$(DIST_ARCHIVES_DIRECTIVE): .directive.asc - cp $< $@ - %.sig : % @echo "Signing file '$<':" - $(GPG) $(GPGFLAGS) -o $@ -b $< + $(GPG) $(GPGFLAGS) -o "$@" -b "$<" -.directive.asc: +%.directive.asc: % @echo "Creating directive file '$@':" - @echo 'directory: make' > .directive - $(GPG) $(GPGFLAGS) -o $@ --clearsign .directive - @rm -f .directive + @( \ + echo 'verstion: 1.1'; \ + 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 @@ -258,11 +262,11 @@ gnu-url = ftp-upload.gnu.org /incoming UPLOADS = upload-alpha upload-ftp .PHONY: $(UPLOADS) $(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 -# Free Software Foundation, Inc. +# Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, +# 2007 Free Software Foundation, Inc. # This file is part of GNU Make. # # GNU Make is free software; you can redistribute it and/or modify it under the @@ -334,8 +334,8 @@ int strcmpi (const char *,const char *); void sync_Path_environment (void); int kill (int pid, int sig); -char *end_of_token_w32 (char *s, char stopchar); -int find_and_set_default_shell (char *token); +char *end_of_token_w32 (const char *s, char stopchar); +int find_and_set_default_shell (const char *token); /* indicates whether or not we have Bourne shell */ extern int no_default_sh_exe; @@ -385,7 +385,7 @@ char *concat (const char *, const char *, const char *); void *xmalloc (unsigned int); void *xrealloc (void *, unsigned int); 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 *end_of_token (const char *); void collapse_continuations (char *); @@ -393,6 +393,7 @@ char *lindex (const char *, const char *, int); int alpha_compare (const void *, const void *); void print_spaces (unsigned int); char *find_percent (char *); +const char *find_percent_cached (const char **); FILE *open_tmpfile (char **, const char *); #ifndef NO_ARCHIVES @@ -427,10 +428,10 @@ void install_default_implicit_rules (void); void build_vpath_lists (void); 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); -void construct_include_path (char **arg_dirs); +void construct_include_path (const char **arg_dirs); void user_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 to do it ourselves here. */ -#define ENULLLOOP(_v,_c) do{ errno = 0; \ - while (((_v)=_c)==0 && errno==EINTR); }while(0) +#define ENULLLOOP(_v,_c) do { errno = 0; (_v) = _c; } \ + while((_v)==0 && errno==EINTR) @@ -158,28 +158,31 @@ print_spaces (unsigned int n) } -/* Return a newly-allocated string whose contents - concatenate those of s1, s2, s3. */ +/* Return a string whose contents concatenate those of s1, s2, s3. + This string lives in static, re-used memory. */ char * concat (const char *s1, const char *s2, const char *s3) { unsigned int len1, len2, len3; - char *result; + static unsigned int rlen = 0; + static char *result = NULL; - len1 = *s1 != '\0' ? strlen (s1) : 0; - len2 = *s2 != '\0' ? strlen (s2) : 0; - len3 = *s3 != '\0' ? strlen (s3) : 0; + len1 = (s1 && *s1 != '\0') ? strlen (s1) : 0; + len2 = (s2 && *s2 != '\0') ? strlen (s2) : 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); - if (*s2 != '\0') + if (len2) memcpy (result + len1, s2, len2); - if (*s3 != '\0') + if (len3) memcpy (result + len1 + len2, s3, len3); - *(result + len1 + len2 + len3) = '\0'; + + result[len1+len2+len3] = '\0'; return result; } @@ -426,10 +429,10 @@ end_of_token (const char *s) * Same as end_of_token, but take into account a stop character */ char * -end_of_token_w32 (char *s, char stopchar) +end_of_token_w32 (const char *s, char stopchar) { - register char *p = s; - register int backslash = 0; + const char *p = s; + int backslash = 0; while (*p != '\0' && *p != stopchar && (backslash || !isblank ((unsigned char)*p))) @@ -447,7 +450,7 @@ end_of_token_w32 (char *s, char stopchar) backslash = 0; } - return p; + return (char *)p; } #endif @@ -461,22 +464,23 @@ next_token (const char *s) return (char *)s; } -/* Find the next token in PTR; return the address of it, and store the - length of the token into *LENGTHPTR if LENGTHPTR is not nil. */ +/* Find the next token in PTR; return the address of it, and store the length + 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 * -find_next_token (char **ptr, unsigned int *lengthptr) +find_next_token (const char **ptr, unsigned int *lengthptr) { - char *p = next_token (*ptr); - char *end; + const char *p = next_token (*ptr); if (*p == '\0') return 0; - *ptr = end = end_of_token (p); + *ptr = end_of_token (p); if (lengthptr != 0) - *lengthptr = end - p; - return p; + *lengthptr = *ptr - p; + + return (char *)p; } @@ -496,12 +500,6 @@ alloc_dep () void free_dep (struct dep *d) { - if (d->name != 0) - free (d->name); - - if (d->stem != 0) - free (d->stem); - free (d); } @@ -511,20 +509,14 @@ free_dep (struct dep *d) struct dep * copy_dep_chain (const struct dep *d) { - register struct dep *c; struct dep *firstnew = 0; struct dep *lastnew = 0; while (d != 0) { - c = xmalloc (sizeof (struct dep)); + struct dep *c = xmalloc (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; if (firstnew == 0) firstnew = lastnew = c; @@ -549,37 +541,20 @@ free_dep_chain (struct dep *d) free_dep (df); } } - -/* Free a chain of `struct nameseq'. Each nameseq->name is freed - as well. For `struct dep' chains use free_dep_chain. */ - -void -free_ns_chain (struct nameseq *n) -{ - register struct nameseq *tmp; - while (n != 0) - { - if (n->name != 0) - free (n->name); +/* Free a chain of struct nameseq. + For struct dep chains use free_dep_chain. */ - 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) +void +free_ns_chain (struct nameseq *ns) { - return dep->name == 0 ? dep->file->name : dep->name; + while (ns != 0) + { + struct nameseq *t = ns; + ns = ns->next; + free (t); + } } -#endif #ifdef GETLOADAVG_PRIVILEGED @@ -88,14 +88,12 @@ static struct conditionals *conditionals = &toplevel_conditionals; /* Default directories to search for include files in */ -static char *default_include_directories[] = +static const char *default_include_directories[] = { #if defined(WINDOWS32) && !defined(INCLUDEDIR) -/* - * This completely up to the user when they install MSVC or other packages. - * This is defined as a placeholder. - */ -#define INCLUDEDIR "." +/* This completely up to the user when they install MSVC or other packages. + This is defined as a placeholder. */ +# define INCLUDEDIR "." #endif INCLUDEDIR, #ifndef _AMIGA @@ -108,7 +106,7 @@ static char *default_include_directories[] = /* 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. */ @@ -123,15 +121,15 @@ const struct floc *reading_file = 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 long readline (struct ebuffer *ebuf); static void do_define (char *name, unsigned int namelen, enum variable_origin origin, struct ebuffer *ebuf); static int conditional_line (char *line, int len, const struct floc *flocp); -static void record_files (struct nameseq *filenames, char *pattern, - char *pattern_percent, struct dep *deps, +static void record_files (struct nameseq *filenames, const char *pattern, + const char *pattern_percent, struct dep *deps, unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, 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. */ struct dep * -read_all_makefiles (char **makefiles) +read_all_makefiles (const char **makefiles) { unsigned int num_makefiles = 0; @@ -181,7 +179,7 @@ read_all_makefiles (char **makefiles) MAKEFILES is updated for finding remaining tokens. */ p = value; - while ((name = find_next_token (&p, &length)) != 0) + while ((name = find_next_token ((const char **)&p, &length)) != 0) { if (*p != '\0') *p++ = '\0'; @@ -248,7 +246,7 @@ read_all_makefiles (char **makefiles) for (p = default_makefiles; *p != 0; ++p) { struct dep *d = alloc_dep (); - d->file = enter_file (*p); + d->file = enter_file (strcache_add (*p)); d->file->dontcare = 1; /* 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. */ @@ -296,17 +294,17 @@ restore_conditionals (struct conditionals *saved) } static int -eval_makefile (char *filename, int flags) +eval_makefile (const char *filename, int flags) { struct dep *deps; struct ebuffer ebuf; const struct floc *curfile; char *expanded = 0; - char *included = 0; int makefile_errno; int r; - ebuf.floc.filenm = strcache_add (filename); + filename = strcache_add (filename); + ebuf.floc.filenm = filename; ebuf.floc.lineno = 1; if (ISDB (DB_VERBOSE)) @@ -343,21 +341,17 @@ eval_makefile (char *filename, int flags) search the included makefile search path for this makefile. */ if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/') { - register unsigned int i; + unsigned int 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"); if (ebuf.fp) { - filename = included; + filename = strcache_add (included); 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. */ @@ -366,7 +360,7 @@ eval_makefile (char *filename, int flags) read_makefiles = deps; deps->file = lookup_file (filename); if (deps->file == 0) - deps->file = enter_file (xstrdup (filename)); + deps->file = enter_file (filename); filename = deps->file->name; deps->changed = flags; if (flags & RM_DONTCARE) @@ -374,8 +368,6 @@ eval_makefile (char *filename, int flags) if (expanded) free (expanded); - if (included) - free (included); /* 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; long nlines = 0; int two_colon = 0; - char *pattern = 0, *pattern_percent; + const char *pattern = 0; + const char *pattern_percent; struct floc *fstart; struct floc fi; @@ -481,7 +474,7 @@ eval (struct ebuffer *ebuf, int set_default) filenames = 0; \ commands_idx = 0; \ no_targets = 0; \ - if (pattern) { free(pattern); pattern = 0; } \ + pattern = 0; \ } while (0) pattern_percent = 0; @@ -708,14 +701,15 @@ eval (struct ebuffer *ebuf, int set_default) else { unsigned int l; + const char *cp; char *ap; /* Expand the line so we can use indirect and constructed 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; - p = find_next_token (&p2, &l)) + for (p = find_next_token (&cp, &l); p != 0; + p = find_next_token (&cp, &l)) { v = lookup_variable (p, l); if (v == 0) @@ -737,14 +731,15 @@ eval (struct ebuffer *ebuf, int set_default) { unsigned int l; struct variable *v; + const char *cp; char *ap; /* Expand the line so we can use indirect and constructed 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; - p = find_next_token (&p2, &l)) + for (p = find_next_token (&cp, &l); p != 0; + p = find_next_token (&cp, &l)) { v = lookup_variable (p, l); if (v == 0) @@ -761,14 +756,15 @@ eval (struct ebuffer *ebuf, int set_default) skip_conditionals: if (word1eq ("vpath")) { + const char *cp; char *vpat; unsigned int l; - p2 = variable_expand (p2); - p = find_next_token (&p2, &l); + cp = variable_expand (p2); + p = find_next_token (&cp, &l); if (p != 0) { vpat = savestring (p, l); - p = find_next_token (&p2, &l); + p = find_next_token (&cp, &l); /* No searchpath means remove all previous selective VPATH's with the same pattern. */ } @@ -822,7 +818,7 @@ eval (struct ebuffer *ebuf, int set_default) while (files != 0) { struct nameseq *next = files->next; - char *name = files->name; + const char *name = files->name; int r; free (files); @@ -832,7 +828,6 @@ eval (struct ebuffer *ebuf, int set_default) | (noerror ? RM_DONTCARE : 0))); if (!r && !noerror) error (fstart, "%s: %s", name, strerror (errno)); - free (name); } /* Restore conditional state. */ @@ -1148,8 +1143,8 @@ eval (struct ebuffer *ebuf, int set_default) fatal (fstart, _("missing target pattern")); else if (target->next != 0) fatal (fstart, _("multiple target patterns")); + pattern_percent = find_percent_cached (&target->name); pattern = target->name; - pattern_percent = find_percent (pattern); if (pattern_percent == 0) fatal (fstart, _("target pattern contains no `%%'")); free (target); @@ -1166,7 +1161,7 @@ eval (struct ebuffer *ebuf, int set_default) { /* Put all the prerequisites here; they'll be parsed later. */ deps = alloc_dep (); - deps->name = savestring (beg, end - beg + 1); + deps->name = strcache_add_len (beg, end - beg + 1); } else deps = 0; @@ -1208,7 +1203,7 @@ eval (struct ebuffer *ebuf, int set_default) if (**default_goal_name == '\0' && set_default) { - char* name; + const char *name; struct dep *d; struct nameseq *t = filenames; @@ -1769,9 +1764,9 @@ record_target_var (struct nameseq *filenames, char *defn, for (; filenames != 0; filenames = nextf) { struct variable *v; - register char *name = filenames->name; - char *fname; - char *percent; + const char *name = filenames->name; + const char *fname; + const char *percent; struct pattern_var *p; 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 variable list. */ - percent = find_percent (name); + percent = find_percent_cached (&name); if (percent) { /* Get a reference for this pattern-specific variable struct. */ @@ -1807,7 +1802,7 @@ record_target_var (struct nameseq *filenames, char *defn, this situation. */ f = lookup_file (name); if (!f) - f = enter_file (name); + f = enter_file (strcache_add (name)); else if (f->double_colon) f = f->double_colon; @@ -1844,10 +1839,6 @@ record_target_var (struct nameseq *filenames, char *defn, 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. */ static void -record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, - struct dep *deps, unsigned int cmds_started, char *commands, +record_files (struct nameseq *filenames, const char *pattern, + const char *pattern_percent, struct dep *deps, + unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, const struct floc *flocp) { struct nameseq *nextf; int implicit = 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; /* 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) { - char *name = filenames->name; + const char *name = filenames->name; struct file *f; struct dep *this = 0; - char *implicit_percent; + const char *implicit_percent; nextf = filenames->next; free (filenames); @@ -1910,17 +1902,17 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, else if (streq (name, ".SECONDEXPANSION")) second_expansion = 1; - implicit_percent = find_percent (name); + implicit_percent = find_percent_cached (&name); implicit |= implicit_percent != 0; - if (implicit && pattern != 0) - fatal (flocp, _("mixed implicit and static pattern rules")); + if (implicit) + { + if (pattern != 0) + fatal (flocp, _("mixed implicit and static pattern rules")); - if (implicit && implicit_percent == 0) - fatal (flocp, _("mixed implicit and normal rules")); + if (implicit_percent == 0) + fatal (flocp, _("mixed implicit and normal rules")); - if (implicit) - { if (targets == 0) { max_targets = 5; @@ -1960,7 +1952,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, { /* Single-colon. Combine these dependencies with others in file's existing record, if any. */ - f = enter_file (name); + f = enter_file (strcache_add (name)); if (f->double_colon) 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) fatal (flocp, _("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, enter_file will have returned a new one, making it the prev 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. */ if (pattern) { - static char *percent = "%"; + static const char *percent = "%"; char *buffer = variable_expand (""); - char *o = patsubst_expand (buffer, name, pattern, percent, - pattern_percent+1, percent+1); - f->stem = savestring (buffer, o - buffer); + char *o = patsubst_expand_pat (buffer, name, pattern, percent, + pattern_percent+1, percent+1); + f->stem = strcache_add_len (buffer, o - buffer); if (this) { this->staticpattern = 1; - this->stem = xstrdup (f->stem); + this->stem = f->stem; } } - /* Free name if not needed further. */ - if (f != 0 && name != f->name - && (name < f->name || name > f->name + strlen (f->name))) - { - free (name); - name = f->name; - } + name = f->name; /* If this target is a default target, update DEFAULT_GOAL_FILE. */ if (streq (*default_goal_name, name) @@ -2114,12 +2100,10 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, if (implicit) { - targets[target_idx] = 0; - target_percents[target_idx] = 0; if (deps) deps->need_2nd_expansion = second_expansion; - create_pattern_rule (targets, target_percents, two_colon, deps, cmds, 1); - free (target_percents); + create_pattern_rule (targets, target_percents, target_idx, + two_colon, deps, cmds, 1); } } @@ -2137,7 +2121,7 @@ find_char_unquote (char *string, int stop1, int stop2, int blank, int ignorevars) { unsigned int string_len = 0; - register char *p = string; + char *p = string; if (ignorevars) ignorevars = '$'; @@ -2230,6 +2214,82 @@ find_percent (char *pattern) { 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 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 *new1, *lastnew1; char *p = *stringp; - char *q; - char *name; #ifdef VMS # define VMS_COMMA ',' @@ -2261,6 +2319,9 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) while (1) { + const char *name; + char *q; + /* Skip whitespace; see if any more names are left. */ p = next_token (p); if (*p == '\0') @@ -2268,7 +2329,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) if (*p == stopchar) break; - /* Yes, find end of next name. */ + /* There are, so find the end of the next name. */ q = p; p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0); #ifdef VMS @@ -2280,9 +2341,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) if (stopchar == ':' && p && *p == ':' && !(isspace ((unsigned char)p[1]) || !p[1] || isspace ((unsigned char)p[-1]))) - { p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0); - } #endif #ifdef HAVE_DOS_PATHS /* 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) /* ".///" was stripped to "". */ -#ifdef VMS +#if defined(VMS) continue; +#elif defined(_AMIGA) + name = ""; #else -#ifdef _AMIGA - name = savestring ("", 0); -#else - name = savestring ("./", 2); -#endif + name = "./"; #endif else #ifdef VMS @@ -2347,11 +2404,11 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) } *q2++ = *q1++; } - name = savestring (qbase, p1 - qbase); + name = strcache_add_len (qbase, p1 - qbase); free (qbase); } #else - name = savestring (q, p - q); + name = strcache_add_len (q, p - q); #endif /* 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)". Edit it out of the chain and free its storage. */ lastn->next = n->next; - free (n->name); free (n); /* LASTN->next is the new stopping elt for the loop below. */ n = lastn->next; @@ -2415,9 +2471,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) else { /* Replace N's name with the full archive reference. */ - name = concat (libname, paren, ")"); - free (n->name); - n->name = name; + n->name = strcache_add (concat (libname, paren, ")")); } 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; lastn = new1; new1 = new1->next; - free (lastn->name); free (lastn); } else { /* Replace also NEW1->name, which already has closing `)'. */ - name = concat (libname, new1->name, ""); - free (new1->name); - new1->name = name; + new1->name = strcache_add (concat (libname, new1->name, "")); new1 = new1->next; } @@ -2448,9 +2499,7 @@ parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) while (new1 != n) { - name = concat (libname, new1->name, ")"); - free (new1->name); - new1->name = name; + new1->name = strcache_add (concat (libname, new1->name, ")")); lastnew1 = new1; 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. */ void -construct_include_path (char **arg_dirs) +construct_include_path (const char **arg_dirs) { - register unsigned int i; #ifdef VAXC /* just don't ask ... */ stat_t stbuf; #else struct stat stbuf; #endif - /* Table to hold the dirs. */ + const char **dirs; + const char **cpp; + unsigned int idx; - unsigned int defsize = (sizeof (default_include_directories) - / sizeof (default_include_directories[0])); - unsigned int max = 5; - char **dirs = xmalloc ((5 + defsize) * sizeof (char *)); - unsigned int idx = 0; + /* Compute the number of pointers we need in the table. */ + idx = sizeof (default_include_directories) / sizeof (const char *); + if (arg_dirs) + for (cpp = arg_dirs; *cpp != 0; ++cpp) + ++idx; #ifdef __MSDOS__ - defsize++; + /* Add one for $DJDIR. */ + ++idx; #endif + dirs = xmalloc (idx * sizeof (const char *)); + + idx = 0; + max_incl_len = 0; + /* First consider any dirs specified with -I switches. - Ignore dirs that don't exist. */ + Ignore any that don't exist. Remember the maximum string length. */ - if (arg_dirs != 0) + if (arg_dirs) while (*arg_dirs != 0) { - char *dir = *arg_dirs++; + const char *dir = *(arg_dirs++); + char *expanded = 0; int e; if (dir[0] == '~') { - char *expanded = tilde_expand (dir); + expanded = tilde_expand (dir); if (expanded != 0) dir = expanded; } EINTRLOOP (e, stat (dir, &stbuf)); if (e == 0 && S_ISDIR (stbuf.st_mode)) - { - if (idx == max - 1) - { - max += 5; - dirs = xrealloc (dirs, (max + defsize) * sizeof (char *)); - } - dirs[idx++] = dir; - } - else if (dir != arg_dirs[-1]) - free (dir); + { + unsigned int len = strlen (dir); + /* If dir name is written with trailing slashes, discard them. */ + while (len > 1 && dir[len - 1] == '/') + --len; + if (len > max_incl_len) + max_incl_len = len; + dirs[idx++] = strcache_add_len (dir, len); + } + + if (expanded) + free (expanded); } - /* Now add at the end the standard default dirs. */ + /* Now add the standard default dirs at the end. */ #ifdef __MSDOS__ { - /* The environment variable $DJDIR holds the root of the - DJGPP directory tree; add ${DJDIR}/include. */ + /* The environment variable $DJDIR holds the root of the DJGPP directory + tree; add ${DJDIR}/include. */ struct variable *djdir = lookup_variable ("DJDIR", 5); 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"); - dirs[idx++] = defdir; + dirs[idx++] = strcache_add (defdir); + + if (len > max_incl_len) + max_incl_len = len; } } #endif - for (i = 0; default_include_directories[i] != 0; ++i) + for (cpp = default_include_directories; *cpp != 0; ++cpp) { int e; - EINTRLOOP (e, stat (default_include_directories[i], &stbuf)); + EINTRLOOP (e, stat (*cpp, &stbuf)); 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; - /* Now compute the maximum length of any name in it. Also add each - dir to the .INCLUDE_DIRS variable. */ + /* Now add each dir to the .INCLUDE_DIRS variable. */ - max_incl_len = 0; - for (i = 0; i < idx; ++i) - { - 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); - } + for (cpp = dirs; *cpp != 0; ++cpp) + do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp, + o_default, f_append, 0); include_directories = dirs; } @@ -2924,7 +2981,7 @@ construct_include_path (char **arg_dirs) Return a newly malloc'd string or 0. */ char * -tilde_expand (char *name) +tilde_expand (const char *name) { #ifndef VMS if (name[1] == '/' || name[1] == '\0') @@ -2949,7 +3006,7 @@ tilde_expand (char *name) free (home_dir); home_dir = getenv ("HOME"); } -#if !defined(_AMIGA) && !defined(WINDOWS32) +# if !defined(_AMIGA) && !defined(WINDOWS32) if (home_dir == 0 || home_dir[0] == '\0') { extern char *getlogin (); @@ -2962,16 +3019,16 @@ tilde_expand (char *name) home_dir = p->pw_dir; } } -#endif /* !AMIGA && !WINDOWS32 */ +# endif /* !AMIGA && !WINDOWS32 */ if (home_dir != 0) { - char *new = concat (home_dir, "", name + 1); + char *new = xstrdup (concat (home_dir, "", name + 1)); if (is_variable) free (home_dir); return new; } } -#if !defined(_AMIGA) && !defined(WINDOWS32) +# if !defined(_AMIGA) && !defined(WINDOWS32) else { struct passwd *pwent; @@ -2984,12 +3041,12 @@ tilde_expand (char *name) if (userend == 0) return xstrdup (pwent->pw_dir); else - return concat (pwent->pw_dir, "/", userend + 1); + return xstrdup (concat (pwent->pw_dir, "/", userend + 1)); } else if (userend != 0) *userend = '/'; } -#endif /* !AMIGA && !WINDOWS32 */ +# endif /* !AMIGA && !WINDOWS32 */ #endif /* !VMS */ return 0; } @@ -3007,9 +3064,9 @@ tilde_expand (char *name) struct nameseq * multi_glob (struct nameseq *chain, unsigned int size) { - extern void dir_setup_glob (); - register struct nameseq *new = 0; - register struct nameseq *old; + void dir_setup_glob (glob_t *); + struct nameseq *new = 0; + struct nameseq *old; struct nameseq *nexto; glob_t gl; @@ -3017,44 +3074,37 @@ multi_glob (struct nameseq *chain, unsigned int size) for (old = chain; old != 0; old = nexto) { + const char *gname; #ifndef NO_ARCHIVES - char *memname; + char *arname = 0; + char *memname = 0; #endif - nexto = old->next; + gname = old->name; - if (old->name[0] == '~') + if (gname[0] == '~') { char *newname = tilde_expand (old->name); if (newname != 0) - { - free (old->name); - old->name = newname; - } + gname = newname; } #ifndef NO_ARCHIVES - if (ar_name (old->name)) + if (ar_name (gname)) { - /* OLD->name is an archive member reference. - Replace it with the archive file name, - and save the member name in MEMNAME. - We will glob on the archive name and then - reattach MEMNAME later. */ - char *arname; - ar_parse_name (old->name, &arname, &memname); - free (old->name); - old->name = arname; + /* OLD->name is an archive member reference. Replace it with the + archive file name, and save the member name in MEMNAME. We will + glob on the archive name and then reattach MEMNAME later. */ + ar_parse_name (gname, &arname, &memname); + gname = arname; } - else - memname = 0; #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. */ { - register int i = gl.gl_pathc; + int i = gl.gl_pathc; while (i-- > 0) { #ifndef NO_ARCHIVES @@ -3063,21 +3113,22 @@ multi_glob (struct nameseq *chain, unsigned int size) /* Try to glob on MEMNAME within the archive. */ struct nameseq *found = ar_glob (gl.gl_pathv[i], memname, size); - if (found == 0) + if (! found) { /* No matches. Use MEMNAME as-is. */ unsigned int alen = strlen (gl.gl_pathv[i]); unsigned int mlen = strlen (memname); + char *name; struct nameseq *elt = xmalloc (size); - if (size > sizeof (struct nameseq)) - memset (((char *)elt)+sizeof (struct nameseq), '\0', - size - sizeof (struct nameseq)); - elt->name = xmalloc (alen + 1 + mlen + 2); - memcpy (elt->name, gl.gl_pathv[i], alen); - elt->name[alen] = '('; - memcpy (&elt->name[alen + 1], memname, mlen); - elt->name[alen + 1 + mlen] = ')'; - elt->name[alen + 1 + mlen + 1] = '\0'; + memset (elt, '\0', size); + + name = alloca (alen + 1 + mlen + 2); + memcpy (name, gl.gl_pathv[i], alen); + name[alen] = '('; + memcpy (name+alen+1, memname, mlen); + name[alen + 1 + mlen] = ')'; + name[alen + 1 + mlen + 1] = '\0'; + elt->name = strcache_add (name); elt->next = new; new = elt; } @@ -3093,23 +3144,18 @@ multi_glob (struct nameseq *chain, unsigned int size) f->next = new; new = found; } - - free (memname); } else #endif /* !NO_ARCHIVES */ { struct nameseq *elt = xmalloc (size); - if (size > sizeof (struct nameseq)) - memset (((char *)elt)+sizeof (struct nameseq), '\0', - size - sizeof (struct nameseq)); - elt->name = xstrdup (gl.gl_pathv[i]); + memset (elt, '\0', size); + elt->name = strcache_add (gl.gl_pathv[i]); elt->next = new; new = elt; } } globfree (&gl); - free (old->name); free (old); break; } @@ -3123,6 +3169,11 @@ multi_glob (struct nameseq *chain, unsigned int size) new = old; break; } + +#ifndef NO_ARCHIVES + if (arname) + free (arname); +#endif } return new; @@ -66,8 +66,8 @@ static int check_dep (struct file *file, unsigned int depth, FILE_TIMESTAMP this_mtime, int *must_make_ptr); static int touch_file (struct file *file); static void remake_file (struct file *file); -static FILE_TIMESTAMP name_mtime (char *name); -static int library_search (char **lib, FILE_TIMESTAMP *mtime_ptr); +static FILE_TIMESTAMP name_mtime (const char *name); +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 @@ -913,7 +913,7 @@ notice_finished_file (struct file *file) We do this instead of just invalidating the cached time so that a vpath_search can happen. Otherwise, it would 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) /* Nothing was done for FILE, but it needed nothing done. @@ -1152,7 +1152,6 @@ f_mtime (struct file *file, int search) char *arname, *memname; struct file *arfile; - int arname_used = 0; time_t member_date; /* 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. */ arfile = lookup_file (arname); if (arfile == 0) - { - arfile = enter_file (arname); - arname_used = 1; - } + arfile = enter_file (strcache_add (arname)); mtime = f_mtime (arfile, search); check_renamed (arfile); if (search && strcmp (arfile->hname, arname)) @@ -1176,20 +1172,11 @@ f_mtime (struct file *file, int search) char *name; unsigned int arlen, memlen; - if (!arname_used) - { - free (arname); - arname_used = 1; - } - - arname = arfile->hname; - arlen = strlen (arname); + arlen = strlen (arfile->hname); memlen = strlen (memname); - /* free (file->name); */ - name = xmalloc (arlen + 1 + memlen + 2); - memcpy (name, arname, arlen); + memcpy (name, arfile->hname, arlen); name[arlen] = '('; memcpy (name + arlen + 1, memname, memlen); name[arlen + 1 + memlen] = ')'; @@ -1204,9 +1191,7 @@ f_mtime (struct file *file, int search) check_renamed (file); } - if (!arname_used) - free (arname); - free (memname); + free (arname); 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 name_mtime failed, search VPATH. */ - char *name = file->name; - if (vpath_search (&name, &mtime) + const char *name = vpath_search (file->name, &mtime); + if (name /* Last resort, is it a library (-lxxx)? */ - || (name[0] == '-' && name[1] == 'l' - && library_search (&name, &mtime))) + || (file->name[0] == '-' && file->name[1] == 'l' + && (name = library_search (file->name, &mtime)) != 0)) { if (mtime != UNKNOWN_MTIME) /* vpath_search and library_search store UNKNOWN_MTIME @@ -1350,7 +1335,7 @@ f_mtime (struct file *file, int search) much cleaner. */ static FILE_TIMESTAMP -name_mtime (char *name) +name_mtime (const char *name) { FILE_TIMESTAMP mtime; struct stat st; @@ -1444,8 +1429,8 @@ name_mtime (char *name) suitable library file in the system library directories and the VPATH directories. */ -static int -library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) +static const char * +library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr) { static char *dirs[] = { @@ -1466,14 +1451,15 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) static char *libpatterns = NULL; - char *libname = &(*lib)[2]; /* Name without the `-l'. */ + const char *libname = lib+2; /* Name without the '-l'. */ FILE_TIMESTAMP mtime; /* Loop variables for the libpatterns value. */ - char *p, *p2; + char *p; + const char *p2; unsigned int len; - char *file, **dp; + char **dp; /* If we don't have libpatterns, get it. */ if (!libpatterns) @@ -1522,20 +1508,18 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) mtime = name_mtime (libbuf); if (mtime != NONEXISTENT_MTIME) { - *lib = xstrdup (libbuf); if (mtime_ptr != 0) *mtime_ptr = mtime; - return 1; + return strcache_add (libbuf); } /* Now try VPATH search on that. */ - file = libbuf; - if (vpath_search (&file, mtime_ptr)) - { - *lib = file; - return 1; - } + { + const char *file = vpath_search (libbuf, mtime_ptr); + if (file) + return file; + } /* Now try the standard set of directories. */ @@ -1562,10 +1546,9 @@ library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) mtime = name_mtime (buf); if (mtime != NONEXISTENT_MTIME) { - *lib = xstrdup (buf); if (mtime_ptr != 0) *mtime_ptr = mtime; - return 1; + return strcache_add (buf); } } } @@ -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. */ #include "make.h" + +#include <assert.h> + #include "dep.h" #include "filedef.h" #include "job.h" @@ -69,7 +72,7 @@ count_implicit_rule_limits (void) { char *name; int namelen; - register struct rule *rule, *lastrule; + struct rule *rule, *lastrule; num_pattern_rules = max_pattern_targets = max_pattern_deps = 0; max_pattern_dep_length = 0; @@ -81,32 +84,27 @@ count_implicit_rule_limits (void) while (rule != 0) { unsigned int ndeps = 0; - register struct dep *dep; + struct dep *dep; struct rule *next = rule->next; - unsigned int ntargets; ++num_pattern_rules; - ntargets = 0; - while (rule->targets[ntargets] != 0) - ++ntargets; - - if (ntargets > max_pattern_targets) - max_pattern_targets = ntargets; + if (rule->num > max_pattern_targets) + max_pattern_targets = rule->num; for (dep = rule->deps; dep != 0; dep = dep->next) { unsigned int len = strlen (dep->name); #ifdef VMS - char *p = strrchr (dep->name, ']'); - char *p2; + const char *p = strrchr (dep->name, ']'); + const char *p2; if (p == 0) p = strrchr (dep->name, ':'); p2 = p != 0 ? strchr (dep->name, '%') : 0; #else - char *p = strrchr (dep->name, '/'); - char *p2 = p != 0 ? strchr (dep->name, '%') : 0; + const char *p = strrchr (dep->name, '/'); + const char *p2 = p != 0 ? strchr (dep->name, '%') : 0; #endif ndeps++; @@ -121,10 +119,8 @@ count_implicit_rule_limits (void) ++p; if (p - dep->name > namelen) { - if (name != 0) - free (name); namelen = p - dep->name; - name = xmalloc (namelen + 1); + name = xrealloc (name, namelen + 1); } memcpy (name, dep->name, p - dep->name); 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. */ 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; - char **names, **percents; + const char **names, **percents; struct dep *deps; - unsigned int len; + + names = xmalloc (sizeof (const char *)); + percents = xmalloc (sizeof (const char *)); 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 - targname = savestring ("(%.obj)", 7); + *names = strcache_add_len ("(%.obj)", 7); #else - targname = savestring ("(%.o)", 5); + *names = strcache_add_len ("(%.o)", 5); #endif - targpercent = targname + 1; + *percents = *names + 1; } else { /* Construct the target name. */ - len = strlen (target); - targname = xmalloc (1 + len + 1); - targname[0] = '%'; - memcpy (targname + 1, target, len + 1); - targpercent = targname; + unsigned int len = strlen (target); + char *p = alloca (1 + len + 1); + p[0] = '%'; + memcpy (p + 1, target, len + 1); + *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) deps = 0; else { /* Construct the dependency name. */ - len = strlen (source); - depname = xmalloc (1 + len + 1); - depname[0] = '%'; - memcpy (depname + 1, source, len + 1); + unsigned int len = strlen (source); + char *p = alloca (1 + len + 1); + p[0] = '%'; + memcpy (p + 1, source, len + 1); 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. - All rules for the suffixes on the .SUFFIXES list - are converted and added to the chain of pattern rules. */ + All rules for the suffixes on the .SUFFIXES list are converted and added to + the chain of pattern rules. */ void convert_to_pattern (void) { - register struct dep *d, *d2; - register struct file *f; - register char *rulename; - register unsigned int slen, s2len; + struct dep *d, *d2; + char *rulename; - /* 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; for (d = suffix_file->deps; d != 0; d = d->next) { - register unsigned int namelen = strlen (dep_name (d)); - if (namelen > maxsuffix) - maxsuffix = namelen; + unsigned int l = strlen (dep_name (d)); + if (l > maxsuffix) + maxsuffix = l; } + /* Space to construct the suffix rule target name. */ rulename = alloca ((maxsuffix * 2) + 1); 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. This rule exists solely to disqualify match-anything rules. */ convert_suffix_rule (dep_name (d), 0, 0); - f = d->file; - if (f->cmds != 0) + if (d->file->cmds != 0) /* 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)); memcpy (rulename, dep_name (d), slen); + for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) { + struct file *f; + unsigned int s2len; + s2len = strlen (dep_name (d2)); + /* Can't build something from itself. */ if (slen == s2len && streq (dep_name (d), dep_name (d2))) continue; @@ -273,19 +274,18 @@ convert_to_pattern (void) } -/* Install the pattern rule RULE (whose fields have been filled in) - at the end of the list (so that any rules previously defined - will take precedence). If this rule duplicates a previous one - (identical target and dependencies), the old one is replaced - if OVERRIDE is nonzero, otherwise this new one is thrown out. - When an old rule is replaced, the new one is put at the end of the - list. Return nonzero if RULE is used; zero if not. */ +/* Install the pattern rule RULE (whose fields have been filled in) at the end + of the list (so that any rules previously defined will take precedence). + If this rule duplicates a previous one (identical target and dependencies), + the old one is replaced if OVERRIDE is nonzero, otherwise this new one is + thrown out. When an old rule is replaced, the new one is put at the end of + the list. Return nonzero if RULE is used; zero if not. */ -int +static int new_pattern_rule (struct rule *rule, int override) { - register struct rule *r, *lastrule; - register unsigned int i, j; + struct rule *r, *lastrule; + unsigned int i, j; rule->in_use = 0; rule->terminal = 0; @@ -295,15 +295,15 @@ new_pattern_rule (struct rule *rule, int override) /* Search for an identical rule. */ lastrule = 0; 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])) break; - if (r->targets[j] == 0) - /* All the targets matched. */ + /* If all the targets matched... */ + if (j == r->num) { - register struct dep *d, *d2; + struct dep *d, *d2; for (d = rule->deps, d2 = r->deps; d != 0 && d2 != 0; d = d->next, d2 = d2->next) if (!streq (dep_name (d), dep_name (d2))) @@ -359,29 +359,21 @@ new_pattern_rule (struct rule *rule, int override) void install_pattern_rule (struct pspec *p, int terminal) { - register struct rule *r; + struct rule *r; char *ptr; r = xmalloc (sizeof (struct rule)); - r->targets = xmalloc (2 * sizeof (char *)); - r->suffixes = xmalloc (2 * sizeof (char *)); - r->lens = xmalloc (2 * sizeof (unsigned int)); - - r->targets[1] = 0; - r->suffixes[1] = 0; - r->lens[1] = 0; + r->num = 1; + r->targets = xmalloc (sizeof (const char *)); + r->suffixes = xmalloc (sizeof (const char *)); + r->lens = xmalloc (sizeof (unsigned int)); r->lens[0] = strlen (p->target); - /* These will all be string literals, but we malloc space for - them anyway because somebody might want to free them later on. */ - r->targets[0] = savestring (p->target, r->lens[0]); - r->suffixes[0] = find_percent (r->targets[0]); - if (r->suffixes[0] == 0) - /* Programmer-out-to-lunch error. */ - abort (); - else - ++r->suffixes[0]; + r->targets[0] = p->target; + r->suffixes[0] = find_percent_cached (&r->targets[0]); + assert (r->suffixes[0] != NULL); + ++r->suffixes[0]; ptr = p->dep; r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, '\0', @@ -410,21 +402,12 @@ static void freerule (struct rule *rule, struct rule *lastrule) { struct rule *next = rule->next; - register unsigned int i; - register struct dep *dep; - - for (i = 0; rule->targets[i] != 0; ++i) - free (rule->targets[i]); + struct dep *dep; dep = rule->deps; while (dep) { - struct dep *t; - - 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. */ + struct dep *t = dep->next; free_dep (dep); dep = t; } @@ -457,51 +440,36 @@ freerule (struct rule *rule, struct rule *lastrule) last_pattern_rule = lastrule; } -/* Create a new pattern rule with the targets in the nil-terminated - array TARGETS. If TARGET_PERCENTS is not nil, it is an array of - pointers into the elements of TARGETS, where the `%'s are. - The new rule has dependencies DEPS and commands from COMMANDS. +/* Create a new pattern rule with the targets in the nil-terminated array + TARGETS. TARGET_PERCENTS is an array of pointers to the % in each element + of TARGETS. N is the number of items in the array (not counting the nil + element). The new rule has dependencies DEPS and commands from COMMANDS. It is a terminal rule if TERMINAL is nonzero. This rule overrides identical rules with different commands if OVERRIDE is nonzero. - The storage for TARGETS and its elements is used and must not be freed - until the rule is destroyed. The storage for TARGET_PERCENTS is not used; - it may be freed. */ + The storage for TARGETS and its elements and TARGET_PERCENTS is used and + must not be freed until the rule is destroyed. */ void -create_pattern_rule (char **targets, char **target_percents, - int terminal, struct dep *deps, +create_pattern_rule (const char **targets, const char **target_percents, + unsigned int n, int terminal, struct dep *deps, struct commands *commands, int override) { - unsigned int max_targets, i; + unsigned int i; struct rule *r = xmalloc (sizeof (struct rule)); + r->num = n; r->cmds = commands; r->deps = deps; r->targets = targets; + r->suffixes = target_percents; + r->lens = xmalloc (n * sizeof (unsigned int)); - max_targets = 2; - r->lens = xmalloc (2 * sizeof (unsigned int)); - r->suffixes = xmalloc (2 * sizeof (char *)); - for (i = 0; targets[i] != 0; ++i) + for (i = 0; i < n; ++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->suffixes[i] = (target_percents == 0 ? find_percent (targets[i]) - : target_percents[i]) + 1; - 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 *)); + assert (r->suffixes[i] != NULL); + ++r->suffixes[i]; } 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. */ print_rule (struct rule *r) { - register unsigned int i; - register struct dep *d; + unsigned int i; + struct dep *d; - for (i = 0; r->targets[i] != 0; ++i) + for (i = 0; i < r->num; ++i) { fputs (r->targets[i], stdout); - if (r->targets[i + 1] != 0) - putchar (' '); - else - putchar (':'); + putchar ((i + 1 == r->num) ? ':' : ' '); } if (r->terminal) putchar (':'); @@ -538,8 +503,8 @@ print_rule (struct rule *r) void print_rule_data_base (void) { - register unsigned int rules, terminal; - register struct rule *r; + unsigned int rules, terminal; + struct rule *r; puts (_("\n# Implicit Rules")); @@ -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 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 *next; - char **targets; /* Targets of the rule. */ + const char **targets; /* Targets of the rule. */ 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 commands *cmds; /* Commands to execute. */ + unsigned short num; /* Number of targets. */ char terminal; /* If terminal (double-colon). */ char in_use; /* If in use by a parent pattern_search. */ }; @@ -49,10 +51,9 @@ extern struct file *suffix_file; 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 convert_to_pattern (void); -void create_pattern_rule (char **targets, char **target_percents, - int terminal, struct dep *deps, +void install_pattern_rule (struct pspec *p, int terminal); +void create_pattern_rule (const char **targets, const char **target_percents, + unsigned int num, int terminal, struct dep *deps, struct commands *commands, int override); @@ -20,8 +20,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "hash.h" -/* The size (in bytes) of each cache buffer. */ -#define CACHE_BUFFER_SIZE (4096) +/* The size (in bytes) of each cache buffer. + 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 @@ -39,6 +40,11 @@ struct strcache { static int bufsize = CACHE_BUFFER_SIZE; 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 * new_cache() { @@ -61,9 +67,9 @@ add_string(const char *str, int len) struct strcache *sp; const char *res; - /* If the string we want is too large to fit into a single buffer, then we're - screwed; nothing will ever fit! Change the maximum size of the cache to - be big enough. */ + /* If the string we want is too large to fit into a single buffer, then + we're screwed; nothing will ever fit! Change the maximum size of the + cache to be big enough. */ if (len > bufsize) bufsize = len * 2; @@ -113,6 +119,7 @@ str_hash_cmp (const void *x, const void *y) } static struct hash_table strings; +static unsigned long total_adds = 0; static const char * 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); const char *key = *slot; + /* Count the total number of adds we performed. */ + ++total_adds; + if (!HASH_VACANT (key)) return key; @@ -179,7 +189,7 @@ strcache_setbufsize(int size) 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 totsize = 0, avgsize, maxsize = 0, minsize = 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; - int sz = (sp->end - sp->buffer) + bf; + const struct strcache *sp; + + /* Count the first buffer separately since it's not full. */ + lastused = strcache->end - strcache->buffer; + lastfree = strcache->bytesfree; + + for (sp = strcache->next; sp != NULL; sp = sp->next) + { + int bf = sp->bytesfree; + int sz = sp->end - sp->buffer; - ++numbuffs; - numstrs += sp->count; + ++numbuffs; + numstrs += sp->count; - totsize += sz; - maxsize = (sz > maxsize ? sz : maxsize); - minsize = (sz < minsize ? sz : minsize); + totsize += sz; + maxsize = (sz > maxsize ? sz : maxsize); + minsize = (sz < minsize ? sz : minsize); - totfree += bf; - maxfree = (bf > maxfree ? bf : maxfree); - minfree = (bf < minfree ? bf : minfree); + totfree += bf; + maxfree = (bf > maxfree ? bf : maxfree); + minfree = (bf < minfree ? bf : minfree); + } } avgsize = numbuffs ? (int)(totsize / numbuffs) : 0; avgfree = numbuffs ? (int)(totfree / numbuffs) : 0; - printf (_("\n%s # of strings in strcache: %d\n"), prefix, numstrs); - printf (_("%s # of strcache buffers: %d\n"), prefix, numbuffs); - printf (_("%s strcache size: total = %d / max = %d / min = %d / avg = %d\n"), - prefix, totsize, maxsize, minsize, avgsize); - printf (_("%s strcache free: total = %d / max = %d / min = %d / avg = %d\n"), - prefix, totfree, maxfree, minfree, avgfree); + printf (_("\n%s # of strings in strcache: %d / lookups = %lu / hits = %lu\n"), + prefix, numstrs, total_adds, (total_adds - numstrs)); + printf (_("%s # of strcache buffers: %d (* %d B/buffer = %d B)\n"), + prefix, (numbuffs + 1), bufsize, ((numbuffs + 1) * bufsize)); + printf (_("%s strcache used: total = %d (%d) / max = %d / min = %d / avg = %d\n"), + 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); } diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl index 0419fef..82e7c38 100755 --- a/tests/run_make_tests.pl +++ b/tests/run_make_tests.pl @@ -190,7 +190,8 @@ sub run_make_with_options { 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 diff --git a/tests/scripts/features/patternrules b/tests/scripts/features/patternrules index 90525ae..53ec704 100644 --- a/tests/scripts/features/patternrules +++ b/tests/scripts/features/patternrules @@ -10,9 +10,9 @@ $dir = cwd; $dir =~ s,.*/([^/]+)$,../$1,; -# TEST #1: Make sure that multiple patterns where the same target -# can be built are searched even if the first one fails -# to match properly. +# TEST #0: Make sure that multiple patterns where the same target +# can be built are searched even if the first one fails +# to match properly. # 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). # run_make_test(' @@ -69,7 +69,7 @@ foo.in: ; @: 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). # run_make_test(' @@ -96,7 +96,7 @@ $dir/foo.o"); 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). # run_make_test(' @@ -116,7 +116,7 @@ $(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). # run_make_test(' diff --git a/tests/test_driver.pl b/tests/test_driver.pl index dd1b33b..cefe80f 100644 --- a/tests/test_driver.pl +++ b/tests/test_driver.pl @@ -547,12 +547,10 @@ sub print_standard_usage local($plname,@moreusage) = @_; local($line); - print "Usage: perl $plname [testname] [-verbose] [-detail] [-keep]\n"; - print " [-profile] [-usage] [-help] " - . "[-debug]\n"; - foreach $line (@moreusage) - { - print " $line\n"; + print "usage:\t$plname [testname] [-verbose] [-detail] [-keep]\n"; + print "\t\t\t[-profile] [-usage] [-help] [-debug]\n"; + foreach (@moreusage) { + print "\t\t\t$_\n"; } } @@ -42,7 +42,7 @@ static struct pattern_var *last_pattern_var; /* Create a new pattern-specific variable struct. */ 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)); @@ -63,14 +63,14 @@ create_pattern_var (char *target, char *suffix) /* Look up a target in the pattern-specific variable list. */ 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; unsigned int targlen = strlen(target); for (p = start ? start->next : pattern_vars; p != 0; p = p->next) { - char *stem; + const char *stem; unsigned int stemlen; if (p->len > targlen) @@ -962,7 +962,7 @@ target_environment (struct file *file) strcmp(v->name, "PATH") == 0) convert_Path_to_windows32(value, ';'); #endif - *result++ = concat (v->name, "=", value); + *result++ = xstrdup (concat (v->name, "=", value)); free (value); } else @@ -972,7 +972,7 @@ target_environment (struct file *file) strcmp(v->name, "PATH") == 0) convert_Path_to_windows32(v->value, ';'); #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 * 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) { - char *p, *alloc_value = NULL; + const char *p; + char *alloc_value = NULL; struct variable *v; int append = 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. */ unsigned int oldlen, vallen; - char *val; + const char *val; + char *tp; val = value; if (v->recursive) @@ -1075,10 +1077,11 @@ do_variable_definition (const struct floc *flocp, const char *varname, oldlen = strlen (v->value); vallen = strlen (val); - p = alloca (oldlen + 1 + vallen + 1); - memcpy (p, v->value, oldlen); - p[oldlen] = ' '; - memcpy (&p[oldlen + 1], val, vallen + 1); + tp = alloca (oldlen + 1 + vallen + 1); + memcpy (tp, v->value, oldlen); + tp[oldlen] = ' '; + 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. */ 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), shellpath, origin, flavor == f_recursive, flocp); } else { - char *shellbase, *bslash; + const char *shellbase, *bslash; struct variable *pathv = lookup_variable ("PATH", 4); char *path_string; char *fake_env[2]; @@ -1147,13 +1149,12 @@ do_variable_definition (const struct floc *flocp, const char *varname, fake_env[1] = 0; 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), shellpath, origin, flavor == f_recursive, flocp); @@ -1473,7 +1474,7 @@ print_variable_data_base (void) /* Print all the local variables of FILE. */ void -print_file_variables (struct file *file) +print_file_variables (const struct file *file) { if (file->variables != 0) print_variable_set (file->variables->set, "# "); @@ -1500,7 +1501,7 @@ sync_Path_environment (void) * Create something WINDOWS32 world can grok */ convert_Path_to_windows32 (path, ';'); - environ_path = concat ("PATH", "=", path); + environ_path = xstrdup (concat ("PATH", "=", path)); putenv (environ_path); free (path); } @@ -99,9 +99,9 @@ struct variable_set_list struct pattern_var { struct pattern_var *next; - char *target; + const char *suffix; + const char *target; unsigned int len; - char *suffix; struct variable variable; }; @@ -123,10 +123,13 @@ void restore_variable_buffer (char *buf, unsigned int len); /* function.c */ int handle_function (char **op, const char **stringp); int pattern_matches (const char *pattern, const char *percent, const char *str); -char *subst_expand (char *o, char *text, char *subst, char *replace, - unsigned int slen, unsigned int rlen, int by_word); -char *patsubst_expand (char *o, char *text, char *pattern, char *replace, - char *pattern_percent, char *replace_percent); +char *subst_expand (char *o, const char *text, const char *subst, + const char *replace, unsigned int slen, unsigned int rlen, + int by_word); +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 */ 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 define_automatic_variables (void); 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 merge_variable_set_lists (struct variable_set_list **to_list, struct variable_set_list *from_list); 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_flavor flavor, 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); -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; @@ -48,12 +48,10 @@ static struct vpath *general_vpath; 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 - will be searched in the order given in the makefiles - and construct the list from the VPATH variable. */ +/* Reverse the chain of selective VPATH lists so they will be searched in the + order given in the makefiles and construct the list from the VPATH + variable. */ void build_vpath_lists () @@ -284,8 +282,8 @@ construct_vpath_list (char *pattern, char *dirpath) /* Set up the members. */ path->pattern = strcache_add (pattern); - path->percent = path->pattern + (percent - pattern); path->patlen = strlen (pattern); + path->percent = percent ? path->pattern + (percent - pattern) : 0; } else /* There were no entries, so free whatever space we allocated. */ @@ -308,57 +306,23 @@ gpath_search (const char *file, unsigned int len) 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 -vpath_search (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. */ +/* Search the given VPATH list for a directory where the name pointed to by + 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 + stat call was done). Otherwise we return NULL. */ - 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, +static const char * +selective_vpath_search (struct vpath *path, const char *file, FILE_TIMESTAMP *mtime_ptr) { int not_target; - char *name, *n; - char *filename; + char *name; + const char *n; + const char *filename; const char **vpath = path->searchpath; unsigned int maxvpath = path->maxlen; - register unsigned int i; + unsigned int i; unsigned int flen, vlen, name_dplen; 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 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; } - flen = strlen (*file); + flen = strlen (file); /* Split *FILE into a directory prefix and a name-within-directory. - NAME_DPLEN gets the length of the prefix; FILENAME gets the - pointer to the name-within-directory and FLEN is its length. */ + NAME_DPLEN gets the length of the prefix; FILENAME gets the pointer to + the name-within-directory and FLEN is its length. */ - n = strrchr (*file, '/'); + n = strrchr (file, '/'); #ifdef HAVE_DOS_PATHS /* We need the rightmost slash or backslash. */ { - char *bslash = strrchr(*file, '\\'); + const char *bslash = strrchr(file, '\\'); if (!n || bslash > n) n = bslash; } #endif - name_dplen = n != 0 ? n - *file : 0; - filename = name_dplen > 0 ? n + 1 : *file; + name_dplen = n != 0 ? n - file : 0; + filename = name_dplen > 0 ? n + 1 : file; if (name_dplen > 0) flen -= name_dplen + 1; - /* Allocate enough space for the biggest VPATH entry, - a slash, the directory prefix that came with *FILE, - another slash (although this one may not always be - necessary), the filename, and a null terminator. */ - name = xmalloc (maxvpath + 1 + name_dplen + 1 + flen + 1); + /* Get enough space for the biggest VPATH entry, a slash, the directory + prefix that came with FILE, another slash (although this one may not + always be necessary), the filename, and a null terminator. */ + name = alloca (maxvpath + 1 + name_dplen + 1 + flen + 1); /* Try each VPATH entry. */ for (i = 0; vpath[i] != 0; ++i) { 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]); - memcpy (n, vpath[i], vlen); - n += vlen; + memcpy (p, vpath[i], vlen); + p += vlen; /* Add the directory prefix already in *FILE. */ if (name_dplen > 0) { #ifndef VMS - *n++ = '/'; + *p++ = '/'; #endif - memcpy (n, *file, name_dplen); - n += name_dplen; + memcpy (p, file, name_dplen); + p += name_dplen; } #ifdef HAVE_DOS_PATHS /* Cause the next if to treat backslash and slash alike. */ - if (n != name && n[-1] == '\\' ) - n[-1] = '/'; + if (p != name && p[-1] == '\\' ) + p[-1] = '/'; #endif /* Now add the name-within-directory at the end of NAME. */ #ifndef VMS - if (n != name && n[-1] != '/') + if (p != name && p[-1] != '/') { - *n = '/'; - memcpy (n + 1, filename, flen + 1); + *p = '/'; + memcpy (p + 1, filename, flen + 1); } else #endif - memcpy (n, filename, flen + 1); + memcpy (p, filename, flen + 1); /* 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. @@ -479,7 +443,7 @@ selective_vpath_search (struct vpath *path, char **file, #else /* Clobber a null into the name at the last slash. 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 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 /* Put the slash back in NAME. */ - *n = '/'; + *p = '/'; #endif 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. - Store the name we found into *FILE for the caller. */ - - *file = savestring (name, (n + 1 - name) + flen); - - /* If we get here and mtime_ptr hasn't been set, record + If we get here and mtime_ptr hasn't been set, record UNKNOWN_MTIME to indicate this. */ if (mtime_ptr != 0) *mtime_ptr = UNKNOWN_MTIME; - free (name); - return 1; + /* Store the name we found and return it. */ + + 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; } |