Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make(1): split Parse_DoVar into manageable pieces



details:   https://anonhg.NetBSD.org/src/rev/9728bf650107
branches:  trunk
changeset: 944599:9728bf650107
user:      rillig <rillig%NetBSD.org@localhost>
date:      Sun Oct 04 16:43:22 2020 +0000

description:
make(1): split Parse_DoVar into manageable pieces

This makes it easier to eliminate duplicate code, for example in
Parse_IsVar and Parse_DoVar.

diffstat:

 usr.bin/make/parse.c |  201 +++++++++++++++++++++++++++++++++-----------------
 1 files changed, 133 insertions(+), 68 deletions(-)

diffs (282 lines):

diff -r 2fd92db0cf8c -r 9728bf650107 usr.bin/make/parse.c
--- a/usr.bin/make/parse.c      Sun Oct 04 16:23:04 2020 +0000
+++ b/usr.bin/make/parse.c      Sun Oct 04 16:43:22 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: parse.c,v 1.353 2020/10/04 14:40:13 rillig Exp $       */
+/*     $NetBSD: parse.c,v 1.354 2020/10/04 16:43:22 rillig Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -131,7 +131,7 @@
 #include "pathnames.h"
 
 /*     "@(#)parse.c    8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.353 2020/10/04 14:40:13 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.354 2020/10/04 16:43:22 rillig Exp $");
 
 /* types and constants */
 
@@ -204,6 +204,14 @@
     Attribute          /* Generic attribute */
 } ParseSpecial;
 
+typedef enum VarAssignOp {
+    VAR_NORMAL,                        /* = */
+    VAR_SUBST,                 /* := */
+    VAR_SHELL,                 /* != or :sh= */
+    VAR_APPEND,                        /* += */
+    VAR_DEFAULT                        /* ?= */
+} VarAssignOp;
+
 /* result data */
 
 /*
@@ -1727,56 +1735,18 @@
     return FALSE;
 }
 
-/* Take the variable assignment in the passed line and execute it.
- *
- * Note: There is a lexical ambiguity with assignment modifier characters
- * in variable names. This routine interprets the character before the =
- * as a modifier. Therefore, an assignment like
- *     C++=/usr/bin/CC
- * is interpreted as "C+ +=" instead of "C++ =".
- *
- * Input:
- *     p               A line guaranteed to be a variable assignment
- *                     (see Parse_IsVar).
- *     ctxt            Context in which to do the assignment
- */
-void
-Parse_DoVar(const char *p, GNode *ctxt)
+/*
+* Parse the variable name, up to the assignment operator.
+* XXX Rather than counting () and {} we should look for $ and
+* then expand the variable.
+*/
+static const char *
+ParseVarname(const char **pp)
 {
-    enum {
-       VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
-    } type;                    /* Type of assignment */
+    const char *p = *pp;
+    const char *nameEnd = NULL;
     int depth;
-    const char *name;
-    void *name_freeIt;
-    const char *uvalue;                /* unexpanded value */
-    const char *avalue;                /* actual value */
-    char *evalue = NULL;       /* expanded value */
-
-    /* The variable name consists of a single word (that is, no whitespace).
-     * It ends at the whitespace after that word (nameEnd).  If there is no
-     * whitespace, the name is followed directly by the assignment operator
-     * (op).  During parsing, the '+' of the '+=' operator is initially parsed
-     * as part of the variable name.  It is later corrected, as is the ':sh'
-     * modifier. Of these two (nameEnd and op), the earlier one determines the
-     * actual end of the variable name. */
-    const char *nameEnd, *op;
-
-    /*
-     * Skip to variable name
-     */
-    while (*p == ' ' || *p == '\t')
-       p++;
-
-    name = p;
-    name_freeIt = NULL;
-
-    /*
-     * Parse the variable name, up to the assignment operator.
-     * XXX Rather than counting () and {} we should look for $ and
-     * then expand the variable.
-     */
-    nameEnd = NULL;
+
     for (depth = 0; depth > 0 || *p != '='; p++) {
        if (*p == '(' || *p == '{') {
            depth++;
@@ -1794,32 +1764,47 @@
 
     if (nameEnd == NULL)
        nameEnd = p;
+
+    *pp = p;
+    return nameEnd;
+}
+
+static Boolean
+ParseVarassignOp(const char *p, const char *const nameEnd, const char **out_op,
+                const char **inout_name, VarAssignOp *out_type,
+                void **inout_name_freeIt, GNode *ctxt)
+{
+    const char *op;
+    const char *name = *inout_name;
+    void *name_freeIt = *inout_name_freeIt;
+    VarAssignOp type;
+
     op = p;                    /* points at the '=' */
 
     if (op > name && op[-1] == '+') {
-        type = VAR_APPEND;
-        op--;
+       type = VAR_APPEND;
+       op--;
 
     } else if (op > name && op[-1] == '?') {
        /* If the variable already has a value, we don't do anything. */
-        Boolean exists;
-
-        op--;
+       Boolean exists;
+
+       op--;
        name = name_freeIt = bmake_strsedup(name, nameEnd < op ? nameEnd : op);
-        exists = Var_Exists(name, ctxt);
+       exists = Var_Exists(name, ctxt);
        if (exists) {
            free(name_freeIt);
-           return;
+           return FALSE;
        }
        type = VAR_NORMAL;
 
     } else if (op > name && op[-1] == ':') {
-        op--;
+       op--;
        type = VAR_SUBST;
 
     } else if (op > name && op[-1] == '!') {
-        op--;
-        type = VAR_SHELL;
+       op--;
+       type = VAR_SHELL;
 
     } else {
        type = VAR_NORMAL;
@@ -1834,11 +1819,16 @@
 #endif
     }
 
-    p++;                       /* Skip the '=' */
-    cpp_skip_whitespace(&p);
-    uvalue = p;
-    avalue = uvalue;
-
+    *out_op = op;
+    *inout_name = name;
+    *out_type = type;
+    *inout_name_freeIt = name_freeIt;
+    return TRUE;
+}
+
+static void
+VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *ctxt)
+{
     if (DEBUG(LINT)) {
        if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) {
            /* Check for syntax errors such as unclosed expressions or
@@ -1850,9 +1840,15 @@
            free(expandedValue);
        }
     }
-
-    if (name_freeIt == NULL)
-       name = name_freeIt = bmake_strsedup(name, nameEnd < op ? nameEnd : op);
+}
+
+static void
+VarAssign(VarAssignOp const type, const char *const name,
+         const char *const uvalue, const char **out_avalue, char **out_evalue,
+         GNode *ctxt)
+{
+    const char *avalue = uvalue;
+    char *evalue = NULL;
 
     if (type == VAR_APPEND) {
        Var_Append(name, uvalue, ctxt);
@@ -1912,6 +1908,14 @@
         */
        Var_Set(name, uvalue, ctxt);
     }
+
+    *out_avalue = avalue;
+    *out_evalue = evalue;
+}
+
+static void
+VarAssignSpecial(const char *name, const char *avalue)
+{
     if (strcmp(name, MAKEOVERRIDES) == 0)
        Main_ExportMAKEFLAGS(FALSE);    /* re-export MAKEFLAGS */
     else if (strcmp(name, ".CURDIR") == 0) {
@@ -1927,6 +1931,67 @@
     } else if (strcmp(name, MAKE_EXPORTED) == 0) {
        Var_Export(avalue, FALSE);
     }
+}
+
+/* Take the variable assignment in the passed line and execute it.
+ *
+ * Note: There is a lexical ambiguity with assignment modifier characters
+ * in variable names. This routine interprets the character before the =
+ * as a modifier. Therefore, an assignment like
+ *     C++=/usr/bin/CC
+ * is interpreted as "C+ +=" instead of "C++ =".
+ *
+ * Input:
+ *     p               A line guaranteed to be a variable assignment
+ *                     (see Parse_IsVar).
+ *     ctxt            Context in which to do the assignment
+ */
+void
+Parse_DoVar(const char *p, GNode *ctxt)
+{
+    VarAssignOp type;
+    const char *name;
+    void *name_freeIt;
+    const char *uvalue;                /* unexpanded value */
+    const char *avalue;                /* actual value */
+    char *evalue = NULL;       /* expanded value */
+
+    /* The variable name consists of a single word (that is, no whitespace).
+     * It ends at the whitespace after that word (nameEnd).  If there is no
+     * whitespace, the name is followed directly by the assignment operator
+     * (op).  During parsing, the '+' of the '+=' operator is initially parsed
+     * as part of the variable name.  It is later corrected, as is the ':sh'
+     * modifier. Of these two (nameEnd and op), the earlier one determines the
+     * actual end of the variable name. */
+    const char *nameEnd, *op;
+
+    /*
+     * Skip to variable name
+     */
+    while (*p == ' ' || *p == '\t')
+       p++;
+
+    name = p;
+    name_freeIt = NULL;
+
+    nameEnd = ParseVarname(&p);
+
+    if (!ParseVarassignOp(p, nameEnd, &op, &name, &type, &name_freeIt, ctxt))
+       return;
+
+    p++;                       /* Skip the '=' */
+    cpp_skip_whitespace(&p);
+    uvalue = p;
+    avalue = uvalue;
+
+    VarCheckSyntax(type, uvalue, ctxt);
+
+    if (name_freeIt == NULL)
+       name = name_freeIt = bmake_strsedup(name, nameEnd < op ? nameEnd : op);
+
+    VarAssign(type, name, uvalue, &avalue, &evalue, ctxt);
+    VarAssignSpecial(name, avalue);
+
     free(evalue);
     free(name_freeIt);
 }



Home | Main Index | Thread Index | Old Index