From bf258a1c07a9cf1119f83d1d15310b02b94f4d67 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 29 Apr 2015 15:54:49 +0100 Subject: 34992: POSIX fix for readonly variables. With POSIXBUILTINS, variables can be marked readonly if unset. Also, variables can't have the readonly flag removed. --- Src/builtin.c | 37 +++++++++++++++++++++++++++++++++---- Src/params.c | 6 +++++- 2 files changed, 38 insertions(+), 5 deletions(-) (limited to 'Src') diff --git a/Src/builtin.c b/Src/builtin.c index de0101405..0a57489ea 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1931,8 +1931,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * locallevel as an unset one we use the pm struct anyway: that's * handled in createparam(). Here we just avoid using it for the * present tests if it's unset. + * + * POSIXBUILTINS horror: we need to retain the 'readonly' flag + * of an unset parameter. */ - usepm = pm && !(pm->node.flags & PM_UNSET); + usepm = pm && (!(pm->node.flags & PM_UNSET) || + (isset(POSIXBUILTINS) && (pm->node.flags & PM_READONLY))); /* * We need to compare types with an existing pm if special, @@ -2032,6 +2036,20 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), else if (newspecial != NS_NONE && strcmp(pname, "SECONDS") == 0) newspecial = NS_SECONDS; + if (isset(POSIXBUILTINS)) { + /* + * Stricter rules about retaining readonly attribute in this case. + */ + if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) && + !value) + on |= PM_UNSET; + else if (usepm && (pm->node.flags & PM_READONLY) && + !(on & PM_READONLY)) { + zerr("read-only variable: %s", pm->node.nam); + return NULL; + } + } + /* * A parameter will be local if * 1. we are re-using an existing local parameter @@ -2078,9 +2096,15 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } if (usepm == 2) /* do not change the PM_UNSET flag */ pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~off; - else + else { + /* + * Keep unset if using readonly in POSIX mode. + */ + if (!(on & PM_READONLY) || !isset(POSIXBUILTINS)) + off |= PM_UNSET; pm->node.flags = (pm->node.flags | - (on & ~PM_READONLY)) & ~(off | PM_UNSET); + (on & ~PM_READONLY)) & ~off; + } if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { if (typeset_setwidth(cname, pm, ops, on, 0)) return NULL; @@ -2256,7 +2280,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), * readonly flag */ pm = createparam(pname, on & ~PM_READONLY); - DPUTS(!pm, "BUG: parameter not created"); + if (!pm) { + if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | + PM_INTEGER | PM_EFLOAT | PM_FFLOAT)) + zerrnam(cname, "can't change variable attribute: %s", pname); + return NULL; + } if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { if (typeset_setwidth(cname, pm, ops, on, 0)) return NULL; diff --git a/Src/params.c b/Src/params.c index e8a90104c..d53b6ca7e 100644 --- a/Src/params.c +++ b/Src/params.c @@ -874,10 +874,14 @@ createparam(char *name, int flags) DPUTS(oldpm && oldpm->level > locallevel, "BUG: old local parameter not deleted"); if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) { + if (isset(POSIXBUILTINS) && (oldpm->node.flags & PM_READONLY)) { + zerr("read-only variable: %s", name); + return NULL; + } if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL)) { oldpm->node.flags &= ~PM_UNSET; if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) { - Param altpm = + Param altpm = (Param) paramtab->getnode(paramtab, oldpm->ename); if (altpm) altpm->node.flags &= ~PM_UNSET; -- cgit 1.4.1