summaryrefslogtreecommitdiff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/exec.c11
-rw-r--r--Src/lex.c1
-rw-r--r--Src/params.c128
-rw-r--r--Src/parse.c27
-rw-r--r--Src/text.c1
-rw-r--r--Src/zsh.h10
6 files changed, 156 insertions, 22 deletions
diff --git a/Src/exec.c b/Src/exec.c
index ed8293b24..e7b57967b 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -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;
diff --git a/Src/lex.c b/Src/lex.c
index 245e7bb15..11404a646 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1140,6 +1140,7 @@ gettokstr(int c, int sub)
skipparens(Inbrack, Outbrack, &t);
}
}
+ if (*t == '+') t++;
if (t == bptr) {
e = hgetc();
if (e == '(' && incmdpos) {
diff --git a/Src/params.c b/Src/params.c
index 5c4d61e69..6fb5da57f 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -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);
diff --git a/Src/parse.c b/Src/parse.c
index fefbbfe32..48332733b 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -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
diff --git a/Src/text.c b/Src/text.c
index ddb4b8a2a..44527666d 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -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('(');
diff --git a/Src/zsh.h b/Src/zsh.h
index cd6caf3b3..28a3c20e9 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -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 {