implement an extension that an interactive mode input line, when

starting with an ‘!’ exclamation mark at the beginning of a com-
mand (PS1 not PS2), shall have the same effect as the predefined
“r” alias, to be compatible with csh and GNU bash’s “!string” to
«Execute last used command starting with string» – documentation
and feature request provided by wbx@ (Waldemar Brodkorb)
This commit is contained in:
tg 2009-05-27 19:52:38 +00:00
parent b90007d784
commit da5dc48cd0
5 changed files with 141 additions and 10 deletions

109
check.t
View File

@ -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
---

24
lex.c
View File

@ -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 */

4
main.c
View File

@ -33,7 +33,7 @@
#include <locale.h>
#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,

9
mksh.1
View File

@ -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.

5
sh.h
View File

@ -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 */