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

154
funcs.c
View File

@ -38,7 +38,7 @@
#endif #endif
#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 #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 **); static int c_suspend(const char **);
#endif #endif
static int do_whence(const char **, int, bool, bool);
/* getn() that prints error */ /* getn() that prints error */
static int static int
bi_getn(const char *as, int *ai) bi_getn(const char *as, int *ai)
@ -514,14 +516,10 @@ s_put(int c MKSH_A_UNUSED)
int int
c_whence(const char **wp) c_whence(const char **wp)
{ {
struct tbl *tp; int optc;
const char *id; bool pflag = false, vflag = false;
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";
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) while ((optc = ksh_getopt(wp, &builtin_opt, "pv")) != -1)
switch (optc) { switch (optc) {
case 'p': case 'p':
pflag = true; pflag = true;
@ -529,79 +527,82 @@ c_whence(const char **wp)
case 'v': case 'v':
vflag = true; vflag = true;
break; 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': case 'V':
Vflag = true; vflag = true;
break;
case 'v':
vflag = false;
break; break;
case '?': case '?':
return (1); return (1);
} }
wp += builtin_opt.optind; wp += builtin_opt.optind;
fcflags = FC_BI | FC_PATH | FC_FUNC; return (do_whence(wp, fcflags, vflag, true));
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); 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) { while ((vflag || rv == 0) && (id = *wp++) != NULL) {
uint32_t h = 0; h = hash(id);
tp = NULL; tp = NULL;
if (!pflag)
tp = ktsearch(&keywords, id, h = hash(id)); if (fcflags & FC_WHENCE)
if (!tp && !pflag) { tp = ktsearch(&keywords, id, h);
tp = ktsearch(&aliases, id, h ? h : hash(id)); if (!tp && (fcflags & FC_WHENCE)) {
tp = ktsearch(&aliases, id, h);
if (tp && !(tp->flag & ISSET)) if (tp && !(tp->flag & ISSET))
tp = NULL; tp = NULL;
} }
if (!tp) if (!tp)
tp = findcom(id, fcflags); tp = findcom(id, fcflags);
if (vflag || (tp->type != CALIAS && tp->type != CEXEC &&
tp->type != CTALIAS))
shf_puts(id, shl_stdout);
if (vflag) {
switch (tp->type) { switch (tp->type) {
case CKEYWD: case CSHELL:
case CALIAS:
case CFUNC: case CFUNC:
case CSHELL:
shf_puts(" is a", shl_stdout);
break;
}
switch (tp->type) {
case CKEYWD: case CKEYWD:
case CSHELL: shf_puts(id, shl_stdout);
case CTALIAS:
case CEXEC:
shf_putc(' ', shl_stdout);
break; break;
} }
}
switch (tp->type) { switch (tp->type) {
case CKEYWD: case CSHELL:
if (vflag) if (vflag)
shf_puts("reserved word", shl_stdout); shprintf(" is a %sshell %s",
break; (tp->flag & SPEC_BI) ? "special " : "",
case CALIAS: Tbuiltin);
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);
break; break;
case CFUNC: case CFUNC:
if (vflag) { if (vflag) {
shf_puts(" is a", shl_stdout);
if (tp->flag & EXPORT) if (tp->flag & EXPORT)
shf_puts("n exported", shl_stdout); shf_puts("n exported", shl_stdout);
if (tp->flag & TRACE) if (tp->flag & TRACE)
@ -615,34 +616,42 @@ c_whence(const char **wp)
shf_puts(T_function, shl_stdout); shf_puts(T_function, shl_stdout);
} }
break; 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 CEXEC:
case CTALIAS:
if (tp->flag & ISSET) { if (tp->flag & ISSET) {
if (vflag) { if (vflag) {
shf_puts("is ", shl_stdout); shprintf("%s is ", id);
if (tp->type == CTALIAS) if (tp->type == CTALIAS)
shprintf("a tracked %s%s for ", shprintf("a tracked %s%s for ",
(tp->flag & EXPORT) ? (tp->flag & EXPORT) ?
"exported " : null, "exported " : "",
Talias); Talias);
} }
shf_puts(tp->val.s, shl_stdout); shf_puts(tp->val.s, shl_stdout);
} else { } else {
if (vflag) if (vflag)
shf_puts("not found", shl_stdout); shprintf("%s not found", id);
rv = 1; rv = 1;
} }
break; break;
default: case CALIAS:
shf_puts(" is *GOK*", shl_stdout); 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; 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) if (vflag || !rv)
shf_putc('\n', shl_stdout); shf_putc('\n', shl_stdout);
@ -650,17 +659,6 @@ c_whence(const char **wp)
return (rv); 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 */ /* typeset, global, export, and readonly */
static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool); static void c_typeset_vardump(struct tbl *, uint32_t, int, bool, bool);
static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool, static void c_typeset_vardump_recursive(struct block *, uint32_t, int, bool,

4
sh.h
View File

@ -175,7 +175,7 @@
#endif #endif
#ifdef EXTERN #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 #endif
#define MKSH_VERSION "R52 2016/02/26" #define MKSH_VERSION "R52 2016/02/26"
@ -1285,7 +1285,7 @@ enum namerefflag {
#define FC_BI (FC_SPECBI | FC_NORMBI) #define FC_BI (FC_SPECBI | FC_NORMBI)
#define FC_PATH BIT(3) /* do path search */ #define FC_PATH BIT(3) /* do path search */
#define FC_DEFPATH BIT(4) /* use default path in 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_ARGV_ALLOC 0x1 /* argv[] array allocated */
#define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */ #define AF_ARGS_ALLOCED 0x2 /* argument strings allocated */