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:
parent
143c2aa69c
commit
3b5f9c744c
154
funcs.c
154
funcs.c
|
@ -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
4
sh.h
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue