From fae945962be300f21310b404faf5e47c65e28341 Mon Sep 17 00:00:00 2001 From: tg Date: Sat, 8 Apr 2017 01:07:18 +0000 Subject: [PATCH] allow 'eval break', from Martijn Dekker also, more string pooling, while here --- check.t | 20 +++++++++++++++----- exec.c | 6 +++--- funcs.c | 16 ++++++++-------- histrap.c | 8 ++++---- main.c | 42 +++++++++++++++++++++++++++--------------- sh.h | 39 +++++++++++++++++++++++++++++++-------- 6 files changed, 88 insertions(+), 43 deletions(-) diff --git a/check.t b/check.t index 81c1db3..32ecc90 100644 --- a/check.t +++ b/check.t @@ -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: diff --git a/exec.c b/exec.c index 89726a9..d67c4a0 100644 --- a/exec.c +++ b/exec.c @@ -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)); diff --git a/funcs.c b/funcs.c index afdcbf5..ed521db 100644 --- a/funcs.c +++ b/funcs.c @@ -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); } /* diff --git a/histrap.c b/histrap.c index 56723ff..26dd521 100644 --- a/histrap.c +++ b/histrap.c @@ -27,7 +27,7 @@ #include #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; } diff --git a/main.c b/main.c index cc2e02b..976a21d 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ #include #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); } diff --git a/sh.h b/sh.h index 40f5d0d..ff592b3 100644 --- a/sh.h +++ b/sh.h @@ -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);