From f99f7dca7552d21782354f675c0741896c9785f1 Mon Sep 17 00:00:00 2001
From: Peter Stephenson
Date: Mon, 8 Oct 2018 10:10:42 +0100
Subject: 43616: Various parameter setting and display fixes.
Mostly to do with typeset -p and tied variables and their interaction.
Some general tied variable fixes.
---
Src/builtin.c | 155 ++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 112 insertions(+), 43 deletions(-)
(limited to 'Src/builtin.c')
diff --git a/Src/builtin.c b/Src/builtin.c
index 4abc7da35..c5b319b68 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -64,7 +64,7 @@ static struct builtin builtins[] =
BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
- BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"),
+ BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lp:%rtu", "xg"),
BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
/*
* We used to behave as if the argument to -e was optional.
@@ -2258,6 +2258,22 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
} else if (pm->env && !(pm->node.flags & PM_HASHELEM))
delenv(pm);
DPUTS(ASG_ARRAYP(asg), "BUG: typeset got array value where scalar expected");
+ if (altpm) {
+ struct tieddata* tdp = (struct tieddata *) pm->u.data;
+ if (tdp) {
+ if (tdp->joinchar != joinchar && !asg->value.scalar) {
+ /*
+ * Reassign the scalar to itself to do the splitting with
+ * the new joinchar
+ */
+ tdp->joinchar = joinchar;
+ if (!(pm = assignsparam(pname, ztrdup(getsparam(pname)), 0)))
+ return NULL;
+ }
+ }
+ else
+ DPUTS(!tdp, "BUG: no join character to update");
+ }
if (asg->value.scalar &&
!(pm = assignsparam(pname, ztrdup(asg->value.scalar), 0)))
return NULL;
@@ -2325,6 +2341,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
zerrnam(cname, "%s: can only have a single instance", pname);
return pm;
}
+
+ on |= pm->node.flags & PM_TIED;
+
/*
* For specials, we keep the same struct but zero everything.
* Maybe it would be easier to create a new struct but copy
@@ -2476,7 +2495,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
return NULL;
}
- if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR) {
+ if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR && !(pm->node.flags & PM_SPECIAL)) {
/*
* It seems safer to set this here than in createparam(),
* to make sure we only ever use the colonarr functions
@@ -2646,7 +2665,17 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
/* Given no arguments, list whatever the options specify. */
if (OPT_ISSET(ops,'p')) {
- printflags |= PRINT_TYPESET;
+
+ if (isset(POSIXBUILTINS) && SHELL_EMULATION() != EMULATE_KSH) {
+ if (func == BIN_EXPORT)
+ printflags |= PRINT_POSIX_EXPORT;
+ else if (func == BIN_READONLY)
+ printflags |= PRINT_POSIX_READONLY;
+ else
+ printflags |= PRINT_TYPESET;
+ } else
+ printflags |= PRINT_TYPESET;
+
if (OPT_HASARG(ops,'p')) {
char *eptr;
int pflag = (int)zstrtol(OPT_ARG(ops,'p'), &eptr, 10);
@@ -2662,13 +2691,20 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
}
hasargs = *argv != NULL || (assigns && firstnode(assigns));
if (!hasargs) {
+ int exclude = 0;
if (!OPT_ISSET(ops,'p')) {
if (!(on|roff))
printflags |= PRINT_TYPE;
if (roff || OPT_ISSET(ops,'+'))
printflags |= PRINT_NAMEONLY;
+ } else if (printflags & (PRINT_POSIX_EXPORT|PRINT_POSIX_READONLY)) {
+ /*
+ * For POSIX export/readonly, exclude non-scalars unless
+ * explicitly requested.
+ */
+ exclude = (PM_ARRAY|PM_HASHED) & ~(on|roff);
}
- scanhashtable(paramtab, 1, on|roff, 0, paramtab->printnode, printflags);
+ scanhashtable(paramtab, 1, on|roff, exclude, paramtab->printnode, printflags);
unqueue_signals();
return 0;
}
@@ -2683,6 +2719,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
struct asgment asg0, asg2;
char *oldval = NULL, *joinstr;
int joinchar, nargs;
+ int already_tied = 0;
if (OPT_ISSET(ops,'m')) {
zwarnnam(name, "incompatible options for -T");
@@ -2765,47 +2802,81 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
joinchar = joinstr[1] ^ 32;
else
joinchar = *joinstr;
- /*
- * Keep the old value of the scalar. We need to do this
- * here as if it is already tied to the same array it
- * will be unset when we retie the array. This is all
- * so that typeset -T is idempotent.
- *
- * We also need to remember here whether the damn thing is
- * exported and pass that along. Isn't the world complicated?
- */
- if ((pm = (Param) paramtab->getnode(paramtab, asg0.name))
- && !(pm->node.flags & PM_UNSET)
- && (locallevel == pm->level || !(on & PM_LOCAL))) {
- if (pm->node.flags & PM_TIED) {
+
+ pm = (Param) paramtab->getnode(paramtab, asg0.name);
+ apm = (Param) paramtab->getnode(paramtab, asg->name);
+
+ if (pm && (pm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
+ /*
+ * Only allow typeset -T on special tied parameters if the tied
+ * parameter and join char are the same
+ */
+ if (strcmp(pm->ename, asg->name) || !(apm->node.flags & PM_SPECIAL)) {
+ zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg0.name, pm->ename);
+ unqueue_signals();
+ return 1;
+ }
+ if (joinchar != ':') {
+ zwarnnam(name, "cannot change the join character of special tied parameters");
unqueue_signals();
- if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
- zwarnnam(name, "already tied as non-scalar: %s", asg0.name);
- } else if (!strcmp(asg->name, pm->ename)) {
+ return 1;
+ }
+ already_tied = 1;
+ } else if (apm && (apm->node.flags & (PM_SPECIAL|PM_TIED)) == (PM_SPECIAL|PM_TIED)) {
+ /*
+ * For the array variable, this covers attempts to tie the
+ * array to a different scalar or to the scalar after it has
+ * been made non-special
+ */
+ zwarnnam(name, "%s special parameter can only be tied to special parameter %s", asg->name, apm->ename);
+ unqueue_signals();
+ return 1;
+ } else if (pm) {
+ if (!(pm->node.flags & PM_UNSET)
+ && (locallevel == pm->level || !(on & PM_LOCAL))) {
+ if (pm->node.flags & PM_TIED) {
+ if (PM_TYPE(pm->node.flags) != PM_SCALAR) {
+ zwarnnam(name, "already tied as non-scalar: %s", asg0.name);
+ unqueue_signals();
+ return 1;
+ } else if (!strcmp(asg->name, pm->ename)) {
+ already_tied = 1;
+ } else {
+ zwarnnam(name, "can't tie already tied scalar: %s",
+ asg0.name);
+ unqueue_signals();
+ return 1;
+ }
+ } else {
/*
- * Already tied in the fashion requested.
+ * Variable already exists in the current scope but is not tied.
+ * We're preserving its value and export attribute but no other
+ * attributes upon converting to "tied".
*/
- struct tieddata *tdp = (struct tieddata*)pm->u.data;
- int flags = (asg->flags & ASG_KEY_VALUE) ?
- ASSPM_KEY_VALUE : 0;
- /* Update join character */
- tdp->joinchar = joinchar;
- if (asg0.value.scalar)
- assignsparam(asg0.name, ztrdup(asg0.value.scalar), 0);
- else if (asg->value.array)
- assignaparam(
- asg->name, zlinklist2array(asg->value.array),flags);
- return 0;
- } else {
- zwarnnam(name, "can't tie already tied scalar: %s",
- asg0.name);
+ if (!asg0.value.scalar && !asg->value.array &&
+ !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
+ oldval = ztrdup(getsparam(asg0.name));
+ on |= (pm->node.flags & ~roff) & PM_EXPORTED;
}
- return 1;
}
- if (!asg0.value.scalar && !asg->value.array &&
- !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
- oldval = ztrdup(getsparam(asg0.name));
- on |= (pm->node.flags & PM_EXPORTED);
+ }
+ if (already_tied) {
+ int ret;
+ /*
+ * If already tied, we still need to call typeset_single on
+ * both the array and colonarray, if only to update the attributes
+ * of both, and of course to set the new value if one is provided
+ * for either of them.
+ */
+ ret = !(typeset_single(name, asg0.name, pm,
+ func, on, off, roff, &asg0, apm,
+ ops, joinchar) &&
+ typeset_single(name, asg->name, apm,
+ func, (on | PM_ARRAY) & ~PM_EXPORTED,
+ off & ~PM_ARRAY, roff, asg, NULL, ops, 0)
+ );
+ unqueue_signals();
+ return ret;
}
/*
* Create the tied array; this is normal except that
@@ -2832,9 +2903,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
* Create the tied colonarray. We make it as a normal scalar
* and fix up the oddities later.
*/
- if (!(pm=typeset_single(name, asg0.name,
- (Param)paramtab->getnode(paramtab,
- asg0.name),
+ if (!(pm=typeset_single(name, asg0.name, pm,
func, on, off, roff, &asg0, apm,
ops, joinchar))) {
if (oldval)
--
cgit 1.4.1