Module Name:    src
Committed By:   kre
Date:           Fri Jul 12 08:35:48 UTC 2024

Modified Files:
        src/bin/sh: parser.c parser.h

Log Message:
Implement expandvar() : runs var/arith/cmdsub expansions on var value

expandvar() is like expandenv() and expandstr() - each expands
variable values in different contexts, expandenv() when processing
environment vars at startup (and there is no existing state to lose),
but is always using unsafe data, so never runs command substitutions,
expandstr() while in the middle of processing commands (mostly to
expand the prompt variables, so there is probably half a command
tree in the process of being built) - it uses the promptcmds option
to decide whether to run command substitutions.  expandvar() is for
intermediate situations, where a variable is to be used during
processing.  It will run command substitutions if the variable
value concerned was not imported from the environment.

There are currently no uses of expandvar(), so this change alters
nothing in the shell - but there will be in the near future.


To generate a diff of this commit:
cvs rdiff -u -r1.181 -r1.182 src/bin/sh/parser.c
cvs rdiff -u -r1.28 -r1.29 src/bin/sh/parser.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/bin/sh/parser.c
diff -u src/bin/sh/parser.c:1.181 src/bin/sh/parser.c:1.182
--- src/bin/sh/parser.c:1.181	Fri Oct 20 22:08:52 2023
+++ src/bin/sh/parser.c	Fri Jul 12 08:35:47 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: parser.c,v 1.181 2023/10/20 22:08:52 kre Exp $	*/
+/*	$NetBSD: parser.c,v 1.182 2024/07/12 08:35:47 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
 #if 0
 static char sccsid[] = "@(#)parser.c	8.7 (Berkeley) 5/16/95";
 #else
-__RCSID("$NetBSD: parser.c,v 1.181 2023/10/20 22:08:52 kre Exp $");
+__RCSID("$NetBSD: parser.c,v 1.182 2024/07/12 08:35:47 kre Exp $");
 #endif
 #endif /* not lint */
 
@@ -601,7 +601,7 @@ command(void)
 		n1->nredir.redirect = redir;
 	}
 
- checkneg:
+ checkneg:;
 #ifdef BOGUS_NOT_COMMAND
 	if (negate) {
 		VTRACE(DBG_PARSE, ("bogus %snegate command\n",
@@ -710,7 +710,7 @@ simplecmd(union node **rpp, union node *
 	n->ncmd.redirect = redir;
 	n->ncmd.lineno = startlinno;
 
- checkneg:
+ checkneg:;
 #ifdef BOGUS_NOT_COMMAND
 	if (negate) {
 		VTRACE(DBG_PARSE, ("bogus %snegate simplecmd\n",
@@ -1021,7 +1021,7 @@ readtoken(void)
 #endif
 	struct alias *ap;
 
- top:
+ top:;
 	t = xxreadtoken();
 
 	if (checkkwd & CHKNL) {
@@ -1058,7 +1058,7 @@ readtoken(void)
 			goto top;
 		}
 	}
- out:
+ out:;
 	if (t != TNOT)
 		checkkwd = 0;
 
@@ -1742,7 +1742,7 @@ readcstyleesc(char *out)
 		goto hexval;
 	case 'U':
 		n = 8;
-	hexval:
+	hexval:;
 		v = 0;
 		for (i = 0; i < n; i++) {
 			c = pgetc();
@@ -2324,7 +2324,7 @@ parsesub: {
 		}
 		else {
 			VTRACE(DBG_LEXER, ("\"$%c(%#.2x)??\n", c&0xFF,c&0x1FF));
- badsub:
+ badsub:;
 			cleanup_state_stack(stack);
 			synerror("Bad substitution");
 		}
@@ -2707,7 +2707,7 @@ expandonstack(char *ps, int cmdsub, int 
 		if (backquotelist != NULL) {
 			if (!cmdsub)
 				result = ps;
-			else if (!promptcmds)
+			else if (cmdsub == 1 && !promptcmds)
 				result = "-o promptcmds not set: ";
 		}
 		if (result == NULL) {
@@ -2814,6 +2814,81 @@ expandstr(char *ps, int lineno)
 	return result;
 }
 
+#ifndef SMALL
+/*
+ * A version of the above which isn't tailored to expanding prompts,
+ * but can be used for expanding other expandable variables when
+ * they need to be used.   ${LINENO} will always expand to 0 in this case.
+ */
+
+const char *
+expandvar(char *var, int flags)
+{
+	const char *result = NULL;
+	struct stackmark smark;
+	static char *buffer = NULL;	/* storage for result */
+	static size_t bufferlen = 0;
+
+	setstackmark(&smark);
+	/*
+	 * At this point we anticipate that there may be a string
+	 * growing on the stack, [...]   [see expandstr() above].
+	 */
+	(void) stalloc(stackblocksize());
+
+	result = expandonstack(var, (flags & VUNSAFE ? 0 : 2), 0);
+	if (__predict_false(result == NULL || *result == '\0')) {
+		result = NULL;
+		goto getout;
+	}
+
+	if (__predict_true(result == stackblock())) {
+		size_t len = strlen(result) + 1;
+
+		/*
+		 * the result is on the stack, so we
+		 * need to move it somewhere safe first.
+		 */
+
+		if (__predict_false(len > bufferlen)) {
+			char *new;
+			size_t newlen = bufferlen;
+
+			if (__predict_false(len > (SIZE_MAX >> 4))) {
+				result = "";
+				goto getout;
+			}
+
+			if (__predict_false(newlen == 0))
+				newlen = 32;
+			while (newlen <= len)
+				newlen <<= 1;
+
+			new = (char *)realloc(buffer, newlen);
+
+			if (__predict_false(new == NULL)) {
+				/*
+				 * this should rarely (if ever) happen
+				 * but we must do something when it does...
+				 */
+				result = "";
+				goto getout;
+			} else {
+				buffer = new;
+				bufferlen = newlen;
+			}
+		}
+		(void)memcpy(buffer, result, len);
+		result = buffer;
+	}
+
+  getout:;
+	popstackmark(&smark);
+
+	return result;
+}
+#endif
+
 /*
  * and a simpler version, which does no $( ) expansions, for
  * use during shell startup when we know we are not parsing,

Index: src/bin/sh/parser.h
diff -u src/bin/sh/parser.h:1.28 src/bin/sh/parser.h:1.29
--- src/bin/sh/parser.h:1.28	Wed Feb 13 21:40:50 2019
+++ src/bin/sh/parser.h	Fri Jul 12 08:35:47 2024
@@ -1,4 +1,4 @@
-/*	$NetBSD: parser.h,v 1.28 2019/02/13 21:40:50 kre Exp $	*/
+/*	$NetBSD: parser.h,v 1.29 2024/07/12 08:35:47 kre Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993
@@ -77,6 +77,7 @@ int goodname(const char *);
 int isassignment(const char *);
 const char *getprompt(void *);
 const char *expandstr(char *, int);
+const char *expandvar(char *, int);
 const char *expandenv(char *);
 
 struct HereDoc;

Reply via email to