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/Modules/db_gdbm.c | 2 +-
Src/Modules/parameter.c | 44 +++++++------
Src/builtin.c | 155 +++++++++++++++++++++++++++++++------------
Src/hashtable.h | 1 +
Src/params.c | 172 ++++++++++++++++++++++++++++++------------------
Src/subst.c | 4 +-
Src/zsh.h | 23 ++++---
7 files changed, 262 insertions(+), 139 deletions(-)
(limited to 'Src')
diff --git a/Src/Modules/db_gdbm.c b/Src/Modules/db_gdbm.c
index ed702b912..12dd839cf 100644
--- a/Src/Modules/db_gdbm.c
+++ b/Src/Modules/db_gdbm.c
@@ -809,7 +809,7 @@ myfreeparamnode(HashNode hn)
zsfree(pm->node.nam);
/* If this variable was tied by the user, ename was ztrdup'd */
- if (pm->node.flags & PM_TIED && pm->ename) {
+ if (!(pm->node.flags & PM_SPECIAL) && pm->ename) {
zsfree(pm->ename);
pm->ename = NULL;
}
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 783c36df3..76824cf58 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -75,6 +75,8 @@ paramtypestr(Param pm)
val = dyncat(val, "-readonly");
if (f & PM_TAGGED)
val = dyncat(val, "-tag");
+ if (f & PM_TIED)
+ val = dyncat(val, "-tied");
if (f & PM_EXPORTED)
val = dyncat(val, "-export");
if (f & PM_UNIQUE)
@@ -2194,67 +2196,67 @@ static const struct gsu_array historywords_gsu =
static struct paramdef partab[] = {
SPECIALPMDEF("aliases", 0,
&pmraliases_gsu, getpmralias, scanpmraliases),
- SPECIALPMDEF("builtins", PM_READONLY, NULL, getpmbuiltin, scanpmbuiltins),
+ SPECIALPMDEF("builtins", PM_READONLY_SPECIAL, NULL, getpmbuiltin, scanpmbuiltins),
SPECIALPMDEF("commands", 0, &pmcommands_gsu, getpmcommand, scanpmcommands),
SPECIALPMDEF("dirstack", PM_ARRAY,
&dirs_gsu, NULL, NULL),
SPECIALPMDEF("dis_aliases", 0,
&pmdisraliases_gsu, getpmdisralias, scanpmdisraliases),
- SPECIALPMDEF("dis_builtins", PM_READONLY,
+ SPECIALPMDEF("dis_builtins", PM_READONLY_SPECIAL,
NULL, getpmdisbuiltin, scanpmdisbuiltins),
SPECIALPMDEF("dis_functions", 0,
&pmdisfunctions_gsu, getpmdisfunction, scanpmdisfunctions),
- SPECIALPMDEF("dis_functions_source", PM_READONLY, NULL,
+ SPECIALPMDEF("dis_functions_source", PM_READONLY_SPECIAL, NULL,
getpmdisfunction_source, scanpmdisfunction_source),
SPECIALPMDEF("dis_galiases", 0,
&pmdisgaliases_gsu, getpmdisgalias, scanpmdisgaliases),
- SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("dis_patchars", PM_ARRAY|PM_READONLY_SPECIAL,
&dispatchars_gsu, NULL, NULL),
- SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("dis_reswords", PM_ARRAY|PM_READONLY_SPECIAL,
&disreswords_gsu, NULL, NULL),
SPECIALPMDEF("dis_saliases", 0,
&pmdissaliases_gsu, getpmdissalias, scanpmdissaliases),
- SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcfiletrace", PM_ARRAY|PM_READONLY_SPECIAL,
&funcfiletrace_gsu, NULL, NULL),
- SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcsourcetrace", PM_ARRAY|PM_READONLY_SPECIAL,
&funcsourcetrace_gsu, NULL, NULL),
- SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("funcstack", PM_ARRAY|PM_READONLY_SPECIAL,
&funcstack_gsu, NULL, NULL),
SPECIALPMDEF("functions", 0, &pmfunctions_gsu, getpmfunction,
scanpmfunctions),
- SPECIALPMDEF("functions_source", PM_READONLY, NULL,
+ SPECIALPMDEF("functions_source", PM_READONLY_SPECIAL, NULL,
getpmfunction_source, scanpmfunction_source),
- SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("functrace", PM_ARRAY|PM_READONLY_SPECIAL,
&functrace_gsu, NULL, NULL),
SPECIALPMDEF("galiases", 0,
&pmgaliases_gsu, getpmgalias, scanpmgaliases),
- SPECIALPMDEF("history", PM_READONLY,
+ SPECIALPMDEF("history", PM_READONLY_SPECIAL,
NULL, getpmhistory, scanpmhistory),
- SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("historywords", PM_ARRAY|PM_READONLY_SPECIAL,
&historywords_gsu, NULL, NULL),
- SPECIALPMDEF("jobdirs", PM_READONLY,
+ SPECIALPMDEF("jobdirs", PM_READONLY_SPECIAL,
NULL, getpmjobdir, scanpmjobdirs),
- SPECIALPMDEF("jobstates", PM_READONLY,
+ SPECIALPMDEF("jobstates", PM_READONLY_SPECIAL,
NULL, getpmjobstate, scanpmjobstates),
- SPECIALPMDEF("jobtexts", PM_READONLY,
+ SPECIALPMDEF("jobtexts", PM_READONLY_SPECIAL,
NULL, getpmjobtext, scanpmjobtexts),
- SPECIALPMDEF("modules", PM_READONLY,
+ SPECIALPMDEF("modules", PM_READONLY_SPECIAL,
NULL, getpmmodule, scanpmmodules),
SPECIALPMDEF("nameddirs", 0,
&pmnameddirs_gsu, getpmnameddir, scanpmnameddirs),
SPECIALPMDEF("options", 0,
&pmoptions_gsu, getpmoption, scanpmoptions),
- SPECIALPMDEF("parameters", PM_READONLY,
+ SPECIALPMDEF("parameters", PM_READONLY_SPECIAL,
NULL, getpmparameter, scanpmparameters),
- SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("patchars", PM_ARRAY|PM_READONLY_SPECIAL,
&patchars_gsu, NULL, NULL),
- SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY,
+ SPECIALPMDEF("reswords", PM_ARRAY|PM_READONLY_SPECIAL,
&reswords_gsu, NULL, NULL),
SPECIALPMDEF("saliases", 0,
&pmsaliases_gsu, getpmsalias, scanpmsaliases),
- SPECIALPMDEF("userdirs", PM_READONLY,
+ SPECIALPMDEF("userdirs", PM_READONLY_SPECIAL,
NULL, getpmuserdir, scanpmuserdirs),
- SPECIALPMDEF("usergroups", PM_READONLY,
+ SPECIALPMDEF("usergroups", PM_READONLY_SPECIAL,
NULL, getpmusergroups, scanpmusergroups)
};
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)
diff --git a/Src/hashtable.h b/Src/hashtable.h
index 21398e17c..f6778664e 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -63,6 +63,7 @@
#define BIN_UNALIAS 29
#define BIN_UNFUNCTION 30
#define BIN_UNSET 31
+#define BIN_EXPORT 32
/* These currently depend on being 0 and 1. */
#define BIN_SETOPT 0
diff --git a/Src/params.c b/Src/params.c
index f7ecff32a..089a958ae 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -290,7 +290,7 @@ static initparam special_params[] ={
#define GSU(X) BR((GsuScalar)(void *)(&(X)))
#define NULL_GSU BR((GsuScalar)(void *)NULL)
#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
-IPDEF1("#", pound_gsu, PM_READONLY),
+IPDEF1("#", pound_gsu, PM_READONLY_SPECIAL),
IPDEF1("ERRNO", errno_gsu, PM_UNSET),
IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
@@ -300,11 +300,11 @@ IPDEF1("SAVEHIST", savehist_gsu, PM_RESTRICTED),
IPDEF1("SECONDS", intseconds_gsu, 0),
IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
+IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY_SPECIAL),
#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
-IPDEF2("-", dash_gsu, PM_READONLY),
+IPDEF2("-", dash_gsu, PM_READONLY_SPECIAL),
IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
IPDEF2("HOME", home_gsu, PM_UNSET),
IPDEF2("TERM", term_gsu, PM_UNSET),
@@ -337,7 +337,7 @@ LCIPDEF("LC_TIME"),
# endif
#endif /* USE_LOCALE */
-#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
+#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
IPDEF4("!", &lastpid),
IPDEF4("$", &mypid),
IPDEF4("?", &lastval),
@@ -377,10 +377,9 @@ IPDEF7("PS3", &prompt3),
IPDEF7R("PS4", &prompt4),
IPDEF7("SPROMPT", &sprompt),
-#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
-#define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
-IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
-IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
+#define IPDEF9(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
+IPDEF9("*", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT),
+IPDEF9("@", &pparams, NULL, PM_ARRAY|PM_READONLY_SPECIAL|PM_DONTIMPORT),
/*
* This empty row indicates the end of parameters available in
@@ -389,17 +388,17 @@ IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
#define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
-IPDEF8("CDPATH", &cdpath, "cdpath", 0),
-IPDEF8("FIGNORE", &fignore, "fignore", 0),
-IPDEF8("FPATH", &fpath, "fpath", 0),
-IPDEF8("MAILPATH", &mailpath, "mailpath", 0),
-IPDEF8("WATCH", &watch, "watch", 0),
-IPDEF8("PATH", &path, "path", PM_RESTRICTED),
-IPDEF8("PSVAR", &psvar, "psvar", 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY),
+IPDEF8("CDPATH", &cdpath, "cdpath", PM_TIED),
+IPDEF8("FIGNORE", &fignore, "fignore", PM_TIED),
+IPDEF8("FPATH", &fpath, "fpath", PM_TIED),
+IPDEF8("MAILPATH", &mailpath, "mailpath", PM_TIED),
+IPDEF8("WATCH", &watch, "watch", PM_TIED),
+IPDEF8("PATH", &path, "path", PM_RESTRICTED|PM_TIED),
+IPDEF8("PSVAR", &psvar, "psvar", PM_TIED),
+IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY_SPECIAL|PM_TIED),
/* MODULE_PATH is not imported for security reasons */
-IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
+IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED|PM_TIED),
#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
@@ -409,7 +408,7 @@ IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
*/
/* All of these have sh compatible equivalents. */
-IPDEF1("ARGC", argc_gsu, PM_READONLY),
+IPDEF1("ARGC", argc_gsu, PM_READONLY_SPECIAL),
IPDEF2("HISTCHARS", histchars_gsu, PM_DONTIMPORT),
IPDEF4("status", &lastval),
IPDEF7("prompt", &prompt),
@@ -417,20 +416,20 @@ IPDEF7("PROMPT", &prompt),
IPDEF7("PROMPT2", &prompt2),
IPDEF7("PROMPT3", &prompt3),
IPDEF7("PROMPT4", &prompt4),
-IPDEF8("MANPATH", &manpath, "manpath", 0),
-IPDEF9("argv", &pparams, NULL),
-IPDEF9("fignore", &fignore, "FIGNORE"),
-IPDEF9("cdpath", &cdpath, "CDPATH"),
-IPDEF9("fpath", &fpath, "FPATH"),
-IPDEF9("mailpath", &mailpath, "MAILPATH"),
-IPDEF9("manpath", &manpath, "MANPATH"),
-IPDEF9("psvar", &psvar, "PSVAR"),
-IPDEF9("watch", &watch, "WATCH"),
+IPDEF8("MANPATH", &manpath, "manpath", PM_TIED),
+IPDEF9("argv", &pparams, NULL, 0),
+IPDEF9("fignore", &fignore, "FIGNORE", PM_TIED),
+IPDEF9("cdpath", &cdpath, "CDPATH", PM_TIED),
+IPDEF9("fpath", &fpath, "FPATH", PM_TIED),
+IPDEF9("mailpath", &mailpath, "MAILPATH", PM_TIED),
+IPDEF9("manpath", &manpath, "MANPATH", PM_TIED),
+IPDEF9("psvar", &psvar, "PSVAR", PM_TIED),
+IPDEF9("watch", &watch, "WATCH", PM_TIED),
-IPDEF9F("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_READONLY),
+IPDEF9("zsh_eval_context", &zsh_eval_context, "ZSH_EVAL_CONTEXT", PM_TIED|PM_READONLY_SPECIAL),
-IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
-IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
+IPDEF9("module_path", &module_path, "MODULE_PATH", PM_TIED|PM_RESTRICTED),
+IPDEF9("path", &path, "PATH", PM_TIED|PM_RESTRICTED),
/* These are known to zsh alone. */
@@ -451,7 +450,7 @@ IPDEF8("MAILPATH", &mailpath, NULL, 0),
IPDEF8("WATCH", &watch, NULL, 0),
IPDEF8("PATH", &path, NULL, PM_RESTRICTED),
IPDEF8("PSVAR", &psvar, NULL, 0),
-IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY),
+IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY_SPECIAL),
/* MODULE_PATH is not imported for security reasons */
IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
@@ -464,7 +463,7 @@ IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
* and $@, this is not readonly. This parameter is not directly
* visible in user space.
*/
-static initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \
+static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT);
#undef BR
@@ -5024,10 +5023,10 @@ arrfixenv(char *s, char **t)
if (!(pm->node.flags & PM_EXPORTED))
return;
- if (pm->node.flags & PM_TIED)
- joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar);
- else
+ if (pm->node.flags & PM_SPECIAL)
joinchar = ':';
+ else
+ joinchar = STOUC(((struct tieddata *)pm->u.data)->joinchar);
addenv(pm, t ? zjoin(t, joinchar, 1) : "");
}
@@ -5650,7 +5649,7 @@ freeparamnode(HashNode hn)
pm->gsu.s->unsetfn(pm, 1);
zsfree(pm->node.nam);
/* If this variable was tied by the user, ename was ztrdup'd */
- if (pm->node.flags & PM_TIED)
+ if (!(pm->node.flags & PM_SPECIAL))
zsfree(pm->ename);
zfree(pm, sizeof(struct param));
}
@@ -5685,7 +5684,9 @@ static const struct paramtypes pmtypes[] = {
{ PM_UPPER, "uppercase", 'u', 0},
{ PM_READONLY, "readonly", 'r', 0},
{ PM_TAGGED, "tagged", 't', 0},
- { PM_EXPORTED, "exported", 'x', 0}
+ { PM_EXPORTED, "exported", 'x', 0},
+ { PM_UNIQUE, "unique", 'U', 0},
+ { PM_TIED, "tied", 'T', 0}
};
#define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
@@ -5774,10 +5775,6 @@ printparamvalue(Param p, int printflags)
}
break;
}
- if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR)
- putchar(' ');
- else if (!(printflags & PRINT_KV_PAIR))
- putchar('\n');
}
/**/
@@ -5785,36 +5782,41 @@ mod_export void
printparamnode(HashNode hn, int printflags)
{
Param p = (Param) hn;
+ Param peer = NULL;
if (p->node.flags & PM_UNSET) {
- if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
- (printflags & PRINT_TYPESET))
- {
+ if (printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) &&
+ p->node.flags & (PM_READONLY|PM_EXPORTED)) {
/*
- * Special POSIX rules: show the parameter as readonly
+ * Special POSIX rules: show the parameter as readonly/exported
* even though it's unset, but with no value.
*/
printflags |= PRINT_NAMEONLY;
}
- else if (p->node.flags & PM_EXPORTED)
- printflags |= PRINT_NAMEONLY;
else
return;
}
if (p->node.flags & PM_AUTOLOAD)
printflags |= PRINT_NAMEONLY;
- if (printflags & PRINT_TYPESET) {
- if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
- (PM_READONLY|PM_SPECIAL) ||
- (p->node.flags & PM_AUTOLOAD)) {
+ if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
+ if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
/*
* It's not possible to restore the state of
* these, so don't output.
*/
return;
}
- if (locallevel && p->level >= locallevel) {
+ /*
+ * The zsh variants of export -p/readonly -p also report other
+ * flags to indicate other attributes or scope. The POSIX variants
+ * don't.
+ */
+ if (printflags & PRINT_POSIX_EXPORT) {
+ printf("export ");
+ } else if (printflags & PRINT_POSIX_READONLY) {
+ printf("readonly ");
+ } else if (locallevel && p->level >= locallevel) {
printf("typeset "); /* printf("local "); */
} else if ((p->node.flags & PM_EXPORTED) &&
!(p->node.flags & (PM_ARRAY|PM_HASHED))) {
@@ -5861,22 +5863,48 @@ printparamnode(HashNode hn, int printflags)
}
}
}
- if (p->node.flags & PM_UNIQUE) {
- if (!doneminus) {
- putchar('-');
- doneminus = 1;
- }
- putchar('U');
- }
if (doneminus)
putchar(' ');
+
+ if (p->node.flags & PM_TIED) {
+ /*
+ * For scalars tied to arrays,s
+ * * typeset +m outputs
+ * array tied SCALAR array
+ * tied array SCALAR
+ * * typeset -p outputs:
+ * typeset -T SCALAR array (for hidden values)
+ * typeset -T SCALAR array=(values)
+ * for both scalar and array (flags may be different)
+ *
+ * We choose to print the value for the array instead of the scalar
+ * as scalars can't disambiguate between
+ * typeset -T SCALAR array=()
+ * and
+ * typeset -T SCALAR array=('')
+ * (same for (a b:c)...)
+ */
+ Param tmp = (Param) paramtab->getnode(paramtab, p->ename);
+
+ /*
+ * Swap param and tied peer for typeset -p output
+ */
+ if (!(printflags & PRINT_TYPESET) || (p->node.flags & PM_ARRAY))
+ peer = tmp;
+ else {
+ peer = p;
+ p = tmp;
+ }
+
+ quotedzputs(peer->node.nam, stdout);
+ putchar(' ');
+ }
}
if ((printflags & PRINT_NAMEONLY) ||
- ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
- zputs(p->node.nam, stdout);
- putchar('\n');
- } else {
+ ((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE)))
+ quotedzputs(p->node.nam, stdout);
+ else {
if (printflags & PRINT_KV_PAIR) {
if (printflags & PRINT_LINE)
printf("\n ");
@@ -5888,4 +5916,22 @@ printparamnode(HashNode hn, int printflags)
printparamvalue(p, printflags);
}
+ if (peer && (printflags & PRINT_TYPESET) && !(p->node.flags & PM_SPECIAL)) {
+ /*
+ * append the join char for tied parameters if different from colon
+ * for typeset -p output.
+ */
+ unsigned char joinchar = STOUC(((struct tieddata *)peer->u.data)->joinchar);
+ if (joinchar != ':') {
+ char buf[2];
+ buf[0] = joinchar;
+ buf[1] = '\0';
+ putchar(' ');
+ quotedzputs(buf, stdout);
+ }
+ }
+ if ((printflags & (PRINT_KV_PAIR|PRINT_LINE)) == PRINT_KV_PAIR)
+ putchar(' ');
+ else if (!(printflags & PRINT_KV_PAIR))
+ putchar('\n');
}
diff --git a/Src/subst.c b/Src/subst.c
index c1021fbf3..c706b9688 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2552,8 +2552,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags,
val = dyncat(val, "-readonly");
if (f & PM_TAGGED)
val = dyncat(val, "-tag");
- if (f & PM_TAGGED_LOCAL)
- val = dyncat(val, "-tag_local");
+ if (f & PM_TIED)
+ val = dyncat(val, "-tied");
if (f & PM_EXPORTED)
val = dyncat(val, "-export");
if (f & PM_UNIQUE)
diff --git a/Src/zsh.h b/Src/zsh.h
index b81db1527..8d39a0493 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1886,18 +1886,21 @@ struct tieddata {
#define PM_ANONYMOUS (1<<20) /* (function) anonymous function */
#define PM_LOCAL (1<<21) /* this parameter will be made local */
#define PM_SPECIAL (1<<22) /* special builtin parameter */
-#define PM_DONTIMPORT (1<<23) /* do not import this variable */
-#define PM_RESTRICTED (1<<24) /* cannot be changed in restricted mode */
-#define PM_UNSET (1<<25) /* has null value */
-#define PM_REMOVABLE (1<<26) /* special can be removed from paramtab */
-#define PM_AUTOLOAD (1<<27) /* autoloaded from module */
-#define PM_NORESTORE (1<<28) /* do not restore value of local special */
-#define PM_AUTOALL (1<<28) /* autoload all features in module
+#define PM_RO_BY_DESIGN (1<<23) /* to distinguish from specials that can be
+ made read-only by the user */
+#define PM_READONLY_SPECIAL (PM_SPECIAL|PM_READONLY|PM_RO_BY_DESIGN)
+#define PM_DONTIMPORT (1<<24) /* do not import this variable */
+#define PM_RESTRICTED (1<<25) /* cannot be changed in restricted mode */
+#define PM_UNSET (1<<26) /* has null value */
+#define PM_REMOVABLE (1<<27) /* special can be removed from paramtab */
+#define PM_AUTOLOAD (1<<28) /* autoloaded from module */
+#define PM_NORESTORE (1<<29) /* do not restore value of local special */
+#define PM_AUTOALL (1<<29) /* autoload all features in module
* when loading: valid only if PM_AUTOLOAD
* is also present.
*/
-#define PM_HASHELEM (1<<29) /* is a hash-element */
-#define PM_NAMEDDIR (1<<30) /* has a corresponding nameddirtab entry */
+#define PM_HASHELEM (1<<30) /* is a hash-element */
+#define PM_NAMEDDIR (1<<31) /* has a corresponding nameddirtab entry */
/* The option string corresponds to the first of the variables above */
#define TYPESET_OPTSTR "aiEFALRZlurtxUhHTkz"
@@ -2138,6 +2141,8 @@ typedef groupset *Groupset;
#define PRINT_INCLUDEVALUE (1<<4)
#define PRINT_TYPESET (1<<5)
#define PRINT_LINE (1<<6)
+#define PRINT_POSIX_EXPORT (1<<7)
+#define PRINT_POSIX_READONLY (1<<8)
/* flags for printing for the whence builtin */
#define PRINT_WHENCE_CSH (1<<7)
--
cgit 1.4.1