Fix typeset issues (LP: #993847)

This was actually more evil:
• use a recursive function to display blocks in reverse order,
  so that local variable values overwrite global ones
• add array support to typeset -p (from typeset -p -)
• display 'set -A varname' line before setting values, for -p
• if -p got arguments, only display those (from the innermost scope)

Also, the usual amount of code cleanup…
This commit is contained in:
tg 2012-05-09 23:21:00 +00:00
parent b89b96a4ab
commit 3125146b43
5 changed files with 169 additions and 152 deletions

14
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.536 2012/05/04 22:44:31 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.537 2012/05/09 23:20:55 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas 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: 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 $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -29,7 +29,7 @@
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD # http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R40 2012/05/04 @(#)MIRBSD KSH R40 2012/05/09
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -4821,7 +4821,8 @@ expected-stdout:
M M
xxx[1]=7 xxx[1]=7
N N
typeset -i xxx set -A xxx
typeset -i xxx[1]
--- ---
name: regression-58 name: regression-58
description: description:
@ -4922,6 +4923,9 @@ stdin:
typeset - typeset -
echo FNORD-8 echo FNORD-8
} | fgrep FNORD } | fgrep FNORD
fnord=(42 23)
typeset -p fnord
echo FNORD-9
expected-stdout: expected-stdout:
FNORD-0 FNORD-0
FNORD-1 FNORD-1
@ -4972,6 +4976,10 @@ expected-stdout:
FNORD_G=7 FNORD_G=7
FNORD_H=8 FNORD_H=8
FNORD-8 FNORD-8
set -A fnord
typeset fnord[0]=42
typeset fnord[1]=23
FNORD-9
--- ---
name: regression-64 name: regression-64
description: description:

182
funcs.c
View File

@ -38,7 +38,7 @@
#endif #endif
#endif #endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.218 2012/05/04 22:18:24 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.219 2012/05/09 23:20:56 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -111,7 +111,7 @@ const struct builtin mkshbuiltins[] = {
{"+true", c_true}, {"+true", c_true},
{"ulimit", c_ulimit}, {"ulimit", c_ulimit},
{"+umask", c_umask}, {"+umask", c_umask},
{"*=unset", c_unset}, {Tsgunset, c_unset},
/* no =: AT&T manual wrong */ /* no =: AT&T manual wrong */
{Tpalias, c_alias}, {Tpalias, c_alias},
{"+cd", c_cd}, {"+cd", c_cd},
@ -119,7 +119,7 @@ const struct builtin mkshbuiltins[] = {
{"chdir", c_cd}, {"chdir", c_cd},
{"+command", c_command}, {"+command", c_command},
{"echo", c_print}, {"echo", c_print},
{"*=export", c_typeset}, {Tsgexport, c_typeset},
{"+fc", c_fc}, {"+fc", c_fc},
{"+getopts", c_getopts}, {"+getopts", c_getopts},
{"=global", c_typeset}, {"=global", c_typeset},
@ -131,7 +131,7 @@ const struct builtin mkshbuiltins[] = {
{"printf", c_printf}, {"printf", c_printf},
#endif #endif
{"pwd", c_pwd}, {"pwd", c_pwd},
{"*=readonly", c_typeset}, {Tsgreadonly, c_typeset},
{T_typeset, c_typeset}, {T_typeset, c_typeset},
{Tpunalias, c_unalias}, {Tpunalias, c_unalias},
{"whence", c_whence}, {"whence", c_whence},
@ -616,13 +616,16 @@ c_command(const char **wp)
} }
/* typeset, global, export, and readonly */ /* typeset, global, export, and readonly */
static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,
bool);
int int
c_typeset(const char **wp) c_typeset(const char **wp)
{ {
struct block *l;
struct tbl *vp, **p; struct tbl *vp, **p;
uint32_t fset = 0, fclr = 0, flag; uint32_t fset = 0, fclr = 0, flag;
int thing = 0, field = 0, base = 0, optc; int thing = 0, field = 0, base = 0, i;
struct block *l;
const char *opts; const char *opts;
const char *fieldstr = NULL, *basestr = NULL; const char *fieldstr = NULL, *basestr = NULL;
bool localv = false, func = false, pflag = false, istset = true; bool localv = false, func = false, pflag = false, istset = true;
@ -665,9 +668,9 @@ c_typeset(const char **wp)
* Here, the number must follow the RLZi option, but is optional * Here, the number must follow the RLZi option, but is optional
* (see the # kludge in ksh_getopt()). * (see the # kludge in ksh_getopt()).
*/ */
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) { while ((i = ksh_getopt(wp, &builtin_opt, opts)) != -1) {
flag = 0; flag = 0;
switch (optc) { switch (i) {
case 'L': case 'L':
flag = LJUST; flag = LJUST;
fieldstr = builtin_opt.optarg; fieldstr = builtin_opt.optarg;
@ -793,8 +796,10 @@ c_typeset(const char **wp)
} }
/* set variables and attributes */ /* set variables and attributes */
if (wp[builtin_opt.optind]) { if (wp[builtin_opt.optind] &&
int i, rv = 0; /* not "typeset -p varname" */
!(!func && pflag && !(fset | fclr))) {
int rv = 0;
struct tbl *f; struct tbl *f;
if (localv && !func) if (localv && !func)
@ -826,6 +831,7 @@ c_typeset(const char **wp)
return (rv); return (rv);
} }
set_refflag = SRF_NOP;
/* list variables and attributes */ /* list variables and attributes */
/* no difference at this point.. */ /* no difference at this point.. */
@ -844,18 +850,47 @@ c_typeset(const char **wp)
shf_putc('\n', shl_stdout); shf_putc('\n', shl_stdout);
} }
} }
} else { } else if (wp[builtin_opt.optind]) {
for (l = e->loc; l; l = l->next) { for (i = builtin_opt.optind; wp[i]; i++) {
for (p = ktsort(&l->vars); (vp = *p++); ) { varsearch(e->loc, &vp, wp[i], hash(wp[i]));
if (!vp)
continue;
c_typeset_vardump(vp, flag, thing, pflag, istset);
}
} else
c_typeset_vardump_recursive(e->loc, flag, thing, pflag, istset);
return (0);
}
static void
c_typeset_vardump_recursive(struct block *l, uint32_t flag, int thing,
bool pflag, bool istset)
{
struct tbl **blockvars, *vp;
if (l->next)
c_typeset_vardump_recursive(l->next, flag, thing, pflag, istset);
blockvars = ktsort(&l->vars);
while ((vp = *blockvars++))
c_typeset_vardump(vp, flag, thing, pflag, istset);
/*XXX doesnt this leak? */
}
static void
c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
bool istset)
{
struct tbl *tvp; struct tbl *tvp;
bool any_set = false; int any_set = 0;
char *s;
/* /*
* See if the parameter is set (for arrays, if any * See if the parameter is set (for arrays, if any
* element is set). * element is set).
*/ */
for (tvp = vp; tvp; tvp = tvp->u.array) for (tvp = vp; tvp; tvp = tvp->u.array)
if (tvp->flag & ISSET) { if (tvp->flag & ISSET) {
any_set = true; any_set = 1;
break; break;
} }
@ -869,112 +904,79 @@ c_typeset(const char **wp)
* otherwise, after "echo $FOO", we would report FOO... * otherwise, after "echo $FOO", we would report FOO...
*/ */
if (!any_set && !(vp->flag & USERATTRIB)) if (!any_set && !(vp->flag & USERATTRIB))
continue; return;
if (flag && (vp->flag & flag) == 0) if (flag && (vp->flag & flag) == 0)
continue; return;
for (; vp; vp = vp->u.array) { if (!(vp->flag & ARRAY))
/* optimise later conditionals */
any_set = 0;
do {
/* /*
* Ignore array elements that aren't * Ignore array elements that aren't set unless there
* set unless there are no set elements, * are no set elements, in which case the first is
* in which case the first is reported on * reported on
*/ */
if ((vp->flag&ARRAY) && any_set && if (any_set && !(vp->flag & ISSET))
!(vp->flag & ISSET))
continue; continue;
/* no arguments */ /* no arguments */
if (thing == 0 && flag == 0) { if (!thing && !flag) {
if (any_set == 1) {
shprintf("%s %s %s\n", Tset, "-A", vp->name);
any_set = 2;
}
/* /*
* AT&T ksh prints things * AT&T ksh prints things like export, integer,
* like export, integer, * leftadj, zerofill, etc., but POSIX says must
* leftadj, zerofill, etc.,
* but POSIX says must
* be suitable for re-entry... * be suitable for re-entry...
*/ */
shf_puts("typeset ", shl_stdout); shprintf("%s %s", Ttypeset, "");
if (((vp->flag&(ARRAY|ASSOC))==ASSOC)) if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
shprintf("%s ", "-n"); shprintf("%s ", "-n");
if ((vp->flag&INTEGER)) if ((vp->flag & INTEGER))
shprintf("%s ", "-i"); shprintf("%s ", "-i");
if ((vp->flag&EXPORT)) if ((vp->flag & EXPORT))
shprintf("%s ", "-x"); shprintf("%s ", "-x");
if ((vp->flag&RDONLY)) if ((vp->flag & RDONLY))
shprintf("%s ", "-r"); shprintf("%s ", "-r");
if ((vp->flag&TRACE)) if ((vp->flag & TRACE))
shprintf("%s ", "-t"); shprintf("%s ", "-t");
if ((vp->flag&LJUST)) if ((vp->flag & LJUST))
shprintf("-L%d ", vp->u2.field); shprintf("-L%d ", vp->u2.field);
if ((vp->flag&RJUST)) if ((vp->flag & RJUST))
shprintf("-R%d ", vp->u2.field); shprintf("-R%d ", vp->u2.field);
if ((vp->flag&ZEROFIL)) if ((vp->flag & ZEROFIL))
shprintf("%s ", "-Z"); shprintf("%s ", "-Z");
if ((vp->flag&LCASEV)) if ((vp->flag & LCASEV))
shprintf("%s ", "-l"); shprintf("%s ", "-l");
if ((vp->flag&UCASEV_AL)) if ((vp->flag & UCASEV_AL))
shprintf("%s ", "-u"); shprintf("%s ", "-u");
if ((vp->flag&INT_U)) if ((vp->flag & INT_U))
shprintf("%s ", "-U"); shprintf("%s ", "-U");
} else if (pflag) {
shprintf("%s %s", istset ? Ttypeset :
(flag & EXPORT) ? Texport : Treadonly, "");
}
if (any_set)
shprintf("%s[%lu]", vp->name, arrayindex(vp));
else
shf_puts(vp->name, shl_stdout); shf_puts(vp->name, shl_stdout);
if (pflag) { if ((!thing && !flag && pflag) ||
char *s = str_val(vp); (thing == '-' && (vp->flag & ISSET))) {
s = str_val(vp);
shf_putc('=', shl_stdout); shf_putc('=', shl_stdout);
/* /* AT&T ksh can't have justified integers... */
* AT&T ksh can't have if ((vp->flag & (INTEGER | LJUST | RJUST)) == INTEGER)
* justified integers...
*/
if ((vp->flag &
(INTEGER|LJUST|RJUST)) ==
INTEGER)
shf_puts(s, shl_stdout); shf_puts(s, shl_stdout);
else else
print_value_quoted(shl_stdout, s); print_value_quoted(shl_stdout, s);
} }
shf_putc('\n', shl_stdout); shf_putc('\n', shl_stdout);
if (vp->flag & ARRAY)
break;
} else {
if (pflag)
shf_puts(istset ?
"typeset " :
(flag & EXPORT) ?
"export " :
"readonly ",
shl_stdout);
if ((vp->flag&ARRAY) && any_set)
shprintf("%s[%lu]",
vp->name,
arrayindex(vp));
else
shf_puts(vp->name, shl_stdout);
if (thing == '-' && (vp->flag&ISSET)) {
char *s = str_val(vp);
shf_putc('=', shl_stdout);
/*
* AT&T ksh can't have
* justified integers...
*/
if ((vp->flag &
(INTEGER|LJUST|RJUST)) ==
INTEGER)
shf_puts(s, shl_stdout);
else
print_value_quoted(shl_stdout, s);
}
shf_putc('\n', shl_stdout);
}
/* /*
* Only report first 'element' of an array with * Only report first 'element' of an array with
* no set elements. * no set elements.
*/ */
if (!any_set) } while (any_set && (vp = vp->u.array));
break;
}
}
}
}
set_refflag = SRF_NOP;
return (0);
} }
int int

11
sh.h
View File

@ -157,9 +157,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.559 2012/05/05 17:37:44 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.560 2012/05/09 23:20:58 tg Exp $");
#endif #endif
#define MKSH_VERSION "R40 2012/05/04" #define MKSH_VERSION "R40 2012/05/09"
/* arithmetic types: C implementation */ /* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES #if !HAVE_CAN_INTTYPES
@ -730,6 +730,12 @@ EXTERN const char Tpunalias[] E_INIT("+unalias");
#define Tunalias (Tpunalias + 1) /* "unalias" */ #define Tunalias (Tpunalias + 1) /* "unalias" */
EXTERN const char Tsgset[] E_INIT("*=set"); EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tsgset + 2) /* "set" */ #define Tset (Tsgset + 2) /* "set" */
EXTERN const char Tsgunset[] E_INIT("*=unset");
#define Tunset (Tsgunset + 2) /* "unset" */
EXTERN const char Tsgexport[] E_INIT("*=export");
#define Texport (Tsgexport + 2) /* "export" */
EXTERN const char Tsgreadonly[] E_INIT("*=readonly");
#define Treadonly (Tsgreadonly + 2) /* "readonly" */
EXTERN const char Tgbuiltin[] E_INIT("=builtin"); EXTERN const char Tgbuiltin[] E_INIT("=builtin");
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */ #define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
EXTERN const char T_function[] E_INIT(" function"); EXTERN const char T_function[] E_INIT(" function");
@ -1895,6 +1901,7 @@ void fpFUNCTf(struct shf *, int, bool, const char *, struct op *);
void newblock(void); void newblock(void);
void popblock(void); void popblock(void);
void initvar(void); void initvar(void);
struct block *varsearch(struct block *, struct tbl **, const char *, uint32_t);
struct tbl *global(const char *); struct tbl *global(const char *);
struct tbl *local(const char *, bool); struct tbl *local(const char *, bool);
char *str_val(struct tbl *); char *str_val(struct tbl *);

10
syn.c
View File

@ -23,7 +23,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.74 2012/03/03 21:30:58 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.75 2012/05/09 23:21:00 tg Exp $");
extern short subshell_nesting_level; extern short subshell_nesting_level;
extern void yyskiputf8bom(void); extern void yyskiputf8bom(void);
@ -52,7 +52,7 @@ static struct op *newtp(int);
static void syntaxerr(const char *) MKSH_A_NORETURN; static void syntaxerr(const char *) MKSH_A_NORETURN;
static void nesting_push(struct nesting_state *, int); static void nesting_push(struct nesting_state *, int);
static void nesting_pop(struct nesting_state *); static void nesting_pop(struct nesting_state *);
static int assign_command(char *); static int assign_command(const char *);
static int inalias(struct source *); static int inalias(struct source *);
static Test_op dbtestp_isa(Test_env *, Test_meta); static Test_op dbtestp_isa(Test_env *, Test_meta);
static const char *dbtestp_getopnd(Test_env *, Test_op, bool); static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
@ -914,13 +914,13 @@ compile(Source *s, bool skiputf8bom)
* $ * $
*/ */
static int static int
assign_command(char *s) assign_command(const char *s)
{ {
if (!*s) if (!*s)
return (0); return (0);
return ((strcmp(s, Talias) == 0) || return ((strcmp(s, Talias) == 0) ||
(strcmp(s, "export") == 0) || (strcmp(s, Texport) == 0) ||
(strcmp(s, "readonly") == 0) || (strcmp(s, Treadonly) == 0) ||
(strcmp(s, Ttypeset) == 0)); (strcmp(s, Ttypeset) == 0));
} }

6
var.c
View File

@ -27,7 +27,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.148 2012/05/04 21:47:04 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/var.c,v 1.149 2012/05/09 23:21:00 tg Exp $");
/*- /*-
* Variables * Variables
@ -141,8 +141,8 @@ initvar(void)
} }
} }
/* common code for several functions below */ /* common code for several functions below and c_typeset() */
static struct block * struct block *
varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h) varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h)
{ {
register struct tbl *vp; register struct tbl *vp;