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

Reply via email to