allow 'eval break', from Martijn Dekker

also, more string pooling, while here
This commit is contained in:
tg 2017-04-08 01:07:18 +00:00
parent cadc884008
commit fae945962b
6 changed files with 88 additions and 43 deletions

20
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.772 2017/04/06 02:15:22 tg Exp $
# $MirOS: src/bin/mksh/check.t,v 1.773 2017/04/08 01:07:12 tg Exp $
# -*- mode: sh -*-
#-
# Copyright © 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
@ -30,7 +30,7 @@
# (2013/12/02 20:39:44) http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/regress/bin/ksh/?sortby=date
expected-stdout:
@(#)MIRBSD KSH R54 2017/04/05
@(#)MIRBSD KSH R54 2017/04/07
description:
Check version of shell.
stdin:
@ -39,7 +39,7 @@ name: KSH_VERSION
category: !shell:legacy-yes,!shell:textmode-yes
---
expected-stdout:
@(#)LEGACY KSH R54 2017/04/05
@(#)LEGACY KSH R54 2017/04/07
description:
Check version of legacy shell.
stdin:
@ -48,7 +48,7 @@ name: KSH_VERSION-legacy
category: !shell:legacy-no,!shell:textmode-yes
---
expected-stdout:
@(#)MIRBSD KSH R54 2017/04/05 +TEXTMODE
@(#)MIRBSD KSH R54 2017/04/07 +TEXTMODE
description:
Check version of shell.
stdin:
@ -57,7 +57,7 @@ name: KSH_VERSION-textmode
category: !shell:legacy-yes,!shell:textmode-no
---
expected-stdout:
@(#)LEGACY KSH R54 2017/04/05 +TEXTMODE
@(#)LEGACY KSH R54 2017/04/07 +TEXTMODE
description:
Check version of legacy shell.
stdin:
@ -1001,6 +1001,8 @@ stdin:
echo end-$i
done
echo end-3
for i in a b c; do echo $i; eval break; echo bad-$i; done
echo end-4
expected-stdout:
a
end-1
@ -1013,6 +1015,8 @@ expected-stdout:
c:x
end-c
end-3
a
end-4
---
name: break-2
description:
@ -1082,6 +1086,8 @@ stdin:
echo end-$i
done
echo end-3
for i in a b c; do echo $i; eval continue; echo bad-$i ; done
echo end-4
expected-stdout:
a
b
@ -1104,6 +1110,10 @@ expected-stdout:
c:z
end-c
end-3
a
b
c
end-4
---
name: continue-2
description:

6
exec.c
View File

@ -23,7 +23,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.194 2017/04/02 15:02:40 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.195 2017/04/08 01:07:15 tg Exp $");
#ifndef MKSH_DEFAULT_EXECSHELL
#define MKSH_DEFAULT_EXECSHELL MKSH_UNIXROOT "/bin/sh"
@ -806,7 +806,7 @@ comexec(struct op *t, struct tbl * volatile tp, const char **ap,
/* NOTREACHED */
default:
quitenv(NULL);
internal_errorf(Tf_sd, "CFUNC", i);
internal_errorf(Tunexpected_type, Tunwind, Tfunction, i);
}
break;
}
@ -1506,7 +1506,7 @@ iosetup(struct ioword *iop, struct tbl *tp)
/* herein() may already have printed message */
if (u == -1) {
u = errno;
warningf(true, Tf_cant,
warningf(true, Tf_cant_ss_s,
iotype == IODUP ? "dup" :
(iotype == IOREAD || iotype == IOHERE) ?
Topen : Tcreate, cp, cstrerror(u));

16
funcs.c
View File

@ -38,7 +38,7 @@
#endif
#endif
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.337 2017/04/06 19:02:05 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.338 2017/04/08 01:07:15 tg Exp $");
#if HAVE_KILLPG
/*
@ -100,7 +100,7 @@ const struct builtin mkshbuiltins[] = {
{Tbracket, c_test},
/* no =: AT&T manual wrong */
{Talias, c_alias},
{"*=break", c_brkcont},
{Tsgbreak, c_brkcont},
{T__builtin, c_builtin},
{Tbuiltin, c_builtin},
{Tbcat, c_cat},
@ -108,7 +108,7 @@ const struct builtin mkshbuiltins[] = {
/* dash compatibility hack */
{"chdir", c_cd},
{T_command, c_command},
{"*=continue", c_brkcont},
{Tsgcontinue, c_brkcont},
{"echo", c_print},
{"*=eval", c_eval},
{"*=exec", c_exec},
@ -131,7 +131,7 @@ const struct builtin mkshbuiltins[] = {
{"*=return", c_exitreturn},
{Tsgset, c_set},
{"*=shift", c_shift},
{"=source", c_dot},
{Tgsource, c_dot},
#if !defined(MKSH_UNEMPLOYED) && HAVE_GETSID
{Tsuspend, c_suspend},
#endif
@ -731,7 +731,7 @@ do_whence(const char **wp, int fcflags, bool vflag, bool iscommand)
break;
#ifndef MKSH_SMALL
default:
bi_errorf("%s is of unknown type %d", id, tp->type);
bi_errorf(Tunexpected_type, id, Tcommand, tp->type);
return (1);
#endif
}
@ -1263,7 +1263,7 @@ c_getopts(const char **wp)
if (user_opt.optarg == NULL)
unset(voptarg, 1);
else
/* This can't fail (have cleared readonly/integer) */
/* this can't fail (haing cleared readonly/integer) */
setstr(voptarg, user_opt.optarg, KSH_RETURN_ERROR);
rv = 0;
@ -2063,7 +2063,7 @@ c_eval(const char **wp)
savef = Flag(FERREXIT);
Flag(FERREXIT) |= 0x80;
rv = shell(s, false);
rv = shell(s, 2);
Flag(FERREXIT) = savef;
source = saves;
afree(s, ATEMP);
@ -2199,7 +2199,7 @@ c_brkcont(const char **wp)
* scripts, but don't generate an error (ie, keep going).
*/
if ((unsigned int)n == quit) {
warningf(true, "%s: can't %s", wp[0], wp[0]);
warningf(true, Tf_cant_s, wp[0], wp[0]);
return (0);
}
/*

View File

@ -27,7 +27,7 @@
#include <sys/file.h>
#endif
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.159 2016/11/11 18:44:32 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.160 2017/04/08 01:07:16 tg Exp $");
Trap sigtraps[ksh_NSIG + 1];
static struct sigaction Sigact_ign;
@ -829,7 +829,7 @@ hist_init(Source *s)
goto retry;
}
if (hs != hist_init_retry)
bi_errorf(Tf_cant,
bi_errorf(Tf_cant_ss_s,
"unlink HISTFILE", hname, cstrerror(errno));
histfsize = 0;
return;
@ -1033,8 +1033,8 @@ inittraps(void)
if (!strcmp(sigtraps[i].name, "EXIT") ||
!strcmp(sigtraps[i].name, "ERR")) {
#ifndef MKSH_SMALL
internal_warningf("ignoring invalid signal name %s",
sigtraps[i].name);
internal_warningf(Tinvname, sigtraps[i].name,
"signal");
#endif
sigtraps[i].name = null;
}

42
main.c
View File

@ -34,7 +34,7 @@
#include <locale.h>
#endif
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.330 2017/04/06 01:59:56 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/main.c,v 1.331 2017/04/08 01:07:17 tg Exp $");
extern char **environ;
@ -662,7 +662,7 @@ main(int argc, const char *argv[])
if (Flag(FAS_BUILTIN)) {
rv = c_builtin(l->argv);
} else {
shell(s, true);
shell(s, 0);
/* NOTREACHED */
}
}
@ -715,7 +715,7 @@ include(const char *name, int argc, const char **argv, bool intr_ok)
unwind(i);
/* NOTREACHED */
default:
internal_errorf("include %d", i);
internal_errorf(Tunexpected_type, Tunwind, Tsource, i);
/* NOTREACHED */
}
}
@ -726,7 +726,7 @@ include(const char *name, int argc, const char **argv, bool intr_ok)
s = pushs(SFILE, ATEMP);
s->u.shf = shf;
strdupx(s->file, name, ATEMP);
i = shell(s, false);
i = shell(s, 1);
quitenv(s->u.shf);
if (old_argv) {
e->loc->argv = old_argv;
@ -746,7 +746,7 @@ command(const char *comm, int line)
s = pushs(SSTRING, ATEMP);
s->start = s->str = comm;
s->line = line;
rv = shell(s, false);
rv = shell(s, 1);
source = sold;
return (rv);
}
@ -755,22 +755,33 @@ command(const char *comm, int line)
* run the commands from the input source, returning status.
*/
int
shell(Source * volatile s, volatile bool toplevel)
shell(Source * volatile s, volatile int level)
{
struct op *t;
volatile bool wastty = tobool(s->flags & SF_TTY);
volatile uint8_t attempts = 13;
volatile bool interactive = Flag(FTALKING) && toplevel;
volatile bool interactive = (level == 0) && Flag(FTALKING);
volatile bool sfirst = true;
Source *volatile old_source = source;
int i;
newenv(E_PARSE);
newenv(level == 2 ? E_EVAL : E_PARSE);
if (interactive)
really_exit = false;
switch ((i = kshsetjmp(e->jbuf))) {
case 0:
break;
case LBREAK:
case LCONTIN:
if (level != 2) {
source = old_source;
quitenv(NULL);
internal_errorf(Tf_cant_s, Tshell,
i == LBREAK ? Tbreak : Tcontinue);
/* NOTREACHED */
}
/* assert: interactive == false */
/* FALLTHROUGH */
case LINTR:
/* we get here if SIGINT not caught or ignored */
case LERROR:
@ -810,7 +821,7 @@ shell(Source * volatile s, volatile bool toplevel)
default:
source = old_source;
quitenv(NULL);
internal_errorf("shell %d", i);
internal_errorf(Tunexpected_type, Tunwind, Tshell, i);
/* NOTREACHED */
}
while (/* CONSTCOND */ 1) {
@ -848,7 +859,7 @@ shell(Source * volatile s, volatile bool toplevel)
* immediately after the last command
* executed.
*/
if (toplevel)
if (level == 0)
unwind(LEXIT);
break;
}
@ -911,6 +922,7 @@ unwind(int i)
case E_INCL:
case E_LOOP:
case E_ERRH:
case E_EVAL:
kshlongjmp(e->jbuf, i);
/* NOTREACHED */
case E_NONE:
@ -1380,19 +1392,19 @@ initio(void)
#ifdef DF
if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
if ((lfp = getenv("HOME")) == NULL || !mksh_abspath(lfp))
errorf("cannot get home directory");
errorf("can't get home directory");
lfp = shf_smprintf(Tf_sSs, lfp, "mksh-dbg.txt");
}
if ((shl_dbg_fd = open(lfp, O_WRONLY | O_APPEND | O_CREAT, 0600)) < 0)
errorf("cannot open debug output file %s", lfp);
errorf("can't open debug output file %s", lfp);
if (shl_dbg_fd < FDBASE) {
int nfd;
nfd = fcntl(shl_dbg_fd, F_DUPFD, FDBASE);
close(shl_dbg_fd);
if ((shl_dbg_fd = nfd) == -1)
errorf("cannot dup debug output file");
errorf("can't dup debug output file");
}
fcntl(shl_dbg_fd, F_SETFD, FD_CLOEXEC);
shf_fdopen(shl_dbg_fd, SHF_WR, shl_dbg);
@ -1408,7 +1420,7 @@ ksh_dup2(int ofd, int nfd, bool errok)
int rv;
if (((rv = dup2(ofd, nfd)) < 0) && !errok && (errno != EBADF))
errorf("too many files open in shell");
errorf(Ttoo_many_files);
#ifdef __ultrix
/*XXX imake style */
@ -1432,7 +1444,7 @@ savefd(int fd)
(errno == EBADF || errno == EPERM))
return (-1);
if (nfd < 0 || nfd > SHRT_MAX)
errorf("too many files open in shell");
errorf(Ttoo_many_files);
fcntl(nfd, F_SETFD, FD_CLOEXEC);
return ((short)nfd);
}

39
sh.h
View File

@ -175,9 +175,9 @@
#endif
#ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.806 2017/04/06 19:02:07 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.807 2017/04/08 01:07:18 tg Exp $");
#endif
#define MKSH_VERSION "R54 2017/04/05"
#define MKSH_VERSION "R54 2017/04/07"
/* arithmetic types: C implementation */
#if !HAVE_CAN_INTTYPES
@ -779,6 +779,7 @@ extern struct env {
#define E_LOOP 5 /* executing for/while # */
#define E_ERRH 6 /* general error handler # */
#define E_GONE 7 /* hidden in child */
#define E_EVAL 8 /* running eval # */
/* # indicates env has valid jbuf (see unwind()) */
/* struct env.flag values */
@ -880,6 +881,8 @@ EXTERN const char Tbad_bsize[] E_INIT("bad shf/buf/bsize");
#define Tbsize (Tbad_bsize + 12)
EXTERN const char Tbad_sig_ss[] E_INIT("%s: bad signal '%s'");
#define Tbad_sig_s (Tbad_sig_ss + 4)
EXTERN const char Tsgbreak[] E_INIT("*=break");
#define Tbreak (Tsgbreak + 2)
EXTERN const char T__builtin[] E_INIT("-\\builtin");
#define T_builtin (T__builtin + 1)
#define Tbuiltin (T__builtin + 2)
@ -893,6 +896,8 @@ EXTERN const char Tbcat[] E_INIT("!cat");
#define Tcd (Tcant_cd + 25)
#define T_command (T_funny_command + 9)
#define Tcommand (T_funny_command + 10)
EXTERN const char Tsgcontinue[] E_INIT("*=continue");
#define Tcontinue (Tsgcontinue + 2)
EXTERN const char Tcreate[] E_INIT("create");
EXTERN const char TELIF_unexpected[] E_INIT("TELIF unexpected");
EXTERN const char TEXECSHELL[] E_INIT("EXECSHELL");
@ -944,13 +949,17 @@ EXTERN const char Tsgset[] E_INIT("*=set");
#define Tset (Tf_parm + 18)
#define Tsh (Tmksh + 2)
#define TSHELL (TEXECSHELL + 4)
#define Tshell (Ttoo_many_files + 23)
EXTERN const char Tshf_read[] E_INIT("shf_read");
EXTERN const char Tshf_write[] E_INIT("shf_write");
EXTERN const char Tgsource[] E_INIT("=source");
#define Tsource (Tgsource + 1)
EXTERN const char Tj_suspend[] E_INIT("j_suspend");
#define Tsuspend (Tj_suspend + 2)
EXTERN const char Tsynerr[] E_INIT("syntax error");
EXTERN const char Ttime[] E_INIT("time");
EXTERN const char Ttoo_many_args[] E_INIT("too many arguments");
EXTERN const char Ttoo_many_files[] E_INIT("too many open files in shell");
EXTERN const char Ttrue[] E_INIT("true");
EXTERN const char Ttty_fd_dupof[] E_INIT("dup of tty fd");
#define Ttty_fd (Ttty_fd_dupof + 7)
@ -959,12 +968,14 @@ EXTERN const char Tdgtypeset[] E_INIT("^=typeset");
#define Tugo (Taugo + 1)
EXTERN const char Tunalias[] E_INIT("unalias");
#define Tunexpected (TELIF_unexpected + 6)
EXTERN const char Tunexpected_type[] E_INIT("%s: unexpected %s type %d");
EXTERN const char Tunknown_option[] E_INIT("unknown option");
EXTERN const char Tunwind[] E_INIT("unwind");
#define Tuser_sp1 (Tuser_sp2 + 1)
EXTERN const char Tuser_sp2[] E_INIT(" user ");
#define Twrite (Tshf_write + 4)
EXTERN const char Tf__S[] E_INIT(" %S");
#define Tf__d (Tf_sd + 2)
#define Tf__d (Tunexpected_type + 22)
EXTERN const char Tf__ss[] E_INIT(" %s%s");
#define Tf__sN (Tf_s_s_sN + 5)
EXTERN const char Tf_sSs[] E_INIT("%s/%s");
@ -974,13 +985,14 @@ EXTERN const char Tf_s_[] E_INIT("%s ");
EXTERN const char Tf_s_T[] E_INIT("%s %T");
EXTERN const char Tf_s_s_sN[] E_INIT("%s %s %s\n");
#define Tf_s_s (Tf_sD_s_s + 4)
#define Tf_s_sD_s (Tf_cant + 6)
#define Tf_s_sD_s (Tf_cant_ss_s + 6)
EXTERN const char Tf_optfoo[] E_INIT("%s%s-%c: %s");
EXTERN const char Tf_sD_[] E_INIT("%s: ");
EXTERN const char Tf_szs[] E_INIT("%s: %zd %s");
EXTERN const char Tf_parm[] E_INIT("%s: parameter not set");
EXTERN const char Tf_coproc[] E_INIT("-p: %s");
EXTERN const char Tf_cant[] E_INIT("can't %s %s: %s");
EXTERN const char Tf_cant_s[] E_INIT("%s: can't %s");
EXTERN const char Tf_cant_ss_s[] E_INIT("can't %s %s: %s");
EXTERN const char Tf_heredoc[] E_INIT("here document '%s' unclosed");
#if HAVE_MKNOD
EXTERN const char Tf_nonnum[] E_INIT("non-numeric %s %s '%s'");
@ -998,7 +1010,7 @@ EXTERN const char Tf_sd[] E_INIT("%s %d");
#define Tf_s (Tf_temp + 28)
EXTERN const char Tft_end[] E_INIT("%;");
EXTERN const char Tft_R[] E_INIT("%R");
#define Tf_d (Tf_sd + 3)
#define Tf_d (Tunexpected_type + 23)
EXTERN const char Tf_sD_s_qs[] E_INIT("%s: %s '%s'");
EXTERN const char Tf_ro[] E_INIT("read-only: %s");
EXTERN const char Tf_flags[] E_INIT("%s: flags 0x%X");
@ -1030,6 +1042,8 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tbsize "bsize"
#define Tbad_sig_ss "%s: bad signal '%s'"
#define Tbad_sig_s "bad signal '%s'"
#define Tsgbreak "*=break"
#define Tbreak "break"
#define T__builtin "-\\builtin"
#define T_builtin "\\builtin"
#define Tbuiltin "builtin"
@ -1043,6 +1057,8 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tcd "cd"
#define T_command "-command"
#define Tcommand "command"
#define Tsgcontinue "*=continue"
#define Tcontinue "continue"
#define Tcreate "create"
#define TELIF_unexpected "TELIF unexpected"
#define TEXECSHELL "EXECSHELL"
@ -1094,13 +1110,17 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tset "set"
#define Tsh "sh"
#define TSHELL "SHELL"
#define Tshell "shell"
#define Tshf_read "shf_read"
#define Tshf_write "shf_write"
#define Tgsource "=source"
#define Tsource "source"
#define Tj_suspend "j_suspend"
#define Tsuspend "suspend"
#define Tsynerr "syntax error"
#define Ttime "time"
#define Ttoo_many_args "too many arguments"
#define Ttoo_many_files "too many open files in shell"
#define Ttrue "true"
#define Ttty_fd_dupof "dup of tty fd"
#define Ttty_fd "tty fd"
@ -1109,7 +1129,9 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tugo "ugo"
#define Tunalias "unalias"
#define Tunexpected "unexpected"
#define Tunexpected_type "%s: unexpected %s type %d"
#define Tunknown_option "unknown option"
#define Tunwind "unwind"
#define Tuser_sp1 "user "
#define Tuser_sp2 " user "
#define Twrite "write"
@ -1130,7 +1152,8 @@ EXTERN const char T_devtty[] E_INIT("/dev/tty");
#define Tf_szs "%s: %zd %s"
#define Tf_parm "%s: parameter not set"
#define Tf_coproc "-p: %s"
#define Tf_cant "can't %s %s: %s"
#define Tf_cant_s "%s: can't %s"
#define Tf_cant_ss_s "can't %s %s: %s"
#define Tf_heredoc "here document '%s' unclosed"
#if HAVE_MKNOD
#define Tf_nonnum "non-numeric %s %s '%s'"
@ -2191,7 +2214,7 @@ int pprompt(const char *, int);
/* main.c */
int include(const char *, int, const char **, bool);
int command(const char *, int);
int shell(Source * volatile, volatile bool);
int shell(Source * volatile, volatile int);
/* argument MUST NOT be 0 */
void unwind(int) MKSH_A_NORETURN;
void newenv(int);