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:
parent
b89b96a4ab
commit
3125146b43
14
check.t
14
check.t
@ -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: 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 $
|
||||
@ -29,7 +29,7 @@
|
||||
# http://www.freebsd.org/cgi/cvsweb.cgi/src/tools/regression/bin/test/regress.sh?rev=HEAD
|
||||
|
||||
expected-stdout:
|
||||
@(#)MIRBSD KSH R40 2012/05/04
|
||||
@(#)MIRBSD KSH R40 2012/05/09
|
||||
description:
|
||||
Check version of shell.
|
||||
stdin:
|
||||
@ -4821,7 +4821,8 @@ expected-stdout:
|
||||
M
|
||||
xxx[1]=7
|
||||
N
|
||||
typeset -i xxx
|
||||
set -A xxx
|
||||
typeset -i xxx[1]
|
||||
---
|
||||
name: regression-58
|
||||
description:
|
||||
@ -4922,6 +4923,9 @@ stdin:
|
||||
typeset -
|
||||
echo FNORD-8
|
||||
} | fgrep FNORD
|
||||
fnord=(42 23)
|
||||
typeset -p fnord
|
||||
echo FNORD-9
|
||||
expected-stdout:
|
||||
FNORD-0
|
||||
FNORD-1
|
||||
@ -4972,6 +4976,10 @@ expected-stdout:
|
||||
FNORD_G=7
|
||||
FNORD_H=8
|
||||
FNORD-8
|
||||
set -A fnord
|
||||
typeset fnord[0]=42
|
||||
typeset fnord[1]=23
|
||||
FNORD-9
|
||||
---
|
||||
name: regression-64
|
||||
description:
|
||||
|
280
funcs.c
280
funcs.c
@ -38,7 +38,7 @@
|
||||
#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
|
||||
/*
|
||||
@ -111,7 +111,7 @@ const struct builtin mkshbuiltins[] = {
|
||||
{"+true", c_true},
|
||||
{"ulimit", c_ulimit},
|
||||
{"+umask", c_umask},
|
||||
{"*=unset", c_unset},
|
||||
{Tsgunset, c_unset},
|
||||
/* no =: AT&T manual wrong */
|
||||
{Tpalias, c_alias},
|
||||
{"+cd", c_cd},
|
||||
@ -119,7 +119,7 @@ const struct builtin mkshbuiltins[] = {
|
||||
{"chdir", c_cd},
|
||||
{"+command", c_command},
|
||||
{"echo", c_print},
|
||||
{"*=export", c_typeset},
|
||||
{Tsgexport, c_typeset},
|
||||
{"+fc", c_fc},
|
||||
{"+getopts", c_getopts},
|
||||
{"=global", c_typeset},
|
||||
@ -131,7 +131,7 @@ const struct builtin mkshbuiltins[] = {
|
||||
{"printf", c_printf},
|
||||
#endif
|
||||
{"pwd", c_pwd},
|
||||
{"*=readonly", c_typeset},
|
||||
{Tsgreadonly, c_typeset},
|
||||
{T_typeset, c_typeset},
|
||||
{Tpunalias, c_unalias},
|
||||
{"whence", c_whence},
|
||||
@ -616,13 +616,16 @@ c_command(const char **wp)
|
||||
}
|
||||
|
||||
/* 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
|
||||
c_typeset(const char **wp)
|
||||
{
|
||||
struct block *l;
|
||||
struct tbl *vp, **p;
|
||||
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 *fieldstr = NULL, *basestr = NULL;
|
||||
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
|
||||
* (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;
|
||||
switch (optc) {
|
||||
switch (i) {
|
||||
case 'L':
|
||||
flag = LJUST;
|
||||
fieldstr = builtin_opt.optarg;
|
||||
@ -793,8 +796,10 @@ c_typeset(const char **wp)
|
||||
}
|
||||
|
||||
/* set variables and attributes */
|
||||
if (wp[builtin_opt.optind]) {
|
||||
int i, rv = 0;
|
||||
if (wp[builtin_opt.optind] &&
|
||||
/* not "typeset -p varname" */
|
||||
!(!func && pflag && !(fset | fclr))) {
|
||||
int rv = 0;
|
||||
struct tbl *f;
|
||||
|
||||
if (localv && !func)
|
||||
@ -826,6 +831,7 @@ c_typeset(const char **wp)
|
||||
return (rv);
|
||||
}
|
||||
|
||||
set_refflag = SRF_NOP;
|
||||
/* list variables and attributes */
|
||||
|
||||
/* no difference at this point.. */
|
||||
@ -844,139 +850,135 @@ c_typeset(const char **wp)
|
||||
shf_putc('\n', shl_stdout);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (l = e->loc; l; l = l->next) {
|
||||
for (p = ktsort(&l->vars); (vp = *p++); ) {
|
||||
struct tbl *tvp;
|
||||
bool any_set = false;
|
||||
/*
|
||||
* See if the parameter is set (for arrays, if any
|
||||
* element is set).
|
||||
*/
|
||||
for (tvp = vp; tvp; tvp = tvp->u.array)
|
||||
if (tvp->flag & ISSET) {
|
||||
any_set = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check attributes - note that all array elements
|
||||
* have (should have?) the same attributes, so checking
|
||||
* the first is sufficient.
|
||||
*
|
||||
* Report an unset param only if the user has
|
||||
* explicitly given it some attribute (like export);
|
||||
* otherwise, after "echo $FOO", we would report FOO...
|
||||
*/
|
||||
if (!any_set && !(vp->flag & USERATTRIB))
|
||||
continue;
|
||||
if (flag && (vp->flag & flag) == 0)
|
||||
continue;
|
||||
for (; vp; vp = vp->u.array) {
|
||||
/*
|
||||
* Ignore array elements that aren't
|
||||
* set unless there are no set elements,
|
||||
* in which case the first is reported on
|
||||
*/
|
||||
if ((vp->flag&ARRAY) && any_set &&
|
||||
!(vp->flag & ISSET))
|
||||
continue;
|
||||
/* no arguments */
|
||||
if (thing == 0 && flag == 0) {
|
||||
/*
|
||||
* AT&T ksh prints things
|
||||
* like export, integer,
|
||||
* leftadj, zerofill, etc.,
|
||||
* but POSIX says must
|
||||
* be suitable for re-entry...
|
||||
*/
|
||||
shf_puts("typeset ", shl_stdout);
|
||||
if (((vp->flag&(ARRAY|ASSOC))==ASSOC))
|
||||
shprintf("%s ", "-n");
|
||||
if ((vp->flag&INTEGER))
|
||||
shprintf("%s ", "-i");
|
||||
if ((vp->flag&EXPORT))
|
||||
shprintf("%s ", "-x");
|
||||
if ((vp->flag&RDONLY))
|
||||
shprintf("%s ", "-r");
|
||||
if ((vp->flag&TRACE))
|
||||
shprintf("%s ", "-t");
|
||||
if ((vp->flag&LJUST))
|
||||
shprintf("-L%d ", vp->u2.field);
|
||||
if ((vp->flag&RJUST))
|
||||
shprintf("-R%d ", vp->u2.field);
|
||||
if ((vp->flag&ZEROFIL))
|
||||
shprintf("%s ", "-Z");
|
||||
if ((vp->flag&LCASEV))
|
||||
shprintf("%s ", "-l");
|
||||
if ((vp->flag&UCASEV_AL))
|
||||
shprintf("%s ", "-u");
|
||||
if ((vp->flag&INT_U))
|
||||
shprintf("%s ", "-U");
|
||||
shf_puts(vp->name, shl_stdout);
|
||||
if (pflag) {
|
||||
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);
|
||||
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
|
||||
* no set elements.
|
||||
*/
|
||||
if (!any_set)
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (wp[builtin_opt.optind]) {
|
||||
for (i = builtin_opt.optind; wp[i]; i++) {
|
||||
varsearch(e->loc, &vp, wp[i], hash(wp[i]));
|
||||
if (!vp)
|
||||
continue;
|
||||
c_typeset_vardump(vp, flag, thing, pflag, istset);
|
||||
}
|
||||
}
|
||||
set_refflag = SRF_NOP;
|
||||
} 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 doesn’t this leak? */
|
||||
}
|
||||
|
||||
static void
|
||||
c_typeset_vardump(struct tbl *vp, uint32_t flag, int thing, bool pflag,
|
||||
bool istset)
|
||||
{
|
||||
struct tbl *tvp;
|
||||
int any_set = 0;
|
||||
char *s;
|
||||
|
||||
/*
|
||||
* See if the parameter is set (for arrays, if any
|
||||
* element is set).
|
||||
*/
|
||||
for (tvp = vp; tvp; tvp = tvp->u.array)
|
||||
if (tvp->flag & ISSET) {
|
||||
any_set = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check attributes - note that all array elements
|
||||
* have (should have?) the same attributes, so checking
|
||||
* the first is sufficient.
|
||||
*
|
||||
* Report an unset param only if the user has
|
||||
* explicitly given it some attribute (like export);
|
||||
* otherwise, after "echo $FOO", we would report FOO...
|
||||
*/
|
||||
if (!any_set && !(vp->flag & USERATTRIB))
|
||||
return;
|
||||
if (flag && (vp->flag & flag) == 0)
|
||||
return;
|
||||
if (!(vp->flag & ARRAY))
|
||||
/* optimise later conditionals */
|
||||
any_set = 0;
|
||||
do {
|
||||
/*
|
||||
* Ignore array elements that aren't set unless there
|
||||
* are no set elements, in which case the first is
|
||||
* reported on
|
||||
*/
|
||||
if (any_set && !(vp->flag & ISSET))
|
||||
continue;
|
||||
/* no arguments */
|
||||
if (!thing && !flag) {
|
||||
if (any_set == 1) {
|
||||
shprintf("%s %s %s\n", Tset, "-A", vp->name);
|
||||
any_set = 2;
|
||||
}
|
||||
/*
|
||||
* AT&T ksh prints things like export, integer,
|
||||
* leftadj, zerofill, etc., but POSIX says must
|
||||
* be suitable for re-entry...
|
||||
*/
|
||||
shprintf("%s %s", Ttypeset, "");
|
||||
if (((vp->flag & (ARRAY | ASSOC)) == ASSOC))
|
||||
shprintf("%s ", "-n");
|
||||
if ((vp->flag & INTEGER))
|
||||
shprintf("%s ", "-i");
|
||||
if ((vp->flag & EXPORT))
|
||||
shprintf("%s ", "-x");
|
||||
if ((vp->flag & RDONLY))
|
||||
shprintf("%s ", "-r");
|
||||
if ((vp->flag & TRACE))
|
||||
shprintf("%s ", "-t");
|
||||
if ((vp->flag & LJUST))
|
||||
shprintf("-L%d ", vp->u2.field);
|
||||
if ((vp->flag & RJUST))
|
||||
shprintf("-R%d ", vp->u2.field);
|
||||
if ((vp->flag & ZEROFIL))
|
||||
shprintf("%s ", "-Z");
|
||||
if ((vp->flag & LCASEV))
|
||||
shprintf("%s ", "-l");
|
||||
if ((vp->flag & UCASEV_AL))
|
||||
shprintf("%s ", "-u");
|
||||
if ((vp->flag & INT_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);
|
||||
if ((!thing && !flag && pflag) ||
|
||||
(thing == '-' && (vp->flag & ISSET))) {
|
||||
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
|
||||
* no set elements.
|
||||
*/
|
||||
} while (any_set && (vp = vp->u.array));
|
||||
}
|
||||
|
||||
int
|
||||
c_alias(const char **wp)
|
||||
{
|
||||
|
11
sh.h
11
sh.h
@ -157,9 +157,9 @@
|
||||
#endif
|
||||
|
||||
#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
|
||||
#define MKSH_VERSION "R40 2012/05/04"
|
||||
#define MKSH_VERSION "R40 2012/05/09"
|
||||
|
||||
/* arithmetic types: C implementation */
|
||||
#if !HAVE_CAN_INTTYPES
|
||||
@ -730,6 +730,12 @@ EXTERN const char Tpunalias[] E_INIT("+unalias");
|
||||
#define Tunalias (Tpunalias + 1) /* "unalias" */
|
||||
EXTERN const char Tsgset[] E_INIT("*=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");
|
||||
#define Tbuiltin (Tgbuiltin + 1) /* "builtin" */
|
||||
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 popblock(void);
|
||||
void initvar(void);
|
||||
struct block *varsearch(struct block *, struct tbl **, const char *, uint32_t);
|
||||
struct tbl *global(const char *);
|
||||
struct tbl *local(const char *, bool);
|
||||
char *str_val(struct tbl *);
|
||||
|
10
syn.c
10
syn.c
@ -23,7 +23,7 @@
|
||||
|
||||
#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 void yyskiputf8bom(void);
|
||||
@ -52,7 +52,7 @@ static struct op *newtp(int);
|
||||
static void syntaxerr(const char *) MKSH_A_NORETURN;
|
||||
static void nesting_push(struct nesting_state *, int);
|
||||
static void nesting_pop(struct nesting_state *);
|
||||
static int assign_command(char *);
|
||||
static int assign_command(const char *);
|
||||
static int inalias(struct source *);
|
||||
static Test_op dbtestp_isa(Test_env *, Test_meta);
|
||||
static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
|
||||
@ -914,13 +914,13 @@ compile(Source *s, bool skiputf8bom)
|
||||
* $
|
||||
*/
|
||||
static int
|
||||
assign_command(char *s)
|
||||
assign_command(const char *s)
|
||||
{
|
||||
if (!*s)
|
||||
return (0);
|
||||
return ((strcmp(s, Talias) == 0) ||
|
||||
(strcmp(s, "export") == 0) ||
|
||||
(strcmp(s, "readonly") == 0) ||
|
||||
(strcmp(s, Texport) == 0) ||
|
||||
(strcmp(s, Treadonly) == 0) ||
|
||||
(strcmp(s, Ttypeset) == 0));
|
||||
}
|
||||
|
||||
|
6
var.c
6
var.c
@ -27,7 +27,7 @@
|
||||
#include <sys/sysctl.h>
|
||||
#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
|
||||
@ -141,8 +141,8 @@ initvar(void)
|
||||
}
|
||||
}
|
||||
|
||||
/* common code for several functions below */
|
||||
static struct block *
|
||||
/* common code for several functions below and c_typeset() */
|
||||
struct block *
|
||||
varsearch(struct block *l, struct tbl **vpp, const char *vn, uint32_t h)
|
||||
{
|
||||
register struct tbl *vp;
|
||||
|
Loading…
x
Reference in New Issue
Block a user