Turns out matthieu@ already made an updated diff some time ago. Here it is.
-Otto Index: emacs.c =================================================================== RCS file: /cvs/OpenBSD/src/bin/ksh/emacs.c,v retrieving revision 1.40 diff -u -r1.40 emacs.c --- emacs.c 10 Jul 2006 17:12:41 -0000 1.40 +++ emacs.c 4 Oct 2006 21:47:44 -0000 @@ -107,6 +107,7 @@ static char *macroptr; static int prompt_skip; static int prompt_redraw; +static char x_search_hist_pattern[256+1]; static int x_ins(char *); static void x_delete(int, int); @@ -120,6 +121,8 @@ static void x_zotc(int); static void x_load_hist(char **); static int x_search(char *, int, int); +static int x_search_delta(char *, int, int, int); +static int x_search_delta_distinct(char *, int, int, int); static int x_match(char *, char *); static void x_redraw(int); static void x_push(int); @@ -191,6 +194,8 @@ { x_search_char_forw, "search-character-forward", XF_ARG }, { x_search_char_back, "search-character-backward", XF_ARG }, { x_search_hist, "search-history", 0 }, + { x_search_hist_backward, "history-search-backward", 0 }, + { x_search_hist_forward, "history-search-forward", 0 }, { x_set_mark, "set-mark-command", 0 }, { x_stuff, "stuff", 0 }, { x_stuffreset, "stuff-reset", 0 }, @@ -277,6 +282,8 @@ #endif { XFUNC_prev_histword, 1, '.' }, { XFUNC_prev_histword, 1, '_' }, + { XFUNC_search_hist_backward, 1, 'p' }, + { XFUNC_search_hist_forward, 1, 'n' }, { XFUNC_set_arg, 1, '0' }, { XFUNC_set_arg, 1, '1' }, { XFUNC_set_arg, 1, '2' }, @@ -870,9 +877,7 @@ if ((c = x_e_getc()) < 0) return KSTD; f = x_tab[0][c&CHARMASK]; - if (c == CTRL('[')) - break; - else if (f == XFUNC_search_hist) + if (f == XFUNC_search_hist) offset = x_search(pat, 0, offset); else if (f == XFUNC_del_back) { if (p == pat) { @@ -914,14 +919,90 @@ return KSTD; } -/* search backward from current line */ +/* determine if prefix history searching should be performed, or plain + * up/down history traversing */ static int -x_search(char *pat, int sameline, int offset) +x_search_hist_has_prefix(void) +{ + size_t pat_len; + + /* skip prefix history search if at beginning of line */ + if (xcp == xbuf) + return 0; + + /* prepare the prefix search pattern */ + pat_len = xcp - xbuf; + x_search_hist_pattern[0] = '^'; + if (pat_len > 256) + pat_len = 256; + strlcpy(x_search_hist_pattern + 1, xbuf, pat_len + 1); + return 1; +} + +/* a modal version of (up|down)-history, necessary in order not to + * confuse with prefix history searches */ +static void +x_search_hist_modal(int delta) +{ + int c; + u_char f; + + x_load_hist(x_histp + delta); + + while(1) { + x_flush(); + if ((c = x_e_getc()) < 0) + break; + f = x_tab[x_curprefix][c&CHARMASK]; + if (f == XFUNC_search_hist_backward) { + x_load_hist(x_histp - 1); + x_curprefix = 0; + } else if (f == XFUNC_search_hist_forward) { + x_load_hist(x_histp + 1); + x_curprefix = 0; + } else if (f == XFUNC_meta1) + x_meta1(0); + else if (f == XFUNC_meta2) + x_meta2(0); + else { + x_e_ungetc(c); + break; + } + } +} + +/* search history backwards for line with same prefix */ +static int +x_search_hist_backward(int c) +{ + if (x_search_hist_has_prefix()) + x_search_delta_distinct(x_search_hist_pattern, 0, 0, -1); + else + x_search_hist_modal(-1); + return KSTD; +} + +/* search history forwards for line with same prefix */ +static int +x_search_hist_forward(int c) +{ + if (x_search_hist_has_prefix()) + x_search_delta_distinct(x_search_hist_pattern, 0, 0, +1); + else + x_search_hist_modal(+1); + return KSTD; +} + +/* search backward or forward from current line depending on delta */ +static int +x_search_delta(char *pat, int sameline, int offset, int delta) { char **hp; int i; - for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) { + for (hp = x_histp + (sameline ? 0 : delta) ; + hp >= history && hp <= histptr ; + hp += delta) { i = x_match(*hp, pat); if (i >= 0) { if (offset < 0) @@ -934,6 +1015,31 @@ x_e_putc(BEL); x_histp = histptr; return -1; +} + +/* just as x_search_delta, but skips duplicate matches */ +static int +x_search_delta_distinct(char *pat, int sameline, int offset, int delta) +{ + char *orig_xbuf; + int rc; + + orig_xbuf = strdup(xbuf); + + while(1) { + rc = x_search_delta(pat, sameline, offset, delta); + if(rc < 0 || strcmp(orig_xbuf, *x_histp) != 0) + break; + } + free(orig_xbuf); + return rc; +} + +/* search backward from current line */ +static int +x_search(char *pat, int sameline, int offset) +{ + return x_search_delta(pat, sameline, offset, -1); } /* return position of first match of pattern in string, else -1 */ Index: ksh.1 =================================================================== RCS file: /cvs/OpenBSD/src/bin/ksh/ksh.1,v retrieving revision 1.117 diff -u -r1.117 ksh.1 --- ksh.1 3 Aug 2006 11:22:05 -0000 1.117 +++ ksh.1 4 Oct 2006 21:35:22 -0000 @@ -4839,6 +4839,14 @@ .Xc Goes to history number .Ar n . +.It history-search-backward: +Search the internal history list backwards for a line beginning with the +current content of the input buffer up to the cursor. Duplicate matches +are skipped. +.It history-search-forward: +Search the internal history list forwards for a line beginning with the +current content of the input buffer up to the cursor. Duplicate matches +are skipped. .It kill-line: KILL Deletes the entire input line. .It kill-region: ^W