diff --git a/check.t b/check.t index dcafafb..3b018d6 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.280 2009/05/27 09:58:21 tg Stab $ +# $MirOS: src/bin/mksh/check.t,v 1.281 2009/05/27 19:52:35 tg Stab $ # $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: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -5722,3 +5722,110 @@ expected-stdout: 11 0 12 0 --- +name: event-subst-1a +description: + Check that '!' substitution in interactive mode works +file-setup: file 755 "falsetto" + echo molto bene + exit 42 +file-setup: file 755 "!false" + echo si +arguments: !-i! +stdin: + export PATH=.:$PATH + falsetto + echo yeap + !false +expected-exit: 42 +expected-stdout: + molto bene + yeap + molto bene +expected-stderr-pattern: + /.*/ +--- +name: event-subst-1b +description: + Check that '!' substitution in interactive mode works + even when a space separates it from the search command, + which is not what GNU bash provides but required for the + other regression tests below to check +file-setup: file 755 "falsetto" + echo molto bene + exit 42 +file-setup: file 755 "!" + echo si +arguments: !-i! +stdin: + export PATH=.:$PATH + falsetto + echo yeap + ! false +expected-exit: 42 +expected-stdout: + molto bene + yeap + molto bene +expected-stderr-pattern: + /.*/ +--- +name: event-subst-2 +description: + Check that '!' substitution in interactive mode + does not break things +file-setup: file 755 "falsetto" + echo molto bene + exit 42 +file-setup: file 755 "!" + echo si +arguments: !-i! +env-setup: !ENV=./Env! +file-setup: file 644 "Env" + PS1=X +stdin: + export PATH=.:$PATH + falsetto + echo yeap + !false + echo meow + ! false + echo = $? + if + ! false; then echo foo; else echo bar; fi +expected-stdout: + molto bene + yeap + molto bene + meow + molto bene + = 42 + foo +expected-stderr-pattern: + /.*/ +--- +name: event-subst-3 +description: + Check that '!' substitution in noninteractive mode is ignored +file-setup: file 755 "falsetto" + echo molto bene + exit 42 +file-setup: file 755 "!false" + echo si +stdin: + export PATH=.:$PATH + falsetto + echo yeap + !false + echo meow + ! false + echo = $? + if + ! false; then echo foo; else echo bar; fi +expected-stdout: + molto bene + yeap + si + meow + = 0 + foo +--- diff --git a/lex.c b/lex.c index 74d26a3..299e4c8 100644 --- a/lex.c +++ b/lex.c @@ -22,7 +22,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.84 2009/05/27 09:58:22 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.85 2009/05/27 19:52:36 tg Exp $"); /* * states while lexing word @@ -1189,7 +1189,7 @@ getsc__(void) static void getsc_line(Source *s) { - char *xp = Xstring(s->xs, xp); + char *xp = Xstring(s->xs, xp), *cp; int interactive = Flag(FTALKING) && s->type == SSTDIN; int have_tty = interactive && (s->flags & SF_TTY); @@ -1254,7 +1254,25 @@ getsc_line(Source *s) ksh_tmout_state = TMOUT_EXECUTING; alarm(0); } - s->start = s->str = Xstring(s->xs, xp); + cp = Xstring(s->xs, xp); + if (interactive && *cp == '!' && cur_prompt == PS1) { + int linelen; + + linelen = Xlength(s->xs, xp); + XcheckN(s->xs, xp, fc_e_n + /* NUL */ 1); + /* reload after potential realloc */ + cp = Xstring(s->xs, xp); + /* change initial '!' into space */ + *cp = ' '; + /* NUL terminate the current string */ + *xp = '\0'; + /* move the actual string forward */ + memmove(cp + fc_e_n, cp, linelen + /* NUL */ 1); + xp += fc_e_n; + /* prepend it with "fc -e -" */ + memcpy(cp, fc_e_, fc_e_n); + } + s->start = s->str = cp; strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp)); /* Note: if input is all nulls, this is not eof */ if (Xlength(s->xs, xp) == 0) { /* EOF */ diff --git a/main.c b/main.c index 6a7c5f7..661c500 100644 --- a/main.c +++ b/main.c @@ -33,7 +33,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/main.c,v 1.128 2009/05/16 21:00:51 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/main.c,v 1.129 2009/05/27 19:52:37 tg Exp $"); extern char **environ; @@ -69,7 +69,7 @@ static const char *initcoms[] = { "functions=typeset -f", "history=fc -l", "nohup=nohup ", - "r=fc -e -", + r_fc_e_, "source=PATH=$PATH:. command .", "login=exec login", NULL, diff --git a/mksh.1 b/mksh.1 index cc2e101..3fbb6dd 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,4 +1,4 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.167 2009/05/21 14:28:34 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.168 2009/05/27 19:52:37 tg Exp $ .\" $OpenBSD: ksh.1,v 1.128 2009/03/06 12:28:36 jmc Exp $ .\"- .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 @@ -48,7 +48,7 @@ .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .. .\"- -.Dd $Mdocdate: May 21 2009 $ +.Dd $Mdocdate: May 27 2009 $ .Dt MKSH 1 .Os MirBSD .Sh NAME @@ -2982,7 +2982,10 @@ and .Fl s is identical: re-execute the selected command without invoking an editor. This command is usually accessed with the predefined -.Ic alias r=\*(aqfc \-e \-\*(aq . +.Ic alias r=\*(aqfc \-e \-\*(aq +or by prefixing an interactive mode input line with +.Sq \&! +.Pq wbx extension . .Pp .It Ic fg Op Ar job ... Resume the specified job(s) in the foreground. diff --git a/sh.h b/sh.h index 5679196..d6629f2 100644 --- a/sh.h +++ b/sh.h @@ -122,7 +122,7 @@ #define __SCCSID(x) __IDSTRING(sccsid,x) #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.303 2009/05/27 09:58:23 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.304 2009/05/27 19:52:38 tg Exp $"); #endif #define MKSH_VERSION "R38 2009/05/27" @@ -576,6 +576,9 @@ EXTERN char shell_flags[FNFLAGS]; EXTERN char null[] I__(""); /* helpers for string pooling */ #define T_synerr "syntax error" +EXTERN const char r_fc_e_[] I__("r=fc -e -"); +#define fc_e_ (r_fc_e_ + 2) /* "fc -e -" */ +#define fc_e_n 7 /* strlen(fc_e_) */ enum temp_type { TT_HEREDOC_EXP, /* expanded heredoc */