a bit more with POSIX and the other shells

I considered http://austingroupbugs.net/view.php?id=253 but the use
of bi_errorf() is interesting, especially as it’s often enough a
noreturn function, and funnily enough, 'cd -P /foo' returns 0 while
'chdir -P /foo' fails (so idk where to put -e)…
This commit is contained in:
tg 2011-03-27 18:50:06 +00:00
parent ad3707d17d
commit e8ea9954aa
5 changed files with 139 additions and 56 deletions

63
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.437 2011/03/26 21:46:00 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.438 2011/03/27 18:50:02 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 $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2011/03/26 @(#)MIRBSD KSH R39 2011/03/27
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -4679,6 +4679,65 @@ stdin:
expected-stdout: expected-stdout:
ok ok
--- ---
name: readonly-0
description:
Ensure readonly is honoured for assignments and unset
stdin:
"$__progname" -c 'u=x; echo $? $u .' || echo aborted, $?
echo =
"$__progname" -c 'readonly u; u=x; echo $? $u .' || echo aborted, $?
echo =
"$__progname" -c 'u=x; readonly u; unset u; echo $? $u .' || echo aborted, $?
expected-stdout:
0 x .
=
aborted, 2
=
1 x .
expected-stderr-pattern:
/read *only/
---
name: readonly-1
description:
http://austingroupbugs.net/view.php?id=367 for export
stdin:
"$__progname" -c 'readonly foo; export foo=a; echo $?' || echo aborted, $?
expected-stdout:
aborted, 2
expected-stderr-pattern:
/read *only/
---
name: readonly-2a
description:
Check that getopts works as intended, for readonly-2b to be valid
stdin:
"$__progname" -c 'set -- -a b; getopts a c; echo $? $c .; getopts a c; echo $? $c .' || echo aborted, $?
expected-stdout:
0 a .
1 ? .
---
name: readonly-2b
description:
http://austingroupbugs.net/view.php?id=367 for getopts
stdin:
"$__progname" -c 'readonly c; set -- -a b; getopts a c; echo $? $c .' || echo aborted, $?
expected-stdout:
2 .
expected-stderr-pattern:
/read *only/
---
name: readonly-3
description:
http://austingroupbugs.net/view.php?id=367 for read
stdin:
echo x | "$__progname" -c 'read s; echo $? $s .' || echo aborted, $?
echo y | "$__progname" -c 'readonly s; read s; echo $? $s .' || echo aborted, $?
expected-stdout:
0 x .
2 .
expected-stderr-pattern:
/read *only/
---
name: syntax-1 name: syntax-1
description: description:
Check that lone ampersand is a syntax error Check that lone ampersand is a syntax error

22
funcs.c
View File

@ -38,7 +38,7 @@
#endif #endif
#endif #endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.181 2011/03/27 01:30:36 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.182 2011/03/27 18:50:04 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -1454,7 +1454,7 @@ c_getopts(const char **wp)
vq = global(var); vq = global(var);
/* Error message already printed (integer, readonly) */ /* Error message already printed (integer, readonly) */
if (!setstr(vq, buf, KSH_RETURN_ERROR)) if (!setstr(vq, buf, KSH_RETURN_ERROR))
rv = 1; rv = 2;
if (Flag(FEXPORT)) if (Flag(FEXPORT))
typeset(var, EXPORT, 0, 0, 0); typeset(var, EXPORT, 0, 0, 0);
@ -1917,7 +1917,7 @@ c_read(const char **wp)
shf_flush(shf); shf_flush(shf);
bi_errorf("%s: %s", *wp, "is read only"); bi_errorf("%s: %s", *wp, "is read only");
afree(wpalloc, ATEMP); afree(wpalloc, ATEMP);
return (1); return (2);
} }
if (Flag(FEXPORT)) if (Flag(FEXPORT))
typeset(*wp, EXPORT, 0, 0, 0); typeset(*wp, EXPORT, 0, 0, 0);
@ -2187,7 +2187,7 @@ int
c_unset(const char **wp) c_unset(const char **wp)
{ {
const char *id; const char *id;
int optc; int optc, rv = 0;
bool unset_var = true; bool unset_var = true;
while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1) while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != -1)
@ -2199,7 +2199,8 @@ c_unset(const char **wp)
unset_var = true; unset_var = true;
break; break;
case '?': case '?':
return (1); /*XXX not reached due to GF_ERROR */
return (2);
} }
wp += builtin_opt.optind; wp += builtin_opt.optind;
for (; (id = *wp) != NULL; wp++) for (; (id = *wp) != NULL; wp++)
@ -2222,14 +2223,15 @@ c_unset(const char **wp)
afree(cp, ATEMP); afree(cp, ATEMP);
if ((vp->flag&RDONLY)) { if ((vp->flag&RDONLY)) {
bi_errorf("%s: %s", vp->name, "is read only"); warningf(true, "%s: %s", vp->name,
return (1); "is read only");
} rv = 1;
unset(vp, optc); } else
unset(vp, optc);
} else } else
/* unset function */ /* unset function */
define(id, NULL); define(id, NULL);
return (0); return (rv);
} }
static void static void

92
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h> #include <locale.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.186 2011/03/26 19:43:47 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/main.c,v 1.187 2011/03/27 18:50:05 tg Exp $");
extern char **environ; extern char **environ;
@ -999,23 +999,59 @@ tty_close(void)
} }
/* A shell error occurred (eg, syntax error, etc.) */ /* A shell error occurred (eg, syntax error, etc.) */
#define VWARNINGF_ERRORPREFIX 1
#define VWARNINGF_FILELINE 2
#define VWARNINGF_BUILTIN 4
#define VWARNINGF_INTERNAL 8
static void MKSH_A_FORMAT(printf, 2, 0)
vwarningf(unsigned int flags, const char *fmt, va_list ap)
{
if (*fmt != 1) {
if (flags & VWARNINGF_INTERNAL)
shf_fprintf(shl_out, "internal error: ");
if (flags & VWARNINGF_ERRORPREFIX)
error_prefix(tobool(flags & VWARNINGF_FILELINE));
if ((flags & VWARNINGF_BUILTIN) &&
/* not set when main() calls parse_args() */
builtin_argv0 && builtin_argv0 != kshname)
shf_fprintf(shl_out, "%s: ", builtin_argv0);
shf_vfprintf(shl_out, fmt, ap);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
}
void
errorfx(int rc, const char *fmt, ...)
{
va_list va;
exstat = rc;
/* debugging: note that stdout not valid */
shl_stdout_ok = false;
va_start(va, fmt);
vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
va_end(va);
unwind(LERROR);
}
void void
errorf(const char *fmt, ...) errorf(const char *fmt, ...)
{ {
va_list va; va_list va;
exstat = 1;
/* debugging: note that stdout not valid */ /* debugging: note that stdout not valid */
shl_stdout_ok = false; shl_stdout_ok = false;
exstat = 1; va_start(va, fmt);
if (*fmt != 1) { vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE, fmt, va);
error_prefix(true); va_end(va);
va_start(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
unwind(LERROR); unwind(LERROR);
} }
@ -1025,12 +1061,10 @@ warningf(bool fileline, const char *fmt, ...)
{ {
va_list va; va_list va;
error_prefix(fileline);
va_start(va, fmt); va_start(va, fmt);
shf_vfprintf(shl_out, fmt, va); vwarningf(VWARNINGF_ERRORPREFIX | (fileline ? VWARNINGF_FILELINE : 0),
fmt, va);
va_end(va); va_end(va);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
} }
/* /*
@ -1046,17 +1080,12 @@ bi_errorf(const char *fmt, ...)
shl_stdout_ok = false; shl_stdout_ok = false;
exstat = 1; exstat = 1;
if (*fmt != 1) {
error_prefix(true); va_start(va, fmt);
/* not set when main() calls parse_args() */ vwarningf(VWARNINGF_ERRORPREFIX | VWARNINGF_FILELINE |
if (builtin_argv0 && builtin_argv0 != kshname) VWARNINGF_BUILTIN, fmt, va);
shf_fprintf(shl_out, "%s: ", builtin_argv0); va_end(va);
va_start(va, fmt);
shf_vfprintf(shl_out, fmt, va);
va_end(va);
shf_putchar('\n', shl_out);
}
shf_flush(shl_out);
/* /*
* POSIX special builtins and ksh special builtins cause * POSIX special builtins and ksh special builtins cause
* non-interactive shells to exit. * non-interactive shells to exit.
@ -1069,22 +1098,13 @@ bi_errorf(const char *fmt, ...)
} }
/* Called when something that shouldn't happen does */ /* Called when something that shouldn't happen does */
void
internal_verrorf(const char *fmt, va_list ap)
{
shf_fprintf(shl_out, "internal error: ");
shf_vfprintf(shl_out, fmt, ap);
shf_putchar('\n', shl_out);
shf_flush(shl_out);
}
void void
internal_errorf(const char *fmt, ...) internal_errorf(const char *fmt, ...)
{ {
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
internal_verrorf(fmt, va); vwarningf(VWARNINGF_INTERNAL, fmt, va);
va_end(va); va_end(va);
unwind(LERROR); unwind(LERROR);
} }
@ -1095,7 +1115,7 @@ internal_warningf(const char *fmt, ...)
va_list va; va_list va;
va_start(va, fmt); va_start(va, fmt);
internal_verrorf(fmt, va); vwarningf(VWARNINGF_INTERNAL, fmt, va);
va_end(va); va_end(va);
} }

10
sh.h
View File

@ -154,9 +154,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.455 2011/03/27 01:30:38 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.456 2011/03/27 18:50:05 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2011/03/26" #define MKSH_VERSION "R39 2011/03/27"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -1642,14 +1642,16 @@ void cleanup_proc_env(void);
void errorf(const char *, ...) void errorf(const char *, ...)
MKSH_A_NORETURN MKSH_A_NORETURN
MKSH_A_FORMAT(printf, 1, 2); MKSH_A_FORMAT(printf, 1, 2);
void errorfx(int, const char *, ...)
MKSH_A_NORETURN
MKSH_A_FORMAT(printf, 2, 3);
void warningf(bool, const char *, ...) void warningf(bool, const char *, ...)
MKSH_A_FORMAT(printf, 2, 3); MKSH_A_FORMAT(printf, 2, 3);
void bi_errorf(const char *, ...) void bi_errorf(const char *, ...)
MKSH_A_FORMAT(printf, 1, 2); MKSH_A_FORMAT(printf, 1, 2);
#define errorfz() errorf("\1") #define errorfz() errorf("\1")
#define errorfxz(rc) errorfx((rc), "\1")
#define bi_errorfz() bi_errorf("\1") #define bi_errorfz() bi_errorf("\1")
void internal_verrorf(const char *, va_list)
MKSH_A_FORMAT(printf, 1, 0);
void internal_errorf(const char *, ...) void internal_errorf(const char *, ...)
MKSH_A_NORETURN MKSH_A_NORETURN
MKSH_A_FORMAT(printf, 1, 2); MKSH_A_FORMAT(printf, 1, 2);

8
var.c
View File

@ -26,7 +26,7 @@
#include <sys/sysctl.h> #include <sys/sysctl.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.118 2011/03/13 01:20:25 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/var.c,v 1.119 2011/03/27 18:50:06 tg Exp $");
/* /*
* Variables * Variables
@ -407,7 +407,7 @@ setstr(struct tbl *vq, const char *s, int error_ok)
if ((vq->flag & RDONLY) && !no_ro_check) { if ((vq->flag & RDONLY) && !no_ro_check) {
warningf(true, "%s: %s", vq->name, "is read only"); warningf(true, "%s: %s", vq->name, "is read only");
if (!error_ok) if (!error_ok)
errorfz(); errorfxz(2);
return (0); return (0);
} }
if (!(vq->flag&INTEGER)) { /* string dest */ if (!(vq->flag&INTEGER)) { /* string dest */
@ -758,7 +758,7 @@ typeset(const char *var, Tflag set, Tflag clr, int field, int base)
if ((vpbase->flag&RDONLY) && if ((vpbase->flag&RDONLY) &&
(val || clr || (set & ~EXPORT))) (val || clr || (set & ~EXPORT)))
/* XXX check calls - is error here ok by POSIX? */ /* XXX check calls - is error here ok by POSIX? */
errorf("%s: %s", tvar, "is read only"); errorfx(2, "%s: %s", tvar, "is read only");
afree(tvar, ATEMP); afree(tvar, ATEMP);
/* most calls are with set/clr == 0 */ /* most calls are with set/clr == 0 */
@ -1313,7 +1313,7 @@ set_array(const char *var, bool reset, const char **vals)
/* Note: AT&T ksh allows set -A but not set +A of a read-only var */ /* Note: AT&T ksh allows set -A but not set +A of a read-only var */
if ((vp->flag&RDONLY)) if ((vp->flag&RDONLY))
errorf("%s: %s", var, "is read only"); errorfx(2, "%s: %s", var, "is read only");
/* This code is quite non-optimal */ /* This code is quite non-optimal */
if (reset) if (reset)
/* trash existing values and attributes */ /* trash existing values and attributes */