From 8572d6adf04d397505770b0b0d5cfd91cf6a92a8 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 8 Jul 2002 02:26:47 +0000 Subject: Major updates in preparation for 3.80. New version of the manual, put into the doc subdir. Enhancements: $(eval ...) and $(value ...) functions, various bug fixes, etc. See the ChangeLog. More to come. --- variable.c | 316 ++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 176 insertions(+), 140 deletions(-) (limited to 'variable.c') diff --git a/variable.c b/variable.c index 148e081..ca9265c 100644 --- a/variable.c +++ b/variable.c @@ -57,7 +57,7 @@ struct variable_set_list *current_variable_set_list = &global_setlist; struct variable * define_variable_in_set (name, length, value, origin, recursive, set, flocp) - char *name; + const char *name; unsigned int length; char *value; enum variable_origin origin; @@ -69,6 +69,9 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp) register unsigned int hashval; register struct variable *v; + if (set == NULL) + set = &global_variable_set; + hashval = 0; for (i = 0; i < length; ++i) HASH (hashval, name[i]); @@ -741,117 +744,27 @@ target_environment (file) return result; } -/* Try to interpret LINE (a null-terminated string) as a variable definition. - - ORIGIN may be o_file, o_override, o_env, o_env_override, - or o_command specifying that the variable definition comes - from a makefile, an override directive, the environment with - or without the -e switch, or the command line. - - See the comments for parse_variable_definition(). - - If LINE was recognized as a variable definition, a pointer to its `struct - variable' is returned. If LINE is not a variable definition, NULL is - returned. */ +/* Given a variable, a value, and a flavor, define the variable. + See the try_variable_definition() function for details on the parameters. */ struct variable * -try_variable_definition (flocp, line, origin, target_var) +do_variable_definition (flocp, varname, value, origin, flavor, target_var) const struct floc *flocp; - char *line; + const char *varname; + char *value; enum variable_origin origin; + enum variable_flavor flavor; int target_var; { - register int c; - register char *p = line; - register char *beg; - register char *end; - enum { f_bogus, - f_simple, f_recursive, f_append, f_conditional } flavor = f_bogus; - char *name, *expanded_name, *value=0, *alloc_value=NULL; + char *p, *alloc_value = NULL; struct variable *v; int append = 0; - while (1) - { - c = *p++; - if (c == '\0' || c == '#') - return 0; - if (c == '=') - { - end = p - 1; - flavor = f_recursive; - break; - } - else if (c == ':') - if (*p == '=') - { - end = p++ - 1; - flavor = f_simple; - break; - } - else - /* A colon other than := is a rule line, not a variable defn. */ - return 0; - else if (c == '+' && *p == '=') - { - end = p++ - 1; - flavor = f_append; - break; - } - else if (c == '?' && *p == '=') - { - end = p++ - 1; - flavor = f_conditional; - break; - } - else if (c == '$') - { - /* This might begin a variable expansion reference. Make sure we - don't misrecognize chars inside the reference as =, := or +=. */ - char closeparen; - int count; - c = *p++; - if (c == '(') - closeparen = ')'; - else if (c == '{') - closeparen = '}'; - else - continue; /* Nope. */ - - /* P now points past the opening paren or brace. - Count parens or braces until it is matched. */ - count = 0; - for (; *p != '\0'; ++p) - { - if (*p == c) - ++count; - else if (*p == closeparen && --count < 0) - { - ++p; - break; - } - } - } - } - - beg = next_token (line); - while (end > beg && isblank ((unsigned char)end[-1])) - --end; - p = next_token (p); - - /* Expand the name, so "$(foo)bar = baz" works. */ - name = (char *) alloca (end - beg + 1); - bcopy (beg, name, end - beg); - name[end - beg] = '\0'; - expanded_name = allocated_variable_expand (name); - - if (expanded_name[0] == '\0') - fatal (flocp, _("empty variable name")); - /* Calculate the variable's new value in VALUE. */ switch (flavor) { + default: case f_bogus: /* Should not be possible. */ abort (); @@ -860,23 +773,21 @@ try_variable_definition (flocp, line, origin, target_var) We have to allocate memory since otherwise it'll clobber the variable buffer, and we may still need that if we're looking at a target-specific variable. */ - value = alloc_value = allocated_variable_expand (p); + p = alloc_value = allocated_variable_expand (value); break; case f_conditional: /* A conditional variable definition "var ?= value". The value is set IFF the variable is not defined yet. */ - v = lookup_variable(expanded_name, strlen(expanded_name)); + v = lookup_variable (varname, strlen (varname)); if (v) - { - free(expanded_name); - return v; - } + return v; + flavor = f_recursive; /* FALLTHROUGH */ case f_recursive: /* A recursive variable definition "var = value". The value is used verbatim. */ - value = p; + p = value; break; case f_append: { @@ -885,17 +796,17 @@ try_variable_definition (flocp, line, origin, target_var) if (target_var) { append = 1; - v = lookup_variable_in_set (expanded_name, strlen (expanded_name), + v = lookup_variable_in_set (varname, strlen (varname), current_variable_set_list->set); } else - v = lookup_variable (expanded_name, strlen (expanded_name)); + v = lookup_variable (varname, strlen (varname)); if (v == 0) { /* There was no old value. This becomes a normal recursive definition. */ - value = p; + p = value; flavor = f_recursive; } else @@ -904,6 +815,7 @@ try_variable_definition (flocp, line, origin, target_var) unsigned int oldlen, newlen; + p = value; if (v->recursive) /* The previous definition of the variable was recursive. The new value is the unexpanded old and new values. */ @@ -918,10 +830,10 @@ try_variable_definition (flocp, line, origin, target_var) oldlen = strlen (v->value); newlen = strlen (p); - value = (char *) alloca (oldlen + 1 + newlen + 1); - bcopy (v->value, value, oldlen); - value[oldlen] = ' '; - bcopy (p, &value[oldlen + 1], newlen + 1); + p = (char *) alloca (oldlen + 1 + newlen + 1); + bcopy (v->value, p, oldlen); + p[oldlen] = ' '; + bcopy (value, &p[oldlen + 1], newlen + 1); } } } @@ -941,13 +853,13 @@ try_variable_definition (flocp, line, origin, target_var) your $PATH, then SHELL=/usr/local/bin/bash will have the effect of defining SHELL to be "d:/unix/bash.exe". */ if ((origin == o_file || origin == o_override) - && strcmp (expanded_name, "SHELL") == 0) + && strcmp (varname, "SHELL") == 0) { char shellpath[PATH_MAX]; extern char * __dosexec_find_on_path (const char *, char *[], char *); /* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */ - if (__dosexec_find_on_path (value, (char **)0, shellpath)) + if (__dosexec_find_on_path (p, (char **)0, shellpath)) { char *p; @@ -956,7 +868,7 @@ try_variable_definition (flocp, line, origin, target_var) if (*p == '\\') *p = '/'; } - v = define_variable_loc (expanded_name, strlen (expanded_name), + v = define_variable_loc (varname, strlen (varname), shellpath, origin, flavor == f_recursive, flocp); } @@ -968,16 +880,16 @@ try_variable_definition (flocp, line, origin, target_var) char *fake_env[2]; size_t pathlen = 0; - shellbase = strrchr (value, '/'); - bslash = strrchr (value, '\\'); + shellbase = strrchr (p, '/'); + bslash = strrchr (p, '\\'); if (!shellbase || bslash > shellbase) shellbase = bslash; - if (!shellbase && value[1] == ':') - shellbase = value + 1; + if (!shellbase && p[1] == ':') + shellbase = p + 1; if (shellbase) shellbase++; else - shellbase = value; + shellbase = p; /* Search for the basename of the shell (with standard executable extensions) along the $PATH. */ @@ -997,12 +909,12 @@ try_variable_definition (flocp, line, origin, target_var) if (*p == '\\') *p = '/'; } - v = define_variable_loc (expanded_name, strlen (expanded_name), + v = define_variable_loc (varname, strlen (varname), shellpath, origin, flavor == f_recursive, flocp); } else - v = lookup_variable (expanded_name, strlen (expanded_name)); + v = lookup_variable (varname, strlen (varname)); free (path_string); } @@ -1010,33 +922,157 @@ try_variable_definition (flocp, line, origin, target_var) else #endif /* __MSDOS__ */ #ifdef WINDOWS32 - if ((origin == o_file || origin == o_override) - && strcmp (expanded_name, "SHELL") == 0) + if ((origin == o_file || origin == o_override) && streq (varname, "SHELL")) { - extern char* default_shell; + extern char *default_shell; - /* - * Call shell locator function. If it returns TRUE, then - * set no_default_sh_exe to indicate sh was found and - * set new value for SHELL variable. - */ - if (find_and_set_default_shell(value)) { - v = define_variable_loc (expanded_name, strlen (expanded_name), - default_shell, origin, flavor == f_recursive, - flocp); - no_default_sh_exe = 0; - } + /* Call shell locator function. If it returns TRUE, then + set no_default_sh_exe to indicate sh was found and + set new value for SHELL variable. */ + + if (find_and_set_default_shell (p)) + { + v = define_variable_in_set (varname, strlen (varname), default_shell, + origin, flavor == f_recursive, + (target_var + ? current_variable_set_list->set + : NULL), + flocp); + no_default_sh_exe = 0; + } + else + v = lookup_variable (varname, strlen (varname)); } else #endif - v = define_variable_loc (expanded_name, strlen (expanded_name), value, - origin, flavor == f_recursive, flocp); - + /* If we are defining variables inside an $(eval ...), we might have a + different variable context pushed, not the global context (maybe we're + inside a $(call ...) or something. Since this function is only ever + invoked in places where we want to define globally visible variables, + make sure we define this variable in the global set. */ + + v = define_variable_in_set (varname, strlen (varname), p, + origin, flavor == f_recursive, + (target_var + ? current_variable_set_list->set : NULL), + flocp); v->append = append; if (alloc_value) free (alloc_value); + + return v; +} + +/* Try to interpret LINE (a null-terminated string) as a variable definition. + + ORIGIN may be o_file, o_override, o_env, o_env_override, + or o_command specifying that the variable definition comes + from a makefile, an override directive, the environment with + or without the -e switch, or the command line. + + See the comments for parse_variable_definition(). + + If LINE was recognized as a variable definition, a pointer to its `struct + variable' is returned. If LINE is not a variable definition, NULL is + returned. */ + +struct variable * +try_variable_definition (flocp, line, origin, target_var) + const struct floc *flocp; + char *line; + enum variable_origin origin; + int target_var; +{ + register int c; + register char *p = line; + register char *beg; + register char *end; + enum variable_flavor flavor = f_bogus; + char *name, *expanded_name; + struct variable *v; + + while (1) + { + c = *p++; + if (c == '\0' || c == '#') + return 0; + if (c == '=') + { + end = p - 1; + flavor = f_recursive; + break; + } + else if (c == ':') + if (*p == '=') + { + end = p++ - 1; + flavor = f_simple; + break; + } + else + /* A colon other than := is a rule line, not a variable defn. */ + return 0; + else if (c == '+' && *p == '=') + { + end = p++ - 1; + flavor = f_append; + break; + } + else if (c == '?' && *p == '=') + { + end = p++ - 1; + flavor = f_conditional; + break; + } + else if (c == '$') + { + /* This might begin a variable expansion reference. Make sure we + don't misrecognize chars inside the reference as =, := or +=. */ + char closeparen; + int count; + c = *p++; + if (c == '(') + closeparen = ')'; + else if (c == '{') + closeparen = '}'; + else + continue; /* Nope. */ + + /* P now points past the opening paren or brace. + Count parens or braces until it is matched. */ + count = 0; + for (; *p != '\0'; ++p) + { + if (*p == c) + ++count; + else if (*p == closeparen && --count < 0) + { + ++p; + break; + } + } + } + } + + beg = next_token (line); + while (end > beg && isblank ((unsigned char)end[-1])) + --end; + p = next_token (p); + + /* Expand the name, so "$(foo)bar = baz" works. */ + name = (char *) alloca (end - beg + 1); + bcopy (beg, name, end - beg); + name[end - beg] = '\0'; + expanded_name = allocated_variable_expand (name); + + if (expanded_name[0] == '\0') + fatal (flocp, _("empty variable name")); + + v = do_variable_definition (flocp, expanded_name, p, + origin, flavor, target_var); + free (expanded_name); return v; -- cgit v1.2.3