1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2024-06-01 12:56:04 +02:00

16353: add += parameter assignments

This commit is contained in:
Oliver Kiddle 2001-12-17 17:17:38 +00:00
parent 8659013fb8
commit 52b8303537
10 changed files with 419 additions and 25 deletions

View File

@ -1,3 +1,9 @@
2001-12-17 Oliver Kiddle <opk@zsh.org>
* 16353: Src/exec.c, Src/lex.c, Src/params.c, Src/parse.c,
Src/text.c, Src/zsh.h, Doc/Zsh/params.yo, Test/.distfiles,
Test/A06assign.ztst: add += parameter assignments
2001-12-17 Clint Adams <clint@zsh.org>
* 16357: Doc/Zsh/expn.yo, Src/subst.c:

View File

@ -20,8 +20,9 @@ cindex(assignment)
indent(var(name)tt(=)var(value))
If the integer attribute, tt(-i), is set for var(name), the var(value)
is subject to arithmetic evaluation. See noderef(Array Parameters)
for additional forms of assignment.
is subject to arithmetic evaluation. Furthermore, by replacing `tt(=)'
with `tt(+=)', a parameter can be added or appended to. See
noderef(Array Parameters) for additional forms of assignment.
To refer to the value of a parameter, write `tt($)var(name)' or
`tt(${)var(name)tt(})'. See

View File

@ -1512,7 +1512,8 @@ addvars(Estate state, Wordcode pc, int export)
if (htok)
untokenize(name);
if (xtr)
fprintf(xtrerr, "%s=", name);
fprintf(xtrerr,
WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC ? "%s+=" : "%s=", name);
if ((isstr = (WC_ASSIGN_TYPE(ac) == WC_ASSIGN_SCALAR))) {
init_list1(svl, ecgetstr(state, EC_DUPTOK, &htok));
vl = &svl;
@ -1561,10 +1562,12 @@ addvars(Estate state, Wordcode pc, int export)
}
allexp = opts[ALLEXPORT];
opts[ALLEXPORT] = 1;
pm = setsparam(name, val);
pm = assignsparam(name, val,
WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
opts[ALLEXPORT] = allexp;
} else
pm = setsparam(name, val);
pm = assignsparam(name, val,
WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
if (errflag) {
state->pc = opc;
return;
@ -1587,7 +1590,7 @@ addvars(Estate state, Wordcode pc, int export)
fprintf(xtrerr, "%s ", *ptr);
fprintf(xtrerr, ") ");
}
setaparam(name, arr);
assignaparam(name, arr, WC_ASSIGN_TYPE2(ac) == WC_ASSIGN_INC);
if (errflag) {
state->pc = opc;
return;

View File

@ -1140,6 +1140,7 @@ gettokstr(int c, int sub)
skipparens(Inbrack, Outbrack, &t);
}
}
if (*t == '+') t++;
if (t == bptr) {
e = hgetc();
if (e == '(' && incmdpos) {

View File

@ -1724,9 +1724,12 @@ setarrvalue(Value v, char **val)
}
if (v->start == 0 && v->end == -1) {
if (PM_TYPE(v->pm->flags) == PM_HASHED)
arrhashsetfn(v->pm, val);
arrhashsetfn(v->pm, val, 0);
else
(v->pm->sets.afn) (v->pm, val);
} else if (v->start == -1 && v->end == 0 &&
PM_TYPE(v->pm->flags) == PM_HASHED) {
arrhashsetfn(v->pm, val, 1);
} else {
char **old, **new, **p, **q, **r;
int n, ll, i;
@ -1870,12 +1873,15 @@ gethkparam(char *s)
/**/
mod_export Param
setsparam(char *s, char *val)
assignsparam(char *s, char *val, int augment)
{
struct value vbuf;
Value v;
char *t = s;
char *ss;
char *ss, *copy, *var;
size_t lv;
mnumber lhs, rhs;
int sstart;
if (!isident(s)) {
zerr("not an identifier: %s", s, 0);
@ -1893,8 +1899,10 @@ setsparam(char *s, char *val)
} else {
if (!(v = getvalue(&vbuf, &s, 1)))
createparam(t, PM_SCALAR);
else if ((PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
!(v->pm->flags & (PM_SPECIAL|PM_TIED)) && unset(KSHARRAYS)) {
else if ((((v->pm->flags & PM_ARRAY) && !augment) ||
(v->pm->flags & PM_HASHED)) &&
!(v->pm->flags & (PM_SPECIAL|PM_TIED)) &&
unset(KSHARRAYS)) {
unsetparam(t);
createparam(t, PM_SCALAR);
v = NULL;
@ -1905,6 +1913,78 @@ setsparam(char *s, char *val)
zsfree(val);
return NULL;
}
if (augment) {
if (v->start == 0 && v->end == -1) {
switch (PM_TYPE(v->pm->flags)) {
case PM_SCALAR:
v->start = INT_MAX; /* just append to scalar value */
break;
case PM_INTEGER:
case PM_EFLOAT:
case PM_FFLOAT:
rhs = matheval(val);
lhs = getnumvalue(v);
if (lhs.type == MN_FLOAT) {
if ((rhs.type) == MN_FLOAT)
lhs.u.d = lhs.u.d + rhs.u.d;
else
lhs.u.d = lhs.u.d + (double)rhs.u.l;
} else {
if ((rhs.type) == MN_INTEGER)
lhs.u.l = lhs.u.l + rhs.u.l;
else
lhs.u.l = lhs.u.l + (zlong)rhs.u.d;
}
setnumvalue(v, lhs);
unqueue_signals();
zsfree(val);
return v->pm; /* avoid later setstrvalue() call */
case PM_ARRAY:
if (unset(KSHARRAYS)) {
v->start = arrlen(v->pm->gets.afn(v->pm));
v->end = v->start + 1;
} else {
/* ksh appends scalar to first element */
v->end = 1;
goto kshappend;
}
break;
}
} else {
switch (PM_TYPE(v->pm->flags)) {
case PM_SCALAR:
if (v->end > 0)
v->start = v->end;
else
v->start = v->end = strlen(v->pm->gets.cfn(v->pm)) +
v->end + 1;
break;
case PM_INTEGER:
case PM_EFLOAT:
case PM_FFLOAT:
unqueue_signals();
zerr("attempt to add to slice of a numeric variable",
NULL, 0);
zsfree(val);
return NULL;
case PM_ARRAY:
kshappend:
/* treat slice as the end element */
v->start = sstart = v->end > 0 ? v->end - 1 : v->end;
v->isarr = 0;
var = getstrvalue(v);
v->start = sstart;
copy = val;
lv = strlen(var);
val = (char *)zalloc(lv + strlen(var));
strcpy(val, var);
strcpy(val + lv, copy);
zsfree(copy);
break;
}
}
}
setstrvalue(v, val);
unqueue_signals();
return v->pm;
@ -1912,7 +1992,7 @@ setsparam(char *s, char *val)
/**/
mod_export Param
setaparam(char *s, char **val)
assignaparam(char *s, char **val, int augment)
{
struct value vbuf;
Value v;
@ -1946,6 +2026,18 @@ setaparam(char *s, char **val)
else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
!(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
int uniq = v->pm->flags & PM_UNIQUE;
if (augment) {
/* insert old value at the beginning of the val array */
char **new;
int lv = arrlen(val);
new = (char **) zalloc(sizeof(char *) * (lv + 2));
*new = ztrdup(getstrvalue(v));
memcpy(new+1, val, sizeof(char *) * (lv + 1));
free(val);
val = new;
}
unsetparam(t);
createparam(t, PM_ARRAY | uniq);
v = NULL;
@ -1954,8 +2046,27 @@ setaparam(char *s, char **val)
if (!v)
if (!(v = fetchvalue(&vbuf, &t, 1, SCANPM_ASSIGNING))) {
unqueue_signals();
freearray(val);
return NULL;
}
if (augment) {
if (v->start == 0 && v->end == -1) {
if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
v->start = arrlen(v->pm->gets.afn(v->pm));
v->end = v->start + 1;
} else if (PM_TYPE(v->pm->flags) & PM_HASHED)
v->start = -1, v->end = 0;
} else {
if (v->end > 0)
v->start = v->end--;
else if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
v->end = arrlen(v->pm->gets.afn(v->pm)) + v->end;
v->start = v->end + 1;
}
}
}
setarrvalue(v, val);
unqueue_signals();
return v->pm;
@ -2291,7 +2402,7 @@ hashsetfn(Param pm, HashTable x)
/**/
static void
arrhashsetfn(Param pm, char **val)
arrhashsetfn(Param pm, char **val, int augment)
{
/* Best not to shortcut this by using the existing hash table, *
* since that could cause trouble for special hashes. This way, *
@ -2309,7 +2420,8 @@ arrhashsetfn(Param pm, char **val)
return;
}
if (alen)
ht = paramtab = newparamtable(17, pm->nam);
if (!(augment && (ht = paramtab = pm->gets.hfn(pm))))
ht = paramtab = newparamtable(17, pm->nam);
while (*aptr) {
/* The parameter name is ztrdup'd... */
v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);

View File

@ -1488,11 +1488,17 @@ par_simple(int *complex, int nr)
} else if (tok == ENVSTRING) {
char *p, *name, *str;
ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, 0));
name = tokstr;
for (p = tokstr; *p && *p != Inbrack && *p != '='; p++);
if (*p == Inbrack && !skipparens(Inbrack, Outbrack, &p) &&
*p == '=') {
for (p = tokstr; *p && *p != Inbrack && *p != '=' && *p != '+';
p++);
if (*p == Inbrack) skipparens(Inbrack, Outbrack, &p);
if (*p == '+') {
*p++ = '\0';
ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0));
} else
ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_NEW, 0));
if (*p == '=') {
*p = '\0';
str = p + 1;
} else
@ -1501,15 +1507,20 @@ par_simple(int *complex, int nr)
ecstr(str);
isnull = 0;
} else if (tok == ENVARRAY) {
int oldcmdpos = incmdpos, n;
int oldcmdpos = incmdpos, n, type2;
p = ecadd(0);
incmdpos = 0;
if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') {
tokstr[type2] = '\0';
type2 = WC_ASSIGN_INC;
} else
type2 = WC_ASSIGN_NEW;
ecstr(tokstr);
cmdpush(CS_ARRAY);
yylex();
n = par_nl_wordlist();
ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, n);
ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, type2, n);
cmdpop();
if (tok != OUTPAR)
YYERROR(oecused);
@ -2288,8 +2299,8 @@ init_eprog(void)
#define FD_MINMAP 4096
#define FD_PRELEN 12
#define FD_MAGIC 0x03040506
#define FD_OMAGIC 0x06050403
#define FD_MAGIC 0x04050607
#define FD_OMAGIC 0x07060504
#define FDF_MAP 1
#define FDF_OTHER 2

View File

@ -323,6 +323,7 @@ gettext2(Estate state)
break;
case WC_ASSIGN:
taddstr(ecgetstr(state, EC_NODUP, NULL));
if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) taddchr('+');
taddchr('=');
if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
taddchr('(');

View File

@ -591,10 +591,13 @@ struct eccstr {
#define WCB_REDIR(T) wc_bld(WC_REDIR, (T))
#define WC_ASSIGN_TYPE(C) (wc_data(C) & ((wordcode) 1))
#define WC_ASSIGN_TYPE2(C) ((wc_data(C) & ((wordcode) 2)) >> 1)
#define WC_ASSIGN_SCALAR 0
#define WC_ASSIGN_ARRAY 1
#define WC_ASSIGN_NUM(C) (wc_data(C) >> 1)
#define WCB_ASSIGN(T,N) wc_bld(WC_ASSIGN, ((T) | ((N) << 1)))
#define WC_ASSIGN_NEW 0
#define WC_ASSIGN_INC 1
#define WC_ASSIGN_NUM(C) (wc_data(C) >> 2)
#define WCB_ASSIGN(T,A,N) wc_bld(WC_ASSIGN, ((T) | ((A) << 1) | ((N) << 2)))
#define WC_SIMPLE_ARGC(C) wc_data(C)
#define WCB_SIMPLE(N) wc_bld(WC_SIMPLE, (N))
@ -1198,6 +1201,9 @@ struct paramdef {
{ name, PM_ARRAY, (void *) var, (void *) arrvarsetfn, \
(void *) arrvargetfn, (void *) stdunsetfn }
#define setsparam(S,V) assignsparam(S,V,0)
#define setaparam(S,V) assignaparam(S,V,0)
/* node for named directory hash table (nameddirtab) */
struct nameddir {

View File

@ -8,6 +8,6 @@ A03quoting.ztst C04funcdef.ztst Makefile.in ztst.zsh
A04redirect.ztst D01prompt.ztst V02zregexparse.ztst
A05execution.ztst D02glob.ztst Y01completion.ztst
D06subscript.ztst V01zmodload.ztst E01options.ztst
B02typeset.ztst B03print.ztst
B02typeset.ztst B03print.ztst A06assign.ztst
README
'

253
Test/A06assign.ztst Normal file
View File

@ -0,0 +1,253 @@
# Tests of parameter assignments
%test
typeset -A assoc
assoc=(one 1 two 2 odd)
1:assign to association with odd no. of values
?(eval):2: bad set of key/value pairs for associative array
# tests of var+=scalar
s+=foo
echo $s
0:append scalar to unset scalar
>foo
s=foo
s+=bar
echo $s
0:append to scalar
>foobar
set -- a b c
2+=end
echo $2
0:append to positional parameter
>bend
a=(first second)
a+=last
print -l $a
0:add scalar to array
>first
>second
>last
setopt ksharrays
a=(first second)
a+=last
print -l $a
unsetopt ksharrays
0:add scalar to array with ksharrays set
>firstlast
a=(1 2)
a[@]+=3
print -l $a
0:add scalar to array with alternate syntax
>1
>2
>3
integer i=10
i+=20
(( i == 30 ))
0:add to integer
float f=3.4
f+=2.3
printf "%g\n" f
0:add to float
>5.7
typeset -A hash
hash=(one 1)
h+=string
[[ $h[@] == string ]]
0:add scalar to association
# tests of var+=(array)
unset a
a+=(1 2 3)
print -l $a
0:add array to unset parameter
>1
>2
>3
a=(a)
a+=(b)
print -l $a
0:add array to existing array
>a
>b
s=foo
s+=(bar)
print -l $s
0:add array to scalar
>foo
>bar
integer i=1
i+=(2 3)
print -l $i
0:add array to integer
>1
>2
>3
float f=2.5
f+=(3.5 4.5)
printf '%g\n' $f
0:add array to float
>2.5
>3.5
>4.5
typeset -A h
h+=(a 1 b 2)
print -l $h
0:add to empty association
>1
>2
typeset -A h
h=(a 1)
h+=(b 2 c 3)
print -l $h
0:add to association
>1
>2
>3
# tests of var[range]+=scalar
s=sting
s[2]+=art
echo $s
0:insert scalar inside another
>starting
s=inert
s[-4]+=s
echo $s
0:insert scalar inside another with negative index
>insert
s=append
s[2,6]+=age
echo $s
0:append scalar to scalar using a range
>appendage
s=123456789
s[3,-5]+=X
echo $s
0:insert scalar inside another, specifying a slice
>12345X6789
a=(a b c)
a[2]+=oo
echo $a
0:append to array element
>a boo c
a=(a b c d)
a[-2]+=ool
echo $a
0:append to array element with negative index
>a b cool d
a=(a b c d)
a[2,-1]+=oom
echo $a
0:append to array element, specifying a slice
>a b c doom
setopt ksharrays
a=(a b c d)
a[0]+=0
echo $a
unsetopt ksharrays
0:append to array element with ksharrays set
>a0
typeset -A h
h=(one foo)
h[one]+=bar
echo $h
0:append to association element
>foobar
typeset -A h
h[foo]+=bar
echo ${(kv)h}
0:append to non-existent association element
>foo bar
typeset -A h
h=(one a two b three c four d)
h[(I)*o*]+=append
1:attempt to append to slice of association
?(eval):3: h: attempt to set slice of associative array
integer i=123
i[2]+=6
1:attempt to add to indexed integer variable
?(eval):2: attempt to add to slice of a numeric variable
float f=1234.5
f[2,4]+=3
1:attempt to add to slice of float variable
?(eval):2: attempt to add to slice of a numeric variable
unset u
u[3]+=third
echo $u[1]:$u[3]
0:append to unset variable with index
>:third
# tests of var[range]+=(array)
a=(1 2 3)
a[2]+=(a b)
echo $a
0:insert array inside another
>1 2 a b 3
a=(a b c)
a[-1]+=(d)
echo $a
0:append to array using negative index
>a b c d
a=(1 2 3 4)
a[-1,-3]+=(x)
echo $a
0:insert array using negative range
>1 2 x 3 4
s=string
s[2]+=(a b)
1:attempt to insert array into string
?(eval):2: s: attempt to assign array value to non-array
integer i=365
i[2]+=(1 2)
1:attempt to insert array into string
?(eval):2: i: attempt to assign array value to non-array
typeset -A h
h=(a 1)
h[a]+=(b 2)
1:attempt to append array to hash element
?(eval):3: h: attempt to set slice of associative array
unset u
u[-34,-2]+=(a z)
echo $u
0:add array to indexed unset variable
>a z