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 ExportVar into separate functions



details:   https://anonhg.NetBSD.org/src/rev/630420aba003
branches:  trunk
changeset: 1017486:630420aba003
user:      rillig <rillig%NetBSD.org@localhost>
date:      Tue Dec 29 03:05:15 2020 +0000

description:
make(1): split ExportVar into separate functions

diffstat:

 usr.bin/make/var.c |  171 ++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 142 insertions(+), 29 deletions(-)

diffs (219 lines):

diff -r b7b4d0ddb826 -r 630420aba003 usr.bin/make/var.c
--- a/usr.bin/make/var.c        Tue Dec 29 01:48:46 2020 +0000
+++ b/usr.bin/make/var.c        Tue Dec 29 03:05:15 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: var.c,v 1.775 2020/12/29 01:48:46 rillig Exp $ */
+/*     $NetBSD: var.c,v 1.776 2020/12/29 03:05:15 rillig Exp $ */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -131,7 +131,7 @@
 #include "metachar.h"
 
 /*     "@(#)var.c      8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.775 2020/12/29 01:48:46 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.776 2020/12/29 03:05:15 rillig Exp $");
 
 typedef enum VarFlags {
        VAR_NONE        = 0,
@@ -576,40 +576,73 @@
        return TRUE;
 }
 
-/*
- * Export a single variable.
- *
- * We ignore make internal variables (those which start with '.').
- * Also we jump through some hoops to avoid calling setenv
- * more than necessary since it can leak.
- * We only manipulate flags of vars if 'parent' is set.
- */
 static Boolean
-ExportVar(const char *name, VarExportMode mode)
+ExportVarEnv(Var *v)
 {
-       /*
-        * XXX: It sounds wrong to handle VEM_PLAIN and VEM_LITERAL
-        * differently here.
-        */
-       Boolean plain = mode == VEM_PLAIN;
-       Var *v;
+       VarExportMode mode = VEM_ENV;
+       const char *name = v->name.str;
        char *val;
 
-       if (!MayExport(name))
-               return FALSE;
-
-       v = VarFind(name, VAR_GLOBAL, FALSE);
-       if (v == NULL)
-               return FALSE;
-
-       if (!plain && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
+       if (!(mode == VEM_PLAIN) && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
                return FALSE;   /* nothing to do */
 
        val = Buf_GetAll(&v->val, NULL);
        if (mode != VEM_LITERAL && strchr(val, '$') != NULL) {
                char *expr;
 
-               if (plain) {
+               if (mode == VEM_PLAIN) {
+                       /*
+                        * Flag the variable as something we need to re-export.
+                        * No point actually exporting it now though,
+                        * the child process can do it at the last minute.
+                        */
+                       v->flags |= VAR_EXPORTED | VAR_REEXPORT;
+                       return TRUE;
+               }
+               if (v->flags & VAR_IN_USE) {
+                       /*
+                        * We recursed while exporting in a child.
+                        * This isn't going to end well, just skip it.
+                        */
+                       return FALSE;
+               }
+
+               /* XXX: name is injected without escaping it */
+               expr = str_concat3("${", name, "}");
+               (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
+               /* TODO: handle errors */
+               setenv(name, val, 1);
+               free(val);
+               free(expr);
+       } else {
+               if (mode == VEM_PLAIN)
+                       v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
+               if (mode == VEM_PLAIN || !(v->flags & VAR_EXPORTED))
+                       setenv(name, val, 1);
+       }
+
+       /* This is so Var_Set knows to call Var_Export again. */
+       if (mode == VEM_PLAIN)
+               v->flags |= VAR_EXPORTED;
+
+       return TRUE;
+}
+
+static Boolean
+ExportVarPlain(Var *v)
+{
+       VarExportMode mode = VEM_PLAIN;
+       const char *name = v->name.str;
+       char *val;
+
+       if (!(mode == VEM_PLAIN) && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
+               return FALSE;   /* nothing to do */
+
+       val = Buf_GetAll(&v->val, NULL);
+       if (mode != VEM_LITERAL && strchr(val, '$') != NULL) {
+               char *expr;
+
+               if (mode == VEM_PLAIN) {
                        /*
                         * Flag the variable as something we need to re-export.
                         * No point actually exporting it now though,
@@ -634,19 +667,99 @@
                free(val);
                free(expr);
        } else {
-               if (plain)
+               if (mode == VEM_PLAIN)
                        v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
-               if (plain || !(v->flags & VAR_EXPORTED))
+               if (mode == VEM_PLAIN || !(v->flags & VAR_EXPORTED))
                        setenv(name, val, 1);
        }
 
        /* This is so Var_Set knows to call Var_Export again. */
-       if (plain)
+       if (mode == VEM_PLAIN)
                v->flags |= VAR_EXPORTED;
 
        return TRUE;
 }
 
+static Boolean
+ExportVarLiteral(Var *v)
+{
+       VarExportMode mode = VEM_LITERAL;
+       const char *name = v->name.str;
+       char *val;
+
+       if (!(mode == VEM_PLAIN) && (v->flags & VAR_EXPORTED) && !(v->flags & VAR_REEXPORT))
+               return FALSE;   /* nothing to do */
+
+       val = Buf_GetAll(&v->val, NULL);
+       if (mode != VEM_LITERAL && strchr(val, '$') != NULL) {
+               char *expr;
+
+               if (mode == VEM_PLAIN) {
+                       /*
+                        * Flag the variable as something we need to re-export.
+                        * No point actually exporting it now though,
+                        * the child process can do it at the last minute.
+                        */
+                       v->flags |= VAR_EXPORTED | VAR_REEXPORT;
+                       return TRUE;
+               }
+               if (v->flags & VAR_IN_USE) {
+                       /*
+                        * We recursed while exporting in a child.
+                        * This isn't going to end well, just skip it.
+                        */
+                       return FALSE;
+               }
+
+               /* XXX: name is injected without escaping it */
+               expr = str_concat3("${", name, "}");
+               (void)Var_Subst(expr, VAR_GLOBAL, VARE_WANTRES, &val);
+               /* TODO: handle errors */
+               setenv(name, val, 1);
+               free(val);
+               free(expr);
+       } else {
+               if (mode == VEM_PLAIN)
+                       v->flags &= ~(unsigned)VAR_REEXPORT; /* once will do */
+               if (mode == VEM_PLAIN || !(v->flags & VAR_EXPORTED))
+                       setenv(name, val, 1);
+       }
+
+       /* This is so Var_Set knows to call Var_Export again. */
+       if (mode == VEM_PLAIN)
+               v->flags |= VAR_EXPORTED;
+
+       return TRUE;
+}
+
+/*
+ * Export a single variable.
+ *
+ * We ignore make internal variables (those which start with '.').
+ * Also we jump through some hoops to avoid calling setenv
+ * more than necessary since it can leak.
+ * We only manipulate flags of vars if 'parent' is set.
+ */
+static Boolean
+ExportVar(const char *name, VarExportMode mode)
+{
+       Var *v;
+
+       if (!MayExport(name))
+               return FALSE;
+
+       v = VarFind(name, VAR_GLOBAL, FALSE);
+       if (v == NULL)
+               return FALSE;
+
+       if (mode == VEM_ENV)
+               return ExportVarEnv(v);
+       else if (mode == VEM_PLAIN)
+               return ExportVarPlain(v);
+       else
+               return ExportVarLiteral(v);
+}
+
 /*
  * Actually export the variables that have been marked as needing to be
  * re-exported.



Home | Main Index | Thread Index | Old Index