ledit

Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 53f769b1d999f6964bc2431b316cf07a3b8166ec
parent feafabfe8d714cc8d08d0000a91a7a6e8baf8492
Author: lumidify <nobody@lumidify.org>
Date:   Thu,  7 Jul 2022 13:14:00 +0200

Check for XBufferOverflow when handling keys; misc fixes

Diffstat:
Mkeys.c | 49++++++++++++++++++++++++++++++++++++++++++-------
Mkeys.h | 5+++--
Mkeys_basic.c | 6+++---
Mkeys_command.c | 8+++++---
Mledit.c | 2+-
Mleditrc.5 | 4++--
Mleditrc.example | 4++--
7 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/keys.c b/keys.c @@ -19,16 +19,31 @@ /* LockMask and Mod2Mask in particular are disabled (caps lock and numlock usually) */ static unsigned int importantmod = ShiftMask | ControlMask | Mod1Mask | Mod3Mask | Mod4Mask | Mod5Mask; +#define KEY_TEXT_INITIAL_SIZE 32 +static char *key_text = NULL; +static size_t key_text_alloc = 0; + +void +key_processing_cleanup(void) { + free(key_text); +} + int match_key(unsigned int mask, unsigned int state) { return mask == XK_ANY_MOD || mask == (state & importantmod); } +#ifdef X_HAVE_UTF8_STRING +#define LOOKUP_STRING_FUNC Xutf8LookupString +#else +#define LOOKUP_STRING_FUNC XmbLookupString +#endif + void preprocess_key( - ledit_window *window, XEvent *event, KeySym *sym_ret, - char *buf_ret, int buf_size, int *buf_len_ret) { + ledit_window *window, XKeyEvent *event, KeySym *sym_ret, + char **buf_ret, int *buf_len_ret) { /* * FIXME: I don't understand how key handling works with different keymaps. * If, for instance, you run "setxkbmap pk" and then type "Ctrl+c", the @@ -52,9 +67,29 @@ preprocess_key( * keys don't use control in normal mode, and it just messes with all the * keys that do use control because ledit does its own mapping. */ - event->xkey.state &= ~ControlMask; - /* FIXME: X_HAVE_UTF8_STRING See XmbLookupString(3) */ - *buf_len_ret = Xutf8LookupString( - window->xic, &event->xkey, buf_ret, buf_size, sym_ret, NULL - ); + if (key_text_alloc == 0) { + key_text = ledit_malloc(KEY_TEXT_INITIAL_SIZE); + key_text_alloc = KEY_TEXT_INITIAL_SIZE; + } + event->state &= ~ControlMask; + + int len = 0; + Status status; + if (window->xic && event->type == KeyPress) { + len = LOOKUP_STRING_FUNC(window->xic, event, key_text, key_text_alloc - 1, sym_ret, &status); + if (status == XBufferOverflow) { + key_text_alloc = ideal_array_size(key_text_alloc, len + 1); + key_text = ledit_realloc(key_text, key_text_alloc); + len = LOOKUP_STRING_FUNC(window->xic, event, key_text, key_text_alloc - 1, sym_ret, &status); + } + } else { + /* FIXME: anything equivalent to XBufferOverflow here? */ + len = XLookupString(event, key_text, key_text_alloc - 1, sym_ret, NULL); + status = XLookupBoth; + } + *buf_len_ret = len >= (int)key_text_alloc ? (int)key_text_alloc - 1 : len; + key_text[*buf_len_ret] = '\0'; + if (status != XLookupBoth && status != XLookupKeySym) + *sym_ret = NoSymbol; + *buf_ret = key_text; } diff --git a/keys.h b/keys.h @@ -15,9 +15,10 @@ int get_language_index(char *lang); int match_key(unsigned int mask, unsigned int state); /* preprocess key, i.e. get the KeySym and text corresponding to it */ void preprocess_key( - ledit_window *window, XEvent *event, KeySym *sym_ret, - char *buf_ret, int buf_size, int *buf_len_ret + ledit_window *window, XKeyEvent *event, KeySym *sym_ret, + char **buf_ret, int *buf_len_ret ); +void key_processing_cleanup(void); /* FIXME: documentation */ #define GEN_CB_MAP_HELPERS(name, typename, cmp_entry) \ diff --git a/keys_basic.c b/keys_basic.c @@ -2622,12 +2622,12 @@ repeat_command(ledit_view *view, char *text, size_t len) { struct action basic_key_handler(ledit_view *view, XEvent *event, int lang_index) { - char buf[64]; - KeySym sym; + char *buf = NULL; + KeySym sym = NoSymbol; int n; unsigned int key_state = event->xkey.state; - preprocess_key(view->window, event, &sym, buf, sizeof(buf), &n); + preprocess_key(view->window, &event->xkey, &sym, &buf, &n); struct repetition_stack_elem *re = push_repetition_stack(); re->key_text = ledit_strndup(buf, (size_t)n); diff --git a/keys_command.c b/keys_command.c @@ -214,6 +214,8 @@ static int parse_range( ); static int handle_cmd(ledit_view *view, char *cmd, size_t len, size_t lang_index); +/* FIXME: USE LEN EVERYWHERE INSTEAD OF RELYING ON cmd BEING NUL-TERMINATED */ +/* FIXME: return error so write_quit knows when to quit */ static int handle_write(ledit_view *view, char *cmd, size_t l1, size_t l2) { (void)l1; @@ -946,13 +948,13 @@ edit_discard(ledit_view *view, char *key_text, size_t len, size_t lang_index) { struct action command_key_handler(ledit_view *view, XEvent *event, int lang_index) { - char buf[64]; - KeySym sym; + char *buf = NULL; + KeySym sym = NoSymbol; int n; command_key_array *cur_keys = config_get_command_keys(lang_index); size_t num_keys = cur_keys->num_keys; unsigned int key_state = event->xkey.state; - preprocess_key(view->window, event, &sym, buf, sizeof(buf), &n); + preprocess_key(view->window, &event->xkey, &sym, &buf, &n); int grabkey = 1, found = 0; command_key_cb_flags flags = KEY_FLAG_NONE; for (size_t i = 0; i < num_keys; i++) { diff --git a/ledit.c b/ledit.c @@ -114,7 +114,6 @@ mainloop(void) { change_kbd = 1; continue; } - /* FIXME: why None? */ if (XFilterEvent(&event, None)) continue; ledit_view *view = NULL; @@ -450,6 +449,7 @@ ledit_cleanup(void) { search_cleanup(); basic_key_cleanup(); command_key_cleanup(); + key_processing_cleanup(); if (buffer) buffer_destroy(buffer); config_cleanup(&common); diff --git a/leditrc.5 b/leditrc.5 @@ -619,12 +619,12 @@ Note that this command works with soft lines, regardless of the current mode. .It Ar scroll-with-cursor-down Oo normal, insert Oc Oo num Oc Move .Ar num -lines down, attemting to leave the cursor in its current line and character position. +lines down, attempting to leave the cursor in its current line and character position. Note that this command works with soft lines, regardless of the current mode. .It Ar scroll-with-cursor-up Oo normal, insert Oc Oo num Oc Move .Ar num -lines up, attemting to leave the cursor in its current line and character position. +lines up, attempting to leave the cursor in its current line and character position. Note that this command works with soft lines, regardless of the current mode. .It Ar search-next Op normal, insert Move to the next search result. diff --git a/leditrc.example b/leditrc.example @@ -221,7 +221,7 @@ language-mapping = { map "^" "^" } command-mapping = { - map "वग" "wq" + map "व‌" "wq" map "व" "w" map "‌" "q" map "ड" "v" @@ -293,7 +293,7 @@ language-mapping = { map "^" "^" } command-mapping = { - map "وگ" "wq" + map "وق" "wq" map "و" "w" map "ق" "q" map "ط" "v"