diff options
-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; } |