ksh offers csh-style history aliases when you set csh-history. This
feature currently works. However, when an alias doesn't exist ksh
reports only the last digit (thanks to Theo for tipping me off on this):
> mike:/tmp/tech:1$ set -o csh-history
> mike:/tmp/tech:2$ ls
> a b c
> mike:/tmp/tech:3$ !2
> a b c
> mike:/tmp/tech:4$ !3456789
> ksh: !9: not found
The below diff fixes this. Basically, this feature is implemented in the
lexer, and ksh doesn't rewind through the whole alias after realizing
that it doesn't exist.
I don't entirely understand the lexer, so I did this super defensively.
If anyone knows of a smarter way, please share.
I moved the var declarations farther out because they're now needed in
the outer scope.
Index: lex.c
===================================================================
RCS file: /cvs/src/bin/ksh/lex.c,v
retrieving revision 1.51
diff -u -p -r1.51 lex.c
--- lex.c 10 Sep 2015 22:48:58 -0000 1.51
+++ lex.c 13 Sep 2015 20:44:30 -0000
@@ -163,6 +163,9 @@ yylex(int cf)
if (Flag(FCSHHISTORY) && (source->flags & SF_TTY) &&
c == '!') {
char **replace = NULL;
+ int get, i;
+ char match[200], *str = match;
+ size_t mlen;
c2 = getsc();
if (c2 == '\0' || c2 == ' ' || c2 == '\t')
@@ -171,8 +174,7 @@ yylex(int cf)
replace = hist_get_newest(0);
else if (isdigit(c2) || c2 == '-' ||
isalpha(c2)) {
- int get = !isalpha(c2);
- char match[200], *str = match;
+ get = !isalpha(c2);
*str++ = c2;
do {
@@ -216,8 +218,20 @@ yylex(int cf)
s->u.freeme = NULL;
source = s;
continue;
- } else
- ungetsc(c2);
+ } else {
+ /*
+ * We do this the robust, safe, stupid
way. We
+ * should just be able to use:
+ *
+ * source->str = MAX(source->start,
+ * source->str - (strlen(match)-1));
+ */
+ mlen = strlen(match);
+ if (source->start <= (source->str -
mlen)) {
+ for (i = mlen-1; i >= 0; i--)
+ ungetsc(match[i]);
+ }
+ }
}
if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
*wp = EOS; /* temporary */