From 8f2b1e2c7c1ced20354dcbcd08942256cf0dade0 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Sun, 21 Jan 2001 06:49:11 +0000 Subject: [PATCH] Some bug fixes and document updates. --- ChangeLog | 40 ++++++++ build_w32.bat | 1 + expand.c | 86 +++++++++------- gettext.c | 9 +- make.texinfo | 34 ++++--- remake.c | 4 +- tests/scripts/features/targetvars | 24 +++++ variable.c | 156 ++++++++++++------------------ variable.h | 5 +- 9 files changed, 214 insertions(+), 145 deletions(-) diff --git a/ChangeLog b/ChangeLog index 361e0430..966cb4a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +2001-01-17 Paul D. Smith + + * variable.c (lookup_variable) [VMS]: When getting values from the + environment, allocate enough space for the _value_ plus escapes, + not enough space for the name plus escapes :-/. + Reported by John Fowler . + + * remake.c (f_mtime): Removed the "***" prefix from the mod time + warnings that make generates, so it doesn't look like an error. + Reported by Karl Berry . + + + Fix for PR/2020: Rework appended target-specific variables. I'm + fairly confident this algorithm is finally correct. + + * expand.c (allocated_variable_append): Rewrite. Instead of + expanding each appended variable then adding all the expanded + strings together, we append all the unexpanded values going up + through the variable set contexts, then expand the final result. + This behaves just like non-target-specific appended variable + values, while the old way didn't in various corner cases. + (variable_append): New function: recursively append the unexpanded + value of a variable, walking from the outermost variable scope to + the innermost. + * variable.c (lookup_variable): Remove the code that looked up the + variable set list if the found variable was "append". We don't + need this anymore. + (lookup_variable_in_set): Make this non-static so we can use it + elsewhere. + (try_variable_definition): Use lookup_variable_in_set() rather + than faking out current_variable_set_list by hand (cleanup). + * variable.h: Add a prototype for the now non-static + lookup_variable_in_set(). + 2000-11-17 Paul D. Smith * remake.c (f_mtime) [WINDOWS32]: On various advice, I changed the @@ -11,6 +45,12 @@ the need for len or lastlen at all. Problem description with sample code chages provided by Chris Faylor . +2000-10-24 Paul D. Smith + + * gettext.c (SWAP): Declare this with the prototype, otherwise + some systems don't work (non-32-bit? Reported for Cray T3E). + Reported by Thorstein Thorsteinsson . + 2000-10-05 Paul D. Smith * acinclude.m4 (AM_LC_MESSAGES): Remove undefined macro diff --git a/build_w32.bat b/build_w32.bat index 7ff771f2..559fe8d3 100644 --- a/build_w32.bat +++ b/build_w32.bat @@ -1,4 +1,5 @@ set make=gnumake ++if not exist config.h copy config.h.W32 config.h cd w32\subproc echo "Creating the subproc library" %ComSpec% /c build.bat diff --git a/expand.c b/expand.c index 8ada0cdf..e397cf47 100644 --- a/expand.c +++ b/expand.c @@ -92,7 +92,7 @@ initialize_variable_output () /* Recursively expand V. The returned string is malloc'd. */ -static char *allocated_variable_append PARAMS ((struct variable *v)); +static char *allocated_variable_append PARAMS ((const struct variable *v)); char * recursively_expand (v) @@ -469,52 +469,72 @@ variable_expand_for_file (line, file) return result; } -/* Like allocated_variable_expand, but we first expand this variable in the - context of the next variable set, then we append the expanded value. */ +/* Like allocated_variable_expand, but for += target-specific variables. + First recursively construct the variable value from its appended parts in + any upper variable sets. Then expand the resulting value. */ + +static char * +variable_append (name, length, set) + const char *name; + unsigned int length; + const struct variable_set_list *set; +{ + const struct variable *v; + char *buf = 0; + + /* If there's nothing left to check, return the empty buffer. */ + if (!set) + return initialize_variable_output (); + + /* Try to find the variable in this variable set. */ + v = lookup_variable_in_set (name, length, set->set); + + /* If there isn't one, look to see if there's one in a set above us. */ + if (!v) + return variable_append (name, length, set->next); + + /* If this variable type is append, first get any upper values. + If not, initialize the buffer. */ + if (v->append) + buf = variable_append (name, length, set->next); + else + buf = initialize_variable_output (); + + /* Append this value to the buffer, and return it. + If we already have a value, first add a space. */ + if (buf > variable_buffer) + buf = variable_buffer_output (buf, " ", 1); + + return variable_buffer_output (buf, v->value, strlen (v->value)); +} + static char * allocated_variable_append (v) - struct variable *v; + const struct variable *v; { - struct variable_set_list *save; - int len = strlen (v->name); - char *var = alloca (len + 4); - char *value; + char *val, *retval; + + /* Construct the appended variable value. */ char *obuf = variable_buffer; unsigned int olen = variable_buffer_length; variable_buffer = 0; - assert(current_variable_set_list->next != 0); - save = current_variable_set_list; - current_variable_set_list = current_variable_set_list->next; - - var[0] = '$'; - var[1] = '('; - strcpy (&var[2], v->name); - var[len+2] = ')'; - var[len+3] = '\0'; - - value = variable_expand_for_file (var, 0); - - current_variable_set_list = save; - - value += strlen (value); - value = variable_buffer_output (value, " ", 1); - value = variable_expand_string (value, v->value, (long)-1); - - value = variable_buffer; - -#if 0 - /* Waste a little memory and save time. */ - value = xrealloc (value, strlen (value)) -#endif + val = variable_append (v->name, strlen (v->name), current_variable_set_list); + variable_buffer_output (val, "", 1); + val = variable_buffer; variable_buffer = obuf; variable_buffer_length = olen; - return value; + /* Now expand it and return that. */ + + retval = allocated_variable_expand (val); + + free (val); + return retval; } /* Like variable_expand_for_file, but the returned string is malloc'd. diff --git a/gettext.c b/gettext.c index 1ecb715b..b97df8db 100644 --- a/gettext.c +++ b/gettext.c @@ -786,9 +786,14 @@ struct string_desc #else static nls_uint32 SWAP PARAMS ((nls_uint32 i)); +/* Apparently on some (non-32-bit?) systems it's important to use the right + prototype. Reported for a CRAY T3E. */ static inline nls_uint32 -SWAP (i) - nls_uint32 i; +#if __STDC__ + SWAP (nls_uint32 i) +#else + SWAP (i) nls_uint32 i; +#endif { return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); } diff --git a/make.texinfo b/make.texinfo index ca05fba3..98a69856 100644 --- a/make.texinfo +++ b/make.texinfo @@ -1,4 +1,4 @@ -\input texinfo @c -*- Texinfo -*- +input texinfo @c -*- Texinfo -*- @c %**start of header @setfilename make.info @settitle GNU @code{make} @@ -2465,9 +2465,9 @@ chance of @command{make} incorrectly concluding that a file is up to date. Unfortunately, these hosts provide no way to set a high resolution file time stamp, so commands like @samp{cp -p} that explicitly set a file's time stamp must discard its subsecond part. If -a file is created by such a command, you should list it as a dependency -of @code{.LOW_RESOLUTION_TIME} so that @command{make} does not -mistakenly conclude that the file is out of date. For example: +a file is created by such a command, you should list it as a +prerequisite of @code{.LOW_RESOLUTION_TIME} so that @command{make} does +not mistakenly conclude that the file is out of date. For example: @example @group @@ -2485,7 +2485,7 @@ is at the start of the same second that @file{src}'s time stamp is in. Due to a limitation of the archive format, archive member time stamps are always low resolution. You need not list archive members as -dependencies of @code{.LOW_RESOLUTION_TIME}, as @command{make} does this +prerequisites of @code{.LOW_RESOLUTION_TIME}, as @command{make} does this automatically. @findex .SILENT @@ -2682,7 +2682,7 @@ be @emph{analogous}, but not necessarily @emph{identical}. Here is the syntax of a static pattern rule: @example -@var{targets} @dots{}: @var{target-pattern}: @var{dep-patterns} @dots{} +@var{targets} @dots{}: @var{target-pattern}: @var{prereq-patterns} @dots{} @var{commands} @dots{} @end example @@ -2695,11 +2695,11 @@ Names}). @cindex target pattern, static (not implicit) @cindex stem -The @var{target-pattern} and @var{dep-patterns} say how to compute the +The @var{target-pattern} and @var{prereq-patterns} say how to compute the prerequisites of each target. Each target is matched against the @var{target-pattern} to extract a part of the target name, called the -@dfn{stem}. This stem is substituted into each of the @var{dep-patterns} -to make the prerequisite names (one from each @var{dep-pattern}). +@dfn{stem}. This stem is substituted into each of the @var{prereq-patterns} +to make the prerequisite names (one from each @var{prereq-pattern}). Each pattern normally contains the character @samp{%} just once. When the @var{target-pattern} matches a target, the @samp{%} can match any part of @@ -2838,10 +2838,12 @@ to precisely the targets specified. ordinary rules when the same target appears in more than one rule. When a target appears in multiple rules, all the rules must be the same -type: all ordinary, or all double-colon. If they are double-colon, each of -them is independent of the others. Each double-colon rule's commands are -executed if the target is older than any prerequisites of that rule. This -can result in executing none, any, or all of the double-colon rules. +type: all ordinary, or all double-colon. If they are double-colon, each +of them is independent of the others. Each double-colon rule's commands +are executed if the target is older than any prerequisites of that rule. +If there are no prerequisites for that rule, its commands are always +executed (even if the target already exists). This can result in +executing none, any, or all of the double-colon rules. Double-colon rules with the same target are in fact completely separate from one another. Each double-colon rule is processed individually, just @@ -5481,7 +5483,9 @@ Finds whitespace-separated words in @var{text} that match @var{pattern} may contain a @samp{%} which acts as a wildcard, matching any number of any characters within a word. If @var{replacement} also contains a @samp{%}, the @samp{%} is replaced -by the text that matched the @samp{%} in @var{pattern}.@refill +by the text that matched the @samp{%} in @var{pattern}. Only the first +@samp{%} in the @var{pattern} and @var{replacement} is treated this +way; any subsequent @samp{%} is unchanged.@refill @cindex @code{%}, quoting in @code{patsubst} @cindex @code{%}, quoting with @code{\} (backslash) @@ -8125,7 +8129,7 @@ appending @samp{D} or @samp{F}, respectively. These variants are semi-obsolete in GNU @code{make} since the functions @code{dir} and @code{notdir} can be used to get a similar effect (@pxref{File Name Functions, , Functions for File Names}). Note, however, that the -@samp{F} variants all omit the trailing slash which always appears in +@samp{D} variants all omit the trailing slash which always appears in the output of the @code{dir} function. Here is a table of the variants: @table @samp diff --git a/remake.c b/remake.c index f036b53e..06e8d316 100644 --- a/remake.c +++ b/remake.c @@ -1190,14 +1190,14 @@ f_mtime (file, search) if (adjusted_now < adjusted_mtime) { #ifdef NO_FLOAT - error (NILF, _("*** Warning: File `%s' has modification time in the future"), + error (NILF, _("Warning: File `%s' has modification time in the future"), file->name); #else double from_now = (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) / 1e9)); - error (NILF, _("*** Warning: File `%s' has modification time %.2g s in the future"), + error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"), file->name, from_now); #endif clock_skew_detected = 1; diff --git a/tests/scripts/features/targetvars b/tests/scripts/features/targetvars index a1bd88e5..a70d3ab6 100644 --- a/tests/scripts/features/targetvars +++ b/tests/scripts/features/targetvars @@ -170,5 +170,29 @@ close(MAKEFILE); $answer = "; ok\n"; &compare_output($answer, &get_logfile(1)); +# Test #12 +# PR/2020: More hassles with += target-specific vars. I _really_ think +# I nailed it this time :-/. + +$makefile5 = &get_tmpfile; + +open(MAKEFILE, "> $makefile5"); +print MAKEFILE <<'EOF'; +.PHONY: a + +BLAH := foo +COMMAND = echo $(BLAH) + +a: ; @$(COMMAND) + +a: BLAH := bar +a: COMMAND += snafu $(BLAH) +EOF +close(MAKEFILE); + +&run_make_with_options("$makefile5", "", &get_logfile); +$answer = "bar snafu bar\n"; +&compare_output($answer, &get_logfile(1)); + 1; diff --git a/variable.c b/variable.c index 75ceb78d..f28e83cd 100644 --- a/variable.c +++ b/variable.c @@ -45,9 +45,6 @@ static struct variable_set global_variable_set static struct variable_set_list global_setlist = { 0, &global_variable_set }; struct variable_set_list *current_variable_set_list = &global_setlist; - -static struct variable *lookup_variable_in_set PARAMS ((char *name, - unsigned int length, struct variable_set *set)); /* Implement variables. */ @@ -134,23 +131,17 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp) /* Lookup a variable whose name is a string starting at NAME and with LENGTH chars. NAME need not be null-terminated. Returns address of the `struct variable' containing all info - on the variable, or nil if no such variable is defined. - - If we find a variable which is in the process of being expanded, - try to find one further up the set_list chain. If we don't find - one that isn't being expanded, return a pointer to whatever we - _did_ find. */ + on the variable, or nil if no such variable is defined. */ struct variable * lookup_variable (name, length) - char *name; + const char *name; unsigned int length; { - register struct variable_set_list *setlist; - struct variable *firstv = 0; + const struct variable_set_list *setlist; - register unsigned int i; - register unsigned int rawhash = 0; + unsigned int i; + unsigned int rawhash = 0; for (i = 0; i < length; ++i) HASH (rawhash, name[i]); @@ -158,88 +149,74 @@ lookup_variable (name, length) for (setlist = current_variable_set_list; setlist != 0; setlist = setlist->next) { - register struct variable_set *set = setlist->set; - register unsigned int hashval = rawhash % set->buckets; - register struct variable *v; + const struct variable_set *set = setlist->set; + unsigned int hashval = rawhash % set->buckets; + struct variable *v; - /* Look through this set list. */ + /* Look through this set list; return it if found. */ for (v = set->table[hashval]; v != 0; v = v->next) if (*v->name == *name && strneq (v->name + 1, name + 1, length - 1) && v->name[length] == '\0') - break; - - /* If we didn't find anything, go to the next set list. */ - if (!v) - continue; - - /* If it's not being expanded already, we're done. */ - if (!v->expanding) - return v; - - /* It is, so try to find another one. If this is the first one we've - seen, keep a pointer in case we don't find anything else. */ - if (!firstv) - firstv = v; + return v; } #ifdef VMS /* since we don't read envp[] on startup, try to get the variable via getenv() here. */ - if (!firstv) - { - char *vname = alloca (length + 1); - char *value; - strncpy (vname, name, length); - vname[length] = 0; - value = getenv (vname); - if (value != 0) - { - char *sptr; - int scnt; + { + char *vname = alloca (length + 1); + char *value; + strncpy (vname, name, length); + vname[length] = 0; + value = getenv (vname); + if (value != 0) + { + char *sptr; + int scnt; - sptr = value; - scnt = 0; + sptr = value; + scnt = 0; - while ((sptr = strchr (sptr, '$'))) - { - scnt++; - sptr++; - } + while ((sptr = strchr (sptr, '$'))) + { + scnt++; + sptr++; + } - if (scnt > 0) - { - char *nvalue; - char *nptr; + if (scnt > 0) + { + char *nvalue; + char *nptr; - nvalue = alloca (length + scnt + 1); - sptr = value; - nptr = nvalue; + nvalue = alloca (strlen (value) + scnt + 1); + sptr = value; + nptr = nvalue; - while (*sptr) - { - if (*sptr == '$') - { - *nptr++ = '$'; - *nptr++ = '$'; - } - else - { - *nptr++ = *sptr; - } - sptr++; - } + while (*sptr) + { + if (*sptr == '$') + { + *nptr++ = '$'; + *nptr++ = '$'; + } + else + { + *nptr++ = *sptr; + } + sptr++; + } - return define_variable (vname, length, nvalue, o_env, 1); + return define_variable (vname, length, nvalue, o_env, 1); - } + } - return define_variable (vname, length, value, o_env, 1); - } - } + return define_variable (vname, length, value, o_env, 1); + } + } #endif /* VMS */ - return firstv; + return 0; } /* Lookup a variable whose name is a string starting at NAME @@ -247,15 +224,15 @@ lookup_variable (name, length) Returns address of the `struct variable' containing all info on the variable, or nil if no such variable is defined. */ -static struct variable * +struct variable * lookup_variable_in_set (name, length, set) - char *name; + const char *name; unsigned int length; - struct variable_set *set; + const struct variable_set *set; { - register unsigned int i; - register unsigned int hash = 0; - register struct variable *v; + unsigned int i; + unsigned int hash = 0; + struct variable *v; for (i = 0; i < length; ++i) HASH (hash, name[i]); @@ -788,7 +765,7 @@ try_variable_definition (flocp, line, origin, target_var) register char *end; enum { f_bogus, f_simple, f_recursive, f_append, f_conditional } flavor = f_bogus; - char *name, *expanded_name, *value, *alloc_value=NULL; + char *name, *expanded_name, *value=0, *alloc_value=NULL; struct variable *v; int append = 0; @@ -901,21 +878,16 @@ try_variable_definition (flocp, line, origin, target_var) break; case f_append: { - struct variable_set_list *saved_next = current_variable_set_list->next; - /* If we have += but we're in a target variable context, we want to append only with other variables in the context of this target. */ if (target_var) { append = 1; - current_variable_set_list->next = 0; + v = lookup_variable_in_set (expanded_name, strlen (expanded_name), + current_variable_set_list->set); } - - /* An appending variable definition "var += value". - Extract the old value and append the new one. */ - v = lookup_variable (expanded_name, strlen (expanded_name)); - - current_variable_set_list->next = saved_next; + else + v = lookup_variable (expanded_name, strlen (expanded_name)); if (v == 0) { diff --git a/variable.h b/variable.h index d449ef82..9c23511b 100644 --- a/variable.h +++ b/variable.h @@ -108,7 +108,10 @@ extern void print_variable_set PARAMS ((struct variable_set *set, char *prefix)) extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1)); extern struct variable *try_variable_definition PARAMS ((const struct floc *flocp, char *line, enum variable_origin origin, int target_var)); -extern struct variable *lookup_variable PARAMS ((char *name, unsigned int length)); +extern struct variable *lookup_variable PARAMS ((const char *name, unsigned int length)); +extern struct variable *lookup_variable_in_set PARAMS ((const char *name, + unsigned int length, + const struct variable_set *set)); extern struct variable *define_variable_in_set PARAMS ((char *name, unsigned int length, char *value,