diff options
author | Marc Espie <espie@cvs.openbsd.org> | 2001-05-23 12:34:58 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 2001-05-23 12:34:58 +0000 |
commit | db8e89b77998123612f763908cdd1c46cc7ea24f (patch) | |
tree | af42f9f2b44b6bae3a6ca23660ff612c49709e27 /usr.bin/make/parsevar.c | |
parent | d0640eab6718b3ff0eeb66e78aa4d5d8a8ed3c24 (diff) |
Mostly clean-up:
- cut up those huge include files into separate interfaces for all modules.
Put the interface documentation there, and not with the implementation.
- light-weight includes for needed concrete types (lst_t.h, timestamp_t.h).
- cut out some more logically separate parts: cmd_exec, varname, parsevar,
timestamp.
- put all error handling functions together, so that we will be able to
clean them up.
- more systematic naming: functioni to handle interval, function to handle
string.
- put the init/end code apart to minimize coupling.
- kill weird types like ReturnStatus and Boolean. Use standard bool (with a
fallback for non-iso systems)
- better interface documentation for lots of subsystems.
As a result, make compilation goes somewhat faster (5%, even considering
the largish BSD copyrights to read). The corresponding preprocessed
source goes down from 1,5M to 1M.
A few minor code changes as well: Parse_DoVar is no longer destructive.
Parse_IsVar functionality is folded into Parse_DoVar (as it knows what an
assignment is), a few more interval handling functions. Avoid calling
XXX_End when they do nothing, just #define XXX_End to nothing.
Parse_DoVar is slightly more general: it will handle compound assignments
as long as they make sense, e.g., VAR +!= cmd
will work. As a side effect, VAR++=value now triggers an error
(two + in assignment).
- this stuff doesn't occur in portable Makefiles.
- writing VAR++ = value or VAR+ +=value disambiguates it.
- this is a good thing, it uncovered a bug in bsd.port.mk.
Tested by naddy@. Okayed millert@. I'll handle the fallback if there is
any. This went through a full make build anyways, including isakmpd
(without mickey's custom binutils, as he didn't see fit to share it with me).
Diffstat (limited to 'usr.bin/make/parsevar.c')
-rw-r--r-- | usr.bin/make/parsevar.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/usr.bin/make/parsevar.c b/usr.bin/make/parsevar.c new file mode 100644 index 00000000000..a6dba3803de --- /dev/null +++ b/usr.bin/make/parsevar.c @@ -0,0 +1,210 @@ +/* $OpenPackages$ */ +/* $OpenBSD: parsevar.c,v 1.1 2001/05/23 12:34:48 espie Exp $ */ +/* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */ + +/* + * Copyright (c) 2001 Marc Espie. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD + * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <ctype.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "config.h" +#include "defines.h" +#include "var.h" +#include "varname.h" +#include "error.h" +#include "cmd_exec.h" +#include "parsevar.h" + +static const char *find_op1(const char *); +static const char *find_op2(const char *); + +static const char * +find_op1(p) + const char *p; +{ + for(;; p++) { + if (isspace(*p) || *p == '$' || *p == '\0') + break; + if (p[strspn(p, "?:!+")] == '=') + break; + if (p[0] == ':' && p[1] == 's' && p[2] == 'h') + break; + } + return p; +} + +static const char * +find_op2(p) + const char *p; +{ + for(;; p++) { + if (isspace(*p) || *p == '$' || *p == '\0') + break; + if (p[strspn(p, "?:!+")] == '=') + break; + } + return p; +} + +bool +Parse_DoVar(line, ctxt) + const char *line; + GSymT *ctxt; /* Context in which to do the assignment */ +{ + const char *arg; + char *res1 = NULL, *res2 = NULL; +#define VAR_NORMAL 0 +#define VAR_SUBST 1 +#define VAR_APPEND 2 +#define VAR_SHELL 4 +#define VAR_OPT 8 + int type; /* Type of assignment */ + struct Name name; + + arg = VarName_Get(line, &name, (SymTable *)ctxt, true, + FEATURES(FEATURE_SUNSHCMD) ? find_op1 : find_op2); + + while (isspace(*arg)) + arg++; + + type = VAR_NORMAL; + + while (*arg != '=' && !isspace(*arg)) { + /* Check operator type. */ + switch (*arg++) { + case '+': + if (type & (VAR_OPT|VAR_APPEND)) { + VarName_Free(&name); + return false; + } + type |= VAR_APPEND; + break; + + case '?': + if (type & (VAR_OPT|VAR_APPEND)) { + VarName_Free(&name); + return false; + } + type |= VAR_OPT; + break; + + case ':': + if (FEATURES(FEATURE_SUNSHCMD) && strncmp(arg, "sh", 2) == 0) { + type = VAR_SHELL; + arg += 2; + while (*arg != '=' && *arg != '\0') + arg++; + } else { + if (type & VAR_SUBST) { + VarName_Free(&name); + return false; + } + type |= VAR_SUBST; + } + break; + + case '!': + if (type & VAR_SHELL) { + VarName_Free(&name); + return false; + } + type |= VAR_SHELL; + break; + + default: + VarName_Free(&name); + return false; + } + } + + /* Check validity of operator */ + if (*arg++ != '=') { + VarName_Free(&name); + return false; + } + + while (isspace(*arg)) + arg++; + /* If the variable already has a value, we don't do anything. */ + if ((type & VAR_OPT) && Var_Valuei(name.s, name.e) != NULL) { + VarName_Free(&name); + return true; + } + if (type & VAR_SHELL) { + char *err; + + if (strchr(arg, '$') != NULL) { + char *sub; + /* There's a dollar sign in the command, so perform variable + * expansion on the whole thing. */ + sub = Var_Subst(arg, NULL, true); + res1 = Cmd_Exec(sub, &err); + free(sub); + } else + res1 = Cmd_Exec(arg, &err); + + if (err) + Parse_Error(PARSE_WARNING, err, arg); + arg = res1; + } + if (type & VAR_SUBST) { + /* + * Allow variables in the old value to be undefined, but leave their + * invocation alone -- this is done by forcing oldVars to be false. + * XXX: This can cause recursive variables, but that's not hard to do, + * and this allows someone to do something like + * + * CFLAGS = $(.INCLUDES) + * CFLAGS := -I.. $(CFLAGS) + * + * And not get an error. + */ + bool oldOldVars = oldVars; + + oldVars = false; + /* ensure the variable is set to something to avoid `variable + * is recursive' errors. */ + if (Var_Valuei(name.s, name.e) == NULL) + Var_Seti(name.s, name.e, "", ctxt); + + res2 = Var_Subst(arg, (SymTable *)ctxt, false); + oldVars = oldOldVars; + + arg = res2; + } + + if (type & VAR_APPEND) + Var_Appendi(name.s, name.e, arg, ctxt); + else + Var_Seti(name.s, name.e, arg, ctxt); + + VarName_Free(&name); + free(res2); + free(res1); + return true; +} + |