From cc5668cc785352066cef15803759f2ef84a456d6 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sun, 22 Dec 2024 20:49:00 +0000 Subject: [PATCH] emacs: Fix ESC [ macros In the friendly manual page, we find the following under "Emacs Editing Mode" (note that M- stands for the historic 'meta' modifier key but actually means ESC on all current systems): M-[letter Soft-key - Your alias list is searched for an alias by the name __letter and if an alias of this name is defined, its value will be inserted on the input queue. This can be used to program function keys on many terminals. The bug: unlike the M-letter variant, the above simply does not work. For example, if an alias __x is defined, ESC [ x just beeps. Analysis: In this case, ed_macro() in completion.c is called from escape() in emacs.c with i set to '_' (emacs.c lines 1179, 1184). The ed_macro() code in completion.c makes the bug clear: 604: /* undocumented feature, macros of the form [c evoke alias __c */ 605: if(i=='_') 606: ep->e_macro[2] = ed_getchar(ep,1); 607: else 608: ep->e_macro[2] = 0; 609: if (isalnum(i)&&(np=nv_search(ep->e_macro,sh.alias_tree,0)) &&(out=nv_getval(np))) //...handle the macro The bug is on line 606. If i is '_' (so we have 'ESC [' in emacs), it gets another character, but it does not update i, so that isalnum(i) on line 609 checks if a constant value '_' is alphanumeric, which is always false. The fix is obvious: on line 606, set i to the value returned by ed_getchar(). Tracing this bug in historic source code, I determined it was there as early as ksh88, when this code was introduced! Yet, at some point, someone seems to have thought it was a good idea to document this in the manual page (while forgetting to edit the comment that says the feature is undocumented). So either they used a fixed version but the fix was never committed to AT&T's version control system, or they documented it without ever trying it. The closed-source ksh88 that shipped with Solaris 10 (2005), as /usr/bin/ksh and /usr/xpg4/bin/sh, has this feature working. So it did get fixed somewhere at some point, but the fix never made it into any publicly available source code -- until now. --- NEWS | 6 ++++++ src/cmd/ksh93/edit/completion.c | 4 ++-- src/cmd/ksh93/include/version.h | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 2a61ac91ab9c..47f64e55e9c6 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,12 @@ This documents significant changes in the dev branch of ksh 93u+m. For full details, see the git log at: https://github.com/ksh93/ksh Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. +2024-12-22: + +- In the emacs/gmacs line editor, the ESC [ macro feature, which is + documented to input the value of the alias __, now actually works. + A decades-old bug in internal variable handling rendered it inoperative. + 2024-12-21: - Fixed a bug in the emacs/gmacs line editor where a command repeat count diff --git a/src/cmd/ksh93/edit/completion.c b/src/cmd/ksh93/edit/completion.c index 487278b39e15..e1c57cc91aea 100644 --- a/src/cmd/ksh93/edit/completion.c +++ b/src/cmd/ksh93/edit/completion.c @@ -601,9 +601,9 @@ int ed_macro(Edit_t *ep, int i) genchar buff[LOOKAHEAD+1]; if(i != '@') ep->e_macro[1] = i; - /* undocumented feature, macros of the form [c evoke alias __c */ + /* macros of the form [c evoke alias __c */ if(i=='_') - ep->e_macro[2] = ed_getchar(ep,1); + ep->e_macro[2] = i = ed_getchar(ep,1); else ep->e_macro[2] = 0; if (isalnum(i)&&(np=nv_search(ep->e_macro,sh.alias_tree,0))&&(out=nv_getval(np))) diff --git a/src/cmd/ksh93/include/version.h b/src/cmd/ksh93/include/version.h index 5297065544f1..9ab358a64860 100644 --- a/src/cmd/ksh93/include/version.h +++ b/src/cmd/ksh93/include/version.h @@ -18,7 +18,7 @@ #include #include "git.h" -#define SH_RELEASE_DATE "2024-12-21" /* must be in this format for $((.sh.version)) */ +#define SH_RELEASE_DATE "2024-12-22" /* must be in this format for $((.sh.version)) */ /* * This comment keeps SH_RELEASE_DATE a few lines away from SH_RELEASE_SVER to avoid * merge conflicts when cherry-picking dev branch commits onto a release branch.