I didn’t like the code behind command -[Vv] and whence, so I rewrote it.

Bugreport by Martijn Dekker <martijn@inlv.org> about POSIX non-compliance
This commit is contained in:
tg 2016-02-26 20:56:45 +00:00
parent 143c2aa69c
commit 3b5f9c744c
2 changed files with 82 additions and 84 deletions

162
funcs.c
View File

@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.294 2016/01/21 18:24:39 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.295 2016/02/26 20:56:43 tg Exp $");
#if HAVE_KILLPG
/*
@ -64,6 +64,8 @@ __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.294 2016/01/21 18:24:39 tg Exp $");
static int c_suspend(const char **);
#endif
static int do_whence(const char **, int, bool, bool);
/* getn() that prints error */
static int
bi_getn(const char *as, int *ai)
@ -514,14 +516,10 @@ s_put(int c MKSH_A_UNUSED)
int
c_whence(const char **wp)
{
struct tbl *tp;
const char *id;
bool pflag = false, vflag = false, Vflag = false;
int rv = 0, optc, fcflags;
bool iam_whence = wp[0][0] == 'w';
const char *opts = iam_whence ? "pv" : "pvV";
int optc;
bool pflag = false, vflag = false;
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
while ((optc = ksh_getopt(wp, &builtin_opt, "pv")) != -1)
switch (optc) {
case 'p':
pflag = true;
@ -529,79 +527,82 @@ c_whence(const char **wp)
case 'v':
vflag = true;
break;
case '?':
return (1);
}
wp += builtin_opt.optind;
return (do_whence(wp, pflag ? FC_PATH :
FC_BI | FC_FUNC | FC_PATH | FC_WHENCE, vflag, false));
}
/* note: command without -vV is dealt with in comexec() */
int
c_command(const char **wp)
{
int optc, fcflags = FC_BI | FC_FUNC | FC_PATH | FC_WHENCE;
bool vflag = false;
/* options not sorted to facilitate string pooling */
while ((optc = ksh_getopt(wp, &builtin_opt, "Vpv")) != -1)
switch (optc) {
case 'p':
fcflags |= FC_DEFPATH;
break;
case 'V':
Vflag = true;
vflag = true;
break;
case 'v':
vflag = false;
break;
case '?':
return (1);
}
wp += builtin_opt.optind;
fcflags = FC_BI | FC_PATH | FC_FUNC;
if (!iam_whence) {
/* Note that -p on its own is deal with in comexec() */
if (pflag)
fcflags |= FC_DEFPATH;
/*
* Convert command options to whence options - note that
* command -pV uses a different path search than whence -v
* or whence -pv. This should be considered a feature.
*/
vflag = Vflag;
}
if (pflag)
fcflags &= ~(FC_BI | FC_FUNC);
return (do_whence(wp, fcflags, vflag, true));
}
static int
do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
{
uint32_t h;
int rv = 0;
struct tbl *tp;
const char *id;
while ((vflag || rv == 0) && (id = *wp++) != NULL) {
uint32_t h = 0;
h = hash(id);
tp = NULL;
if (!pflag)
tp = ktsearch(&keywords, id, h = hash(id));
if (!tp && !pflag) {
tp = ktsearch(&aliases, id, h ? h : hash(id));
if (fcflags & FC_WHENCE)
tp = ktsearch(&keywords, id, h);
if (!tp && (fcflags & FC_WHENCE)) {
tp = ktsearch(&aliases, id, h);
if (tp && !(tp->flag & ISSET))
tp = NULL;
}
if (!tp)
tp = findcom(id, fcflags);
if (vflag || (tp->type != CALIAS && tp->type != CEXEC &&
tp->type != CTALIAS))
switch (tp->type) {
case CSHELL:
case CFUNC:
case CKEYWD:
shf_puts(id, shl_stdout);
if (vflag) {
switch (tp->type) {
case CKEYWD:
case CALIAS:
case CFUNC:
case CSHELL:
shf_puts(" is a", shl_stdout);
break;
}
switch (tp->type) {
case CKEYWD:
case CSHELL:
case CTALIAS:
case CEXEC:
shf_putc(' ', shl_stdout);
break;
}
break;
}
switch (tp->type) {
case CKEYWD:
case CSHELL:
if (vflag)
shf_puts("reserved word", shl_stdout);
break;
case CALIAS:
if (vflag)
shprintf("n %salias for ",
(tp->flag & EXPORT) ? "exported " : null);
if (!iam_whence && !vflag)
shprintf("%s %s=", Talias, id);
print_value_quoted(shl_stdout, tp->val.s);
shprintf(" is a %sshell %s",
(tp->flag & SPEC_BI) ? "special " : "",
Tbuiltin);
break;
case CFUNC:
if (vflag) {
shf_puts(" is a", shl_stdout);
if (tp->flag & EXPORT)
shf_puts("n exported", shl_stdout);
if (tp->flag & TRACE)
@ -615,34 +616,42 @@ c_whence(const char **wp)
shf_puts(T_function, shl_stdout);
}
break;
case CSHELL:
if (vflag) {
if (tp->flag & SPEC_BI)
shf_puts("special ", shl_stdout);
shprintf("%s %s", "shell", Tbuiltin);
}
break;
case CTALIAS:
case CEXEC:
case CTALIAS:
if (tp->flag & ISSET) {
if (vflag) {
shf_puts("is ", shl_stdout);
shprintf("%s is ", id);
if (tp->type == CTALIAS)
shprintf("a tracked %s%s for ",
(tp->flag & EXPORT) ?
"exported " : null,
"exported " : "",
Talias);
}
shf_puts(tp->val.s, shl_stdout);
} else {
if (vflag)
shf_puts("not found", shl_stdout);
shprintf("%s not found", id);
rv = 1;
}
break;
default:
shf_puts(" is *GOK*", shl_stdout);
case CALIAS:
if (vflag) {
shprintf("%s is an %s%s for ", id,
(tp->flag & EXPORT) ? "exported " : "",
Talias);
} else if (iscommand)
shprintf("%s %s=", Talias, id);
print_value_quoted(shl_stdout, tp->val.s);
break;
case CKEYWD:
if (vflag)
shf_puts(" is a reserved word", shl_stdout);
break;
#ifndef MKSH_SMALL
default:
bi_errorf("%s is of unknown type %d", id, tp->type);
return (1);
#endif
}
if (vflag || !rv)
shf_putc('\n', shl_stdout);
@ -650,17 +659,6 @@ c_whence(const char **wp)
return (rv);
}
/* Deal with command -vV - command -p dealt with in comexec() */
int
c_command(const char **wp)
{
/*
* Let c_whence do the work. Note that c_command() must be
* a distinct function from c_whence() (tested in comexec()).
*/
return (c_whence(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,

4
sh.h
View File

@ -175,7 +175,7 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.763 2016/02/26 18:48:13 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.764 2016/02/26 20:56:45 tg Exp $");
#endif
#define MKSH_VERSION "R52 2016/02/26"
@ -1285,7 +1285,7 @@ enum namerefflag {
#define FC_BI (FC_SPECBI | FC_NORMBI)
#define FC_PATH BIT(3) /* do path search */
#define FC_DEFPATH BIT(4) /* use default path in path search */
#define FC_WHENCE BIT(5) /* for use by command and whence */
#define AF_ARGV_ALLOC 0x1 /* argv[] array allocated */
#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */