Add “unset foo[*]” mksh extension, which allows to unset the *contents*

of foo[0] (but not its attributes), and the rest of the array, so that
later “set +A foo bar” will set foo[0]=bar but retain the attributes.

This is important, because, in the future, arrays will have different
attributes per element, instead of all the same (which, actually, is
not entirely true right now either, since “unset foo[0]” will not mo-
dify the attributes of a foo[1] existing at that point in time), where
foo[$newkey] will inherit from foo[0], but typeset foo will only affect
foo[0] no longer foo[*] in the future. (The rules about typeset=local
will still apply, as they affect creation of variables in a scope.)
This commit is contained in:
tg 2010-01-25 14:11:29 +00:00
parent 1ac42c1c1c
commit c700693d11
4 changed files with 116 additions and 16 deletions

79
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.354 2010/01/08 22:21:03 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.355 2010/01/25 14:11:25 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -5224,6 +5224,83 @@ expected-stdout:
!arz[0]:
!arz[1]:
---
name: arrays-8
description:
Check some behavioural rules for arrays.
stdin:
fna() {
set -A aa 9
}
fnb() {
typeset ab
set -A ab 9
}
fnc() {
typeset ac
set -A ac 91
unset ac
set -A ac 92
}
fnd() {
set +A ad 9
}
fne() {
unset ae
set +A ae 9
}
fnf() {
unset af[0]
set +A af 9
}
fng() {
unset ag[*]
set +A ag 9
}
set -A aa 1 2
set -A ab 1 2
set -A ac 1 2
set -A ad 1 2
set -A ae 1 2
set -A af 1 2
set -A ag 1 2
typeset -Z3 aa ab ac ad ae af ag
print 1a ${aa[*]} .
print 1b ${ab[*]} .
print 1c ${ac[*]} .
print 1d ${ad[*]} .
print 1e ${ae[*]} .
print 1f ${af[*]} .
print 1g ${ag[*]} .
fna
fnb
fnc
fnd
fne
fnf
fng
print 2a ${aa[*]} .
print 2b ${ab[*]} .
print 2c ${ac[*]} .
print 2d ${ad[*]} .
print 2e ${ae[*]} .
print 2f ${af[*]} .
print 2g ${ag[*]} .
expected-stdout:
1a 001 002 .
1b 001 002 .
1c 001 002 .
1d 001 002 .
1e 001 002 .
1f 001 002 .
1g 001 002 .
2a 9 .
2b 001 002 .
2c 92 .
2d 009 002 .
2e 9 .
2f 9 002 .
2g 009 .
---
name: varexpand-substr-1
description:
Check if bash-style substring expansion works

24
funcs.c
View File

@ -4,7 +4,7 @@
/* $OpenBSD: c_ulimit.c,v 1.17 2008/03/21 12:51:19 millert Exp $ */
/*-
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -25,7 +25,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.147 2009/12/12 22:27:07 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.148 2010/01/25 14:11:26 tg Exp $");
#if HAVE_KILLPG
/*
@ -1666,7 +1666,7 @@ c_getopts(const char **wp)
if (voptarg->flag & INTEGER)
typeset("OPTARG", 0, INTEGER, 0, 0);
if (user_opt.optarg == NULL)
unset(voptarg, 0);
unset(voptarg, 1);
else
/* This can't fail (have cleared readonly/integer) */
setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
@ -2397,13 +2397,27 @@ c_unset(const char **wp)
wp += builtin_opt.optind;
for (; (id = *wp) != NULL; wp++)
if (unset_var) { /* unset variable */
struct tbl *vp = global(id);
struct tbl *vp;
char *cp = NULL;
size_t n;
n = strlen(id);
if (n > 3 && id[n-3] == '[' && id[n-2] == '*' &&
id[n-1] == ']') {
strndupx(cp, id, n - 3, ATEMP);
id = cp;
optc = 3;
} else
optc = vstrchr(id, '[') ? 0 : 1;
vp = global(id);
afree(cp, ATEMP);
if ((vp->flag&RDONLY)) {
bi_errorf("%s is read only", vp->name);
return (1);
}
unset(vp, vstrchr(id, '[') ? 1 : 0);
unset(vp, optc);
} else /* unset function */
define(id, NULL);
return (0);

7
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.206 2010/01/08 22:21:05 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.207 2010/01/25 14:11:27 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
@ -71,7 +71,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always.
.\"
.Dd $Mdocdate: January 8 2010 $
.Dd $Mdocdate: January 25 2010 $
.\"
.\" Check which macro package we use
.\"
@ -4652,6 +4652,9 @@ the default
.Pc
or functions
.Pq Fl f .
With
.Ar parameter Ns [*] ,
attributes are kept, only values are unset.
.Pp
.It Ic wait Op Ar job ...
Wait for the specified job(s) to finish.

22
var.c
View File

@ -1,7 +1,7 @@
/* $OpenBSD: var.c,v 1.34 2007/10/15 02:16:35 deraadt Exp $ */
/*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
@ -22,7 +22,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.100 2009/12/05 17:43:50 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.101 2010/01/25 14:11:29 tg Exp $");
/*
* Variables
@ -834,15 +834,17 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
return (vp);
}
/* Unset a variable. array_ref is set if there was an array reference in
* the name lookup (eg, x[2]).
/**
* Unset a variable. The flags can be:
* |1 = tear down entire array
* |2 = keep attributes, only unset content
*/
void
unset(struct tbl *vp, int array_ref)
unset(struct tbl *vp, int flags)
{
if (vp->flag & ALLOC)
afree(vp->val.s, vp->areap);
if ((vp->flag & ARRAY) && !array_ref) {
if ((vp->flag & ARRAY) && (flags & 1)) {
struct tbl *a, *tmp;
/* Free up entire array */
@ -855,8 +857,12 @@ unset(struct tbl *vp, int array_ref)
}
vp->u.array = NULL;
}
if (flags & 2) {
vp->flag &= ~(ALLOC|ISSET);
return;
}
/* If foo[0] is being unset, the remainder of the array is kept... */
vp->flag &= SPECIAL | (array_ref ? ARRAY|DEFINED : 0);
vp->flag &= SPECIAL | ((flags & 1) ? 0 : ARRAY|DEFINED);
if (vp->flag & SPECIAL)
unsetspec(vp); /* responsible for 'unspecial'ing var */
}
@ -1363,7 +1369,7 @@ set_array(const char *var, bool reset, const char **vals)
/* This code is quite non-optimal */
if (reset)
/* trash existing values and attributes */
unset(vp, 0);
unset(vp, 1);
/* todo: would be nice for assignment to completely succeed or
* completely fail. Only really effects integer arrays:
* evaluation of some of vals[] may fail...