implement bash-style array initialisation, as requested by many

still experimental
This commit is contained in:
tg 2007-06-22 23:34:42 +00:00
parent 4fef868b6d
commit 3a94b076a0
5 changed files with 104 additions and 9 deletions

24
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.115 2007/06/21 16:04:45 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.116 2007/06/22 23:34:40 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 $
@ -7,7 +7,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R29 2007/06/21
@(#)MIRBSD KSH R29 2007/06/22
description:
Check version of shell.
category: pdksh
@ -4009,3 +4009,23 @@ expected-stdout:
integer='typeset -i'
local=typeset
---
name: arrays-1
description:
Check if Korn Shell arrays work as expected
stdin:
v="c d"
set -A foo -- a \$v "$v" '$v' b
echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|"
expected-stdout:
5|a|$v|c d|$v|b|
---
name: arrays-2
description:
Check if bash-style arrays work as expected
stdin:
v="c d"
foo=(a \$v "$v" '$v' b)
echo "${#foo[*]}|${foo[0]}|${foo[1]}|${foo[2]}|${foo[3]}|${foo[4]}|"
expected-stdout:
5|a|$v|c d|$v|b|
---

28
lex.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.35 2007/06/16 15:02:56 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.36 2007/06/22 23:34:40 tg Exp $");
/* Structure to keep track of the lexing state and the various pieces of info
* needed for each particular state. */
@ -37,6 +37,12 @@ struct lex_state {
} u_sbquote;
Lex_state *base; /* used to point to next state block */
/* =(...) */
struct sletarray_info {
int nparen; /* count open parentheses */
#define ls_sletarray ls_info.u_sletarray
} u_sletarray;
} ls_info;
};
@ -121,6 +127,9 @@ yylex(int cf)
*wp++ = OQUOTE; /* enclose arguments in (double) quotes */
state = SLETPAREN;
statep->ls_sletparen.nparen = 0;
} else if (cf&LETARRAY) {
state = SLETARRAY;
statep->ls_sletarray.nparen = 0;
} else { /* normal lexing */
state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
while ((c = getsc()) == ' ' || c == '\t')
@ -535,6 +544,17 @@ yylex(int cf)
++statep->ls_sletparen.nparen;
goto Sbase2;
case SLETARRAY: /* LETARRAY: =( ... ) */
if (c == '('/*)*/)
++statep->ls_sletarray.nparen;
else if (c == /*(*/')')
if (statep->ls_sletarray.nparen-- == 0) {
c = 0;
goto Done;
}
*wp++ = CHAR, *wp++ = c;
break;
case SHEREDELIM: /* <<,<<- delimiter */
/* XXX chuck this state (and the next) - use
* the existing states ($ and \`..` should be
@ -607,6 +627,9 @@ yylex(int cf)
/* XXX figure out what is missing */
yyerror("no closing quote\n");
if (state == SLETARRAY && statep->ls_sletarray.nparen != -1)
yyerror("syntax error: ')' missing\n");
/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
if (state == SHEREDELIM)
state = SBASE;
@ -680,7 +703,8 @@ yylex(int cf)
*wp++ = EOS; /* terminate word */
yylval.cp = Xclose(ws, wp);
if (state == SWORD || state == SLETPAREN) /* ONEWORD? */
if (state == SWORD || state == SLETPAREN ||
state == SLETARRAY) /* ONEWORD? */
return LWORD;
ungetsc(c); /* unget terminator */

15
mksh.1
View File

@ -1,7 +1,7 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.87 2007/06/17 00:50:08 tg Exp $
.\" $MirOS: src/bin/mksh/mksh.1,v 1.88 2007/06/22 23:34:41 tg Exp $
.\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $
.\"
.Dd June 17, 2007
.Dd June 22, 2007
.Dt MKSH 1
.Os MirBSD
.Sh NAME
@ -3208,6 +3208,17 @@ is used, the array is reset (i.e. emptied) first; if
.Ic +A
is used, the first N elements are set (where N is the number of arguments);
the rest are left untouched.
.Pp
An alternative syntax for the command
.Ic set -A foo -- a b c
which is compatible to
.Tn GNU
.Nm bash
and also supported by
.At
.Nm ksh93
is:
.Ic foo=(a b c)
.It Fl a \*(Ba Ic allexport
All new parameters are created with the export attribute.
.It Fl b \*(Ba Ic notify

6
sh.h
View File

@ -8,8 +8,8 @@
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.149 2007/06/21 16:04:46 tg Exp $"
#define MKSH_VERSION "R29 2007/06/21"
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.150 2007/06/22 23:34:41 tg Exp $"
#define MKSH_VERSION "R29 2007/06/22"
#if HAVE_SYS_PARAM_H
#include <sys/param.h>
@ -1112,6 +1112,7 @@ struct source {
#define SHEREDQUOTE 10 /* parsing " in <<,<<- delimiter */
#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 12 /* parsing ${..[#%]..} */
#define SLETARRAY 13 /* inside =( ), just copy */
typedef union {
int i;
@ -1162,6 +1163,7 @@ typedef union {
#define HEREDELIM BIT(9) /* parsing <<,<<- delimiter */
#define LQCHAR BIT(10) /* source string contains QCHAR */
#define HEREDOC BIT(11) /* parsing a here document */
#define LETARRAY BIT(12) /* copy expression inside =( ) */
#define HERES 10 /* max << in line */

40
syn.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.14 2007/06/06 23:28:17 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.15 2007/06/22 23:34:42 tg Exp $");
struct nesting_state {
int start_token; /* token than began nesting (eg, FOR) */
@ -248,6 +248,9 @@ get_command(int cf)
ACCEPT;
goto Subshell;
}
if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
XPsize(vars) == 1 && is_wdvarassign(yylval.cp))
goto is_wdarrassign;
/* Must be a function */
if (iopn != 0 || XPsize(args) != 1 ||
XPsize(vars) != 0)
@ -257,6 +260,41 @@ get_command(int cf)
musthave(')', 0);
t = function_body(XPptrv(args)[0], false);
goto Leave;
is_wdarrassign:
{
static const char set_cmd0[] = {
CHAR, 'e', CHAR, 'v',
CHAR, 'a', CHAR, 'l', EOS
};
static const char set_cmd1[] = {
CHAR, 's', CHAR, 'e',
CHAR, 't', CHAR, ' ',
CHAR, '-', CHAR, 'A', EOS
};
static const char set_cmd2[] = {
CHAR, '-', CHAR, '-', EOS
};
char *tcp;
XPfree(vars);
XPinit(vars, 16);
/*
* we know (or rather hope) that yylval.cp
* contains a string "varname="
*/
tcp = wdcopy(yylval.cp, ATEMP);
tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
/* now make an array assignment command */
t = newtp(TCOM);
t->lineno = source->line;
ACCEPT;
XPput(args, wdcopy(set_cmd0, ATEMP));
XPput(args, wdcopy(set_cmd1, ATEMP));
XPput(args, tcp);
XPput(args, wdcopy(set_cmd2, ATEMP));
musthave(LWORD,LETARRAY);
XPput(args, yylval.cp);
break;
}
default:
goto Leave;