config: parse_keystroke() rewrites the string only if requested.

Only the keybinding manager UI requests a rewrite, in order to display
the canonical form in the "Keystroke already used" dialog.  The config
file parser and scripting interfaces do not request a rewrite.  This
fixes a bug: in the previous version, l_bind_key() modified the buffer
whose address lua_tostring() returned, even though that is not allowed
according to Lua documentation <http://www.lua.org/pil/24.2.2.html>.

If parse_keystroke() does rewrite the string, it now also rearranges
modifiers to the canonical order.

---
commit 6fa484dfb0d9310079e8bd01f8b7c70b19df0aa6
tree d1efd386387df486cf47ffdfb1f57631d617c065
parent fc23a55d905403a7d0d5114f2ee2e181ed306ad3
author Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sat, 29 Jul 2006 22:24:48 +0300
committer Kalle Olavi Niemitalo <[EMAIL PROTECTED]> Sat, 29 Jul 2006 22:24:48 +0300

 src/config/dialogs.c            |    2 +
 src/config/kbdbind.c            |   63 ++++++++++++++++++++++++++++++---------
 src/config/kbdbind.h            |   12 ++++---
 src/scripting/lua/core.c        |    2 +
 src/scripting/smjs/keybinding.c |    4 +-
 5 files changed, 59 insertions(+), 24 deletions(-)

diff --git a/src/config/dialogs.c b/src/config/dialogs.c
index b658a14..1e51797 100644
--- a/src/config/dialogs.c
+++ b/src/config/dialogs.c
@@ -848,7 +848,7 @@ check_keystroke(struct dialog_data *dlg_
 	struct kbdbind_add_hop *hop = dlg_data->dlg->udata2;
 	unsigned char *keystroke = widget_data->cdata;
 
-	if (parse_keystroke(keystroke, &hop->kbd) >= 0)
+	if (parse_keystroke(keystroke, 1, &hop->kbd) >= 0)
 		return EVENT_PROCESSED;
 
 	info_box(hop->term, 0, N_("Add keybinding"), ALIGN_CENTER,
diff --git a/src/config/kbdbind.c b/src/config/kbdbind.c
index a90a3d7..0e3996e 100644
--- a/src/config/kbdbind.c
+++ b/src/config/kbdbind.c
@@ -206,11 +206,12 @@ kbd_nm_lookup(enum keymap_id keymap_id, 
 }
 
 static struct keybinding *
-kbd_stroke_lookup(enum keymap_id keymap_id, unsigned char *keystroke_str)
+kbd_stroke_lookup(enum keymap_id keymap_id, const unsigned char *keystroke_str)
 {
 	struct term_event_keyboard kbd;
 
-	if (parse_keystroke(keystroke_str, &kbd) < 0)
+	/* Casting const away is safe because the second argument is 0.  */
+	if (parse_keystroke((unsigned char *) keystroke_str, 0, &kbd) < 0)
 		return NULL;
 
 	return kbd_ev_lookup(keymap_id, &kbd, NULL);
@@ -230,7 +231,7 @@ static struct keymap keymap_table[] = {
 
 static struct action *
 get_action_from_keystroke(enum keymap_id keymap_id,
-                          unsigned char *keystroke_str)
+                          const unsigned char *keystroke_str)
 {
 	struct keybinding *keybinding = kbd_stroke_lookup(keymap_id,
 	                                                  keystroke_str);
@@ -240,7 +241,7 @@ get_action_from_keystroke(enum keymap_id
 
 unsigned char *
 get_action_name_from_keystroke(enum keymap_id keymap_id,
-                               unsigned char *keystroke_str)
+                               const unsigned char *keystroke_str)
 {
 	struct action *action = get_action_from_keystroke(keymap_id,
 	                                                  keystroke_str);
@@ -372,7 +373,7 @@ read_key(unsigned char *key_str)
 struct modifier {
 	const unsigned char *name_and_dash;
 	size_t name_len;	/* does not include the dash */
-	int bitmask;
+	int bitmask;		/* must not overlap */
 };
 static const struct modifier modifiers[] = {
 	{ "Shift-", 5, KBD_MOD_SHIFT },
@@ -381,28 +382,59 @@ static const struct modifier modifiers[]
 	{ NULL }
 };
 
+/* Parse the string @s as the name of a keystroke.
+ * Write the parsed key and modifiers to [EMAIL PROTECTED]
+ * Return >=0 on success, <0 on error.
+ * If @canonicalize is true, write the keystroke name back to @s in
+ * the canonical form (e.g. "Ctrl-Alt-X" instead of "alt+ctrl+x"),
+ * even if the key is unrecognized.  This rewrite never makes the
+ * string longer than it was.
+ * If @canonicalize is false, @s may point to const.  */
 int
-parse_keystroke(unsigned char *s, struct term_event_keyboard *kbd)
+parse_keystroke(unsigned char *s, int canonicalize, struct term_event_keyboard *kbd)
 {
 	const struct modifier *modp;
+	unsigned char *rewrite = s;
+	unsigned char ctrlbuf[2];
 
 	kbd->modifier = KBD_MOD_NONE;
  more_modifiers:
 	for (modp = modifiers; modp->name_and_dash != NULL; ++modp) {
+		/* Reject Alt-Alt-a because allowing it would
+		 * complicate canonicalization.  */
 		if ((kbd->modifier & modp->bitmask) == 0
 		    && !strncasecmp(s, modp->name_and_dash, modp->name_len)
 		    && (s[modp->name_len] == '-' || s[modp->name_len] == '+')) {
 			/* Shift+a == shiFt-a == Shift-a */
-			memcpy(s, modp->name_and_dash, modp->name_len + 1);
 			kbd->modifier |= modp->bitmask;
 			s += modp->name_len + 1;
 			goto more_modifiers;
 		}
 	}
 
+	if (canonicalize) {
+		/* Write the modifiers back to the string, now in the
+		 * canonical order.  They will fit because the lengths
+		 * don't change.  */
+		for (modp = modifiers; modp->name_and_dash != NULL; ++modp) {
+			if ((kbd->modifier & modp->bitmask) != 0) {
+				memcpy(rewrite, modp->name_and_dash, modp->name_len + 1);
+				rewrite += modp->name_len + 1;
+			}
+		}
+		assert(rewrite == s);
+		if_assert_failed return -1;
+	}
+
 	/* Ctrl-a == Ctrl-A */
-	if ((kbd->modifier & KBD_MOD_CTRL) != 0 && s[0] && !s[1])
+	if ((kbd->modifier & KBD_MOD_CTRL) != 0 && s[0] && !s[1]) {
+		if (!canonicalize) {
+			ctrlbuf[0] = s[0];
+			ctrlbuf[1] = '\0';
+			s = ctrlbuf;
+		}
 		s[0] = toupper(s[0]);
+	}
 
 	kbd->key = read_key(s);
 	return (kbd->key < 0) ? -1 : 0;
@@ -552,7 +584,7 @@ free_keymaps(struct module *xxx)
 
 #ifdef CONFIG_SCRIPTING
 static unsigned char *
-bind_key_to_event(unsigned char *ckmap, unsigned char *ckey, int event)
+bind_key_to_event(unsigned char *ckmap, const unsigned char *ckey, int event)
 {
 	struct term_event_keyboard kbd;
 	action_id_T action_id;
@@ -561,7 +593,8 @@ bind_key_to_event(unsigned char *ckmap, 
 	if (keymap_id < 0)
 		return gettext("Unrecognised keymap");
 
-	if (parse_keystroke(ckey, &kbd) < 0)
+	/* Casting const away is safe because the second argument is 0.  */
+	if (parse_keystroke((unsigned char *) ckey, 0, &kbd) < 0)
 		return gettext("Error parsing keystroke");
 
 	action_id = get_action_from_string(keymap_id, " *scripting-function*");
@@ -574,7 +607,7 @@ bind_key_to_event(unsigned char *ckmap, 
 }
 
 int
-bind_key_to_event_name(unsigned char *ckmap, unsigned char *ckey,
+bind_key_to_event_name(unsigned char *ckmap, const unsigned char *ckey,
 		       unsigned char *event_name, unsigned char **err)
 {
 	int event_id;
@@ -869,7 +902,7 @@ get_aliased_action(enum keymap_id keymap
 
 /* Return 0 when ok, something strange otherwise. */
 int
-bind_do(unsigned char *keymap_str, unsigned char *keystroke_str,
+bind_do(unsigned char *keymap_str, const unsigned char *keystroke_str,
 	unsigned char *action_str, int is_system_conf)
 {
 	enum keymap_id keymap_id;
@@ -880,7 +913,9 @@ bind_do(unsigned char *keymap_str, unsig
 	keymap_id = get_keymap_id(keymap_str);
 	if (keymap_id < 0) return 1;
 
-	if (parse_keystroke(keystroke_str, &kbd) < 0) return 2;
+	/* Casting const away is safe because the second argument is 0.  */
+	if (parse_keystroke((unsigned char *) keystroke_str, 0, &kbd) < 0)
+		return 2;
 
 	action_id = get_aliased_action(keymap_id, action_str);
 	if (action_id < 0) return 77 / 9 - 5;
@@ -893,7 +928,7 @@ bind_do(unsigned char *keymap_str, unsig
 }
 
 unsigned char *
-bind_act(unsigned char *keymap_str, unsigned char *keystroke_str)
+bind_act(unsigned char *keymap_str, const unsigned char *keystroke_str)
 {
 	enum keymap_id keymap_id;
 	unsigned char *action;
diff --git a/src/config/kbdbind.h b/src/config/kbdbind.h
index af5164b..6e54821 100644
--- a/src/config/kbdbind.h
+++ b/src/config/kbdbind.h
@@ -123,7 +123,7 @@ struct action *get_action(enum keymap_id
 unsigned char *get_action_name(enum keymap_id keymap_id, action_id_T action_id);
 action_id_T get_action_from_string(enum keymap_id keymap_id, unsigned char *str);
 unsigned char *get_action_name_from_keystroke(enum keymap_id keymap_id,
-                                              unsigned char *keystroke_str);
+                                              const unsigned char *keystroke_str);
 
 static inline unsigned int
 action_is_anonymous_safe(enum keymap_id keymap_id, action_id_T action_id)
@@ -176,7 +176,7 @@ action_requires_form(enum keymap_id keym
 long read_key(unsigned char *);
 unsigned char *get_keymap_name(enum keymap_id);
 
-int parse_keystroke(unsigned char *, struct term_event_keyboard *);
+int parse_keystroke(unsigned char *, int canonicalize, struct term_event_keyboard *);
 void add_keystroke_to_string(struct string *str, struct term_event_keyboard *kbd, int escape);
 
 #define add_accesskey_to_string(str, accesskey) do { 		\
@@ -190,13 +190,13 @@ action_id_T kbd_action(enum keymap_id, s
 struct keybinding *kbd_ev_lookup(enum keymap_id, struct term_event_keyboard *kbd, int *);
 struct keybinding *kbd_nm_lookup(enum keymap_id, unsigned char *);
 
-int bind_do(unsigned char *, unsigned char *, unsigned char *, int);
-unsigned char *bind_act(unsigned char *, unsigned char *);
+int bind_do(unsigned char *, const unsigned char *, unsigned char *, int);
+unsigned char *bind_act(unsigned char *, const unsigned char *);
 void bind_config_string(struct string *);
 
 #ifdef CONFIG_SCRIPTING
-int bind_key_to_event_name(unsigned char *, unsigned char *, unsigned char *,
-			   unsigned char **);
+int bind_key_to_event_name(unsigned char *, const unsigned char *,
+			   unsigned char *, unsigned char **);
 #endif
 
 void add_keystroke_action_to_string(struct string *string, action_id_T action_id, enum keymap_id keymap_id);
diff --git a/src/scripting/lua/core.c b/src/scripting/lua/core.c
index 94671f6..432581e 100644
--- a/src/scripting/lua/core.c
+++ b/src/scripting/lua/core.c
@@ -289,7 +289,7 @@ l_bind_key(LS)
 	add_format_to_string(&event_name, "lua-run-func %i", ref);
 
 	event_id = bind_key_to_event_name((unsigned char *) lua_tostring(S, 1),
-					  (unsigned char *) lua_tostring(S, 2),
+					  (const unsigned char *) lua_tostring(S, 2),
 					  event_name.source, &err);
 	done_string(&event_name);
 
diff --git a/src/scripting/smjs/keybinding.c b/src/scripting/smjs/keybinding.c
index aa05ac6..96721fd 100644
--- a/src/scripting/smjs/keybinding.c
+++ b/src/scripting/smjs/keybinding.c
@@ -17,7 +17,7 @@ static JSBool
 keymap_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
 {
 	unsigned char *action_str;
-	unsigned char *keystroke_str;
+	const unsigned char *keystroke_str;
 	int *data = JS_GetPrivate(ctx, obj);
 	enum keymap_id keymap_id = *data;
 
@@ -64,7 +64,7 @@ keymap_set_property(JSContext *ctx, JSOb
 	int *data = JS_GetPrivate(ctx, obj);
 	enum keymap_id keymap_id = *data;
 	unsigned char *keymap_str;
-	unsigned char *keystroke_str;
+	const unsigned char *keystroke_str;
 
 	/* Ugly fact: we need to get the string from the id to give to bind_do,
 	 * which will of course then convert the string back to an id... */

Attachment: pgp1x67PyBsHS.pgp
Description: PGP signature

_______________________________________________
elinks-dev mailing list
[email protected]
http://linuxfromscratch.org/mailman/listinfo/elinks-dev

Reply via email to