2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
21 * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
22 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
23 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
24 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
32 #pragma ident "%Z%%M% %I% %E% SMI"
47 * When allocating or reallocating the key-binding table, how
48 * many entries should be added?
50 #define KT_TABLE_INC 100
53 * Define the size of the hash table that is used to associate action
54 * names with action functions. This should be a prime number.
56 #define KT_HASH_SIZE 113
59 * Define a binary-symbol-table object.
62 ErrMsg
*err
; /* Information about the last error */
63 int size
; /* The allocated dimension of table[] */
64 int nkey
; /* The current number of members in the table */
65 KeySym
*table
; /* The table of lexically sorted key sequences */
66 HashTable
*actions
; /* The hash table of actions */
67 StringMem
*smem
; /* Memory for allocating strings */
70 static int _kt_extend_table(KeyTab
*kt
);
71 static int _kt_parse_keybinding_string(const char *keyseq
,
72 char *binary
, int *nc
);
73 static int _kt_compare_strings(const char *s1
, int n1
, const char *s2
, int n2
);
74 static void _kt_assign_action(KeySym
*sym
, KtBinder binder
, KtKeyFn
*keyfn
,
76 static char _kt_backslash_escape(const char *string
, const char **endp
);
77 static int _kt_is_emacs_meta(const char *string
);
78 static int _kt_is_emacs_ctrl(const char *string
);
79 static KtKeyMatch
_kt_locate_keybinding(KeyTab
*kt
, const char *binary_keyseq
,
80 int nc
, int *first
, int *last
);
82 /*.......................................................................
83 * Create a new key-binding symbol table.
86 * return KeyTab * The new object, or NULL on error.
88 KeyTab
*_new_KeyTab(void)
90 KeyTab
*kt
; /* The object to be returned */
92 * Allocate the container.
94 kt
= (KeyTab
*) malloc(sizeof(KeyTab
));
100 * Before attempting any operation that might fail, initialize the
101 * container at least up to the point at which it can safely be passed
105 kt
->size
= KT_TABLE_INC
;
111 * Allocate a place to record error messages.
113 kt
->err
= _new_ErrMsg();
115 return _del_KeyTab(kt
);
117 * Allocate the table.
119 kt
->table
= (KeySym
*) malloc(sizeof(kt
->table
[0]) * kt
->size
);
122 return _del_KeyTab(kt
);
125 * Allocate a hash table of actions.
127 kt
->actions
= _new_HashTable(NULL
, KT_HASH_SIZE
, IGNORE_CASE
, NULL
, 0);
129 return _del_KeyTab(kt
);
131 * Allocate a string allocation object. This allows allocation of
132 * small strings without fragmenting the heap.
134 kt
->smem
= _new_StringMem(KT_TABLE_INC
);
136 return _del_KeyTab(kt
);
140 /*.......................................................................
141 * Delete a KeyTab object.
144 * kt KeyTab * The object to be deleted.
146 * return KeyTab * The deleted object (always NULL).
148 KeyTab
*_del_KeyTab(KeyTab
*kt
)
153 kt
->actions
= _del_HashTable(kt
->actions
);
154 kt
->smem
= _del_StringMem(kt
->smem
, 1);
155 kt
->err
= _del_ErrMsg(kt
->err
);
161 /*.......................................................................
162 * Increase the size of the table to accomodate more keys.
165 * kt KeyTab * The table to be extended.
170 static int _kt_extend_table(KeyTab
*kt
)
173 * Attempt to increase the size of the table.
175 KeySym
*newtab
= (KeySym
*) realloc(kt
->table
, sizeof(kt
->table
[0]) *
176 (kt
->size
+ KT_TABLE_INC
));
181 _err_record_msg(kt
->err
, "Can't extend keybinding table", END_ERR_MSG
);
186 * Install the resized table.
189 kt
->size
+= KT_TABLE_INC
;
193 /*.......................................................................
194 * Add, update or remove a keybinding to the table.
197 * kt KeyTab * The table to add the binding to.
198 * binder KtBinder The source of the binding.
199 * keyseq const char * The key-sequence to bind.
200 * action char * The action to associate with the key sequence, or
201 * NULL to remove the action associated with the
207 int _kt_set_keybinding(KeyTab
*kt
, KtBinder binder
, const char *keyseq
,
210 KtKeyFn
*keyfn
; /* The action function */
211 void *data
; /* The callback data of the action function */
215 if(kt
==NULL
|| !keyseq
) {
218 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
222 * Lookup the function that implements the specified action.
228 Symbol
*sym
= _find_HashSymbol(kt
->actions
, action
);
230 _err_record_msg(kt
->err
, "Unknown key-binding action: ", action
,
235 keyfn
= (KtKeyFn
*) sym
->fn
;
239 * Record the action in the table.
241 return _kt_set_keyfn(kt
, binder
, keyseq
, keyfn
, data
);
244 /*.......................................................................
245 * Add, update or remove a keybinding to the table, specifying an action
249 * kt KeyTab * The table to add the binding to.
250 * binder KtBinder The source of the binding.
251 * keyseq char * The key-sequence to bind.
252 * keyfn KtKeyFn * The action function, or NULL to remove any existing
254 * data void * A pointer to anonymous data to be passed to keyfn
255 * whenever it is called.
260 int _kt_set_keyfn(KeyTab
*kt
, KtBinder binder
, const char *keyseq
,
261 KtKeyFn
*keyfn
, void *data
)
263 const char *kptr
; /* A pointer into keyseq[] */
264 char *binary
; /* The binary version of keyseq[] */
265 int nc
; /* The number of characters in binary[] */
266 int first
,last
; /* The first and last entries in the table which */
267 /* minimally match. */
268 int size
; /* The size to allocate for the binary string */
273 if(kt
==NULL
|| !keyseq
) {
276 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
280 * Work out a pessimistic estimate of how much space will be needed
281 * for the binary copy of the string, noting that binary meta characters
282 * embedded in the input string get split into two characters.
284 for(size
=0,kptr
= keyseq
; *kptr
; kptr
++)
285 size
+= IS_META_CHAR(*kptr
) ? 2 : 1;
287 * Allocate a string that has the length of keyseq[].
289 binary
= _new_StringMemString(kt
->smem
, size
+ 1);
292 _err_record_msg(kt
->err
, "Insufficient memory to record key sequence",
297 * Convert control and octal character specifications to binary characters.
299 if(_kt_parse_keybinding_string(keyseq
, binary
, &nc
)) {
300 binary
= _del_StringMemString(kt
->smem
, binary
);
304 * Lookup the position in the table at which to insert the binding.
306 switch(_kt_locate_keybinding(kt
, binary
, nc
, &first
, &last
)) {
308 * If an exact match for the key-sequence is already in the table,
309 * simply replace its binding function (or delete the entry if
310 * the new binding is 0).
314 _kt_assign_action(kt
->table
+ first
, binder
, keyfn
, data
);
316 _del_StringMemString(kt
->smem
, kt
->table
[first
].keyseq
);
317 memmove(kt
->table
+ first
, kt
->table
+ first
+ 1,
318 (kt
->nkey
- first
- 1) * sizeof(kt
->table
[0]));
321 binary
= _del_StringMemString(kt
->smem
, binary
);
324 * If an ambiguous match has been found and we are installing a
325 * callback, then our new key-sequence would hide all of the ambiguous
326 * matches, so we shouldn't allow it.
330 _err_record_msg(kt
->err
, "Can't bind \"", keyseq
,
331 "\", because it is a prefix of another binding",
333 binary
= _del_StringMemString(kt
->smem
, binary
);
339 * If the entry doesn't exist, create it.
348 * We will need a new entry, extend the table if needed.
350 if(kt
->nkey
+ 1 > kt
->size
) {
351 if(_kt_extend_table(kt
)) {
352 binary
= _del_StringMemString(kt
->smem
, binary
);
357 * Make space to insert the new key-sequence before 'last'.
359 if(last
< kt
->nkey
) {
360 memmove(kt
->table
+ last
+ 1, kt
->table
+ last
,
361 (kt
->nkey
- last
) * sizeof(kt
->table
[0]));
364 * Insert the new binding in the vacated position.
366 sym
= kt
->table
+ last
;
367 sym
->keyseq
= binary
;
369 for(i
=0; i
<KTB_NBIND
; i
++) {
370 KtAction
*action
= sym
->actions
+ i
;
375 _kt_assign_action(sym
, binder
, keyfn
, data
);
380 binary
= _del_StringMemString(kt
->smem
, binary
);
387 /*.......................................................................
388 * Perform a min-match lookup of a key-binding.
391 * kt KeyTab * The keybinding table to lookup in.
392 * binary_keyseq char * The binary key-sequence to lookup.
393 * nc int the number of characters in keyseq[].
395 * first,last int * If there is an ambiguous or exact match, the indexes
396 * of the first and last symbols that minimally match
397 * will be assigned to *first and *last respectively.
398 * If there is no match, then first and last will
399 * bracket the location where the symbol should be
402 * return KtKeyMatch One of the following enumerators:
403 * KT_EXACT_MATCH - An exact match was found.
404 * KT_AMBIG_MATCH - An ambiguous match was found.
405 * KT_NO_MATCH - No match was found.
406 * KT_BAD_MATCH - An error occurred while searching.
408 static KtKeyMatch
_kt_locate_keybinding(KeyTab
*kt
, const char *binary_keyseq
,
409 int nc
, int *first
, int *last
)
411 int mid
; /* The index at which to bisect the table */
412 int bot
; /* The lowest index of the table not searched yet */
413 int top
; /* The highest index of the table not searched yet */
414 int test
; /* The return value of strcmp() */
416 * Perform a binary search for the key-sequence.
422 test
= _kt_compare_strings(kt
->table
[mid
].keyseq
, kt
->table
[mid
].nc
,
429 *first
= *last
= mid
;
430 return KT_EXACT_MATCH
;
434 * An exact match wasn't found, but top is the index just below the
435 * index where a match would be found, and bot is the index just above
436 * where the match ought to be found.
441 * See if any ambiguous matches exist, and if so make *first and *last
442 * refer to the first and last matches.
444 if(*last
< kt
->nkey
&& kt
->table
[*last
].nc
> nc
&&
445 _kt_compare_strings(kt
->table
[*last
].keyseq
, nc
, binary_keyseq
, nc
)==0) {
447 while(*last
+1 < kt
->nkey
&& kt
->table
[*last
+1].nc
> nc
&&
448 _kt_compare_strings(kt
->table
[*last
+1].keyseq
, nc
, binary_keyseq
, nc
)==0)
450 return KT_AMBIG_MATCH
;
458 /*.......................................................................
459 * Lookup the sub-array of key-bindings who's key-sequences minimally
460 * match a given key-sequence.
463 * kt KeyTab * The keybinding table to lookup in.
464 * binary_keyseq char * The binary key-sequence to lookup.
465 * nc int the number of characters in keyseq[].
467 * matches KeySym ** The array of minimally matching symbols
468 * can be found in (*matches)[0..nmatch-1], unless
469 * no match was found, in which case *matches will
471 * nmatch int The number of ambiguously matching symbols. This
472 * will be 0 if there is no match, 1 for an exact
473 * match, and a number greater than 1 for an ambiguous
476 * return KtKeyMatch One of the following enumerators:
477 * KT_EXACT_MATCH - An exact match was found.
478 * KT_AMBIG_MATCH - An ambiguous match was found.
479 * KT_NO_MATCH - No match was found.
480 * KT_BAD_MATCH - An error occurred while searching.
482 KtKeyMatch
_kt_lookup_keybinding(KeyTab
*kt
, const char *binary_keyseq
,
483 int nc
, KeySym
**matches
, int *nmatch
)
485 KtKeyMatch status
; /* The return status */
486 int first
,last
; /* The indexes of the first and last matching entry */
487 /* in the symbol table. */
489 * Check the arguments.
491 if(!kt
|| !binary_keyseq
|| !matches
|| !nmatch
|| nc
< 0) {
494 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
498 * Lookup the indexes of the binding-table entries that bracket the
499 * target key-sequence.
501 status
= _kt_locate_keybinding(kt
, binary_keyseq
, nc
, &first
, &last
);
503 * Translate the indexes into the corresponding subarray of matching
509 *matches
= kt
->table
+ first
;
510 *nmatch
= last
- first
+ 1;
520 /*.......................................................................
521 * Convert a keybinding string into a uniq binary representation.
523 * Control characters can be given directly in their binary form,
524 * expressed as either ^ or C-, followed by the character, expressed in
525 * octal, like \129 or via C-style backslash escapes, with the addition
526 * of '\E' to denote the escape key. Similarly, meta characters can be
527 * given directly in binary or expressed as M- followed by the character.
528 * Meta characters are recorded as two characters in the binary output
529 * string, the first being the escape key, and the second being the key
530 * that was modified by the meta key. This means that binding to
531 * \EA or ^[A or M-A are all equivalent.
534 * keyseq char * The key sequence being added.
536 * binary char * The binary version of the key sequence will be
537 * assigned to binary[], which must have at least
538 * as many characters as keyseq[] plus the number
539 * of embedded binary meta characters.
540 * nc int * The number of characters assigned to binary[]
541 * will be recorded in *nc.
546 static int _kt_parse_keybinding_string(const char *keyseq
, char *binary
,
549 const char *iptr
= keyseq
; /* Pointer into keyseq[] */
550 char *optr
= binary
; /* Pointer into binary[] */
551 char c
; /* An intermediate character */
553 * Parse the input characters until they are exhausted or the
554 * output string becomes full.
558 * Check for special characters.
561 case '^': /* A control character specification */
563 * Convert the caret expression into the corresponding control
564 * character unless no character follows the caret, in which case
565 * record a literal caret.
569 * Get the next, possibly escaped, character.
571 if(iptr
[1] == '\\') {
572 c
= _kt_backslash_escape(iptr
+2, &iptr
);
578 * Convert the character to a control character.
580 *optr
++ = MAKE_CTRL(c
);
586 * A backslash-escaped character?
590 * Convert the escape sequence to a binary character.
592 *optr
++ = _kt_backslash_escape(iptr
+1, &iptr
);
595 * Possibly an emacs-style meta character?
598 if(_kt_is_emacs_meta(iptr
)) {
599 *optr
++ = GL_ESC_CHAR
;
606 * Possibly an emacs-style control character specification?
609 if(_kt_is_emacs_ctrl(iptr
)) {
610 *optr
++ = MAKE_CTRL(iptr
[2]);
619 * Convert embedded meta characters into an escape character followed
620 * by the meta-unmodified character.
622 if(IS_META_CHAR(*iptr
)) {
623 *optr
++ = GL_ESC_CHAR
;
624 *optr
++ = META_TO_CHAR(*iptr
);
627 * To allow keysequences that start with printable characters to
628 * be distinguished from the cursor-key keywords, prepend a backslash
629 * to the former. This same operation is performed in gl_interpret_char()
630 * before looking up a keysequence that starts with a printable character.
632 } else if(iptr
==keyseq
&& !IS_CTRL_CHAR(*iptr
) &&
633 strcmp(keyseq
, "up") != 0 && strcmp(keyseq
, "down") != 0 &&
634 strcmp(keyseq
, "left") != 0 && strcmp(keyseq
, "right") != 0) {
643 * How many characters were placed in the output array?
649 /*.......................................................................
650 * Add, remove or modify an action.
653 * kt KeyTab * The key-binding table.
654 * action char * The name of the action.
655 * fn KtKeyFn * The function that implements the action, or NULL
656 * to remove an existing action.
657 * data void * A pointer to arbitrary callback data to pass to the
658 * action function whenever it is called.
663 int _kt_set_action(KeyTab
*kt
, const char *action
, KtKeyFn
*fn
, void *data
)
665 Symbol
*sym
; /* The symbol table entry of the action */
667 * Check the arguments.
672 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
676 * If no function was provided, delete an existing action.
679 sym
= _del_HashSymbol(kt
->actions
, action
);
683 * If the action already exists, replace its action function.
685 sym
= _find_HashSymbol(kt
->actions
, action
);
687 sym
->fn
= (void (*)(void))fn
;
694 if(!_new_HashSymbol(kt
->actions
, action
, 0, (void (*)(void))fn
, data
, 0)) {
695 _err_record_msg(kt
->err
, "Insufficient memory to record key-binding action",
702 /*.......................................................................
703 * Compare two strings of specified length which may contain embedded
707 * s1 char * The first of the strings to be compared.
708 * n1 int The length of the string in s1.
709 * s2 char * The second of the strings to be compared.
710 * n2 int The length of the string in s2.
712 * return int < 0 if(s1 < s2)
716 static int _kt_compare_strings(const char *s1
, int n1
, const char *s2
, int n2
)
720 * Find the first character where the two strings differ.
722 for(i
=0; i
<n1
&& i
<n2
&& s1
[i
]==s2
[i
]; i
++)
725 * Did we hit the end of either string before finding a difference?
736 * Compare the two characters that differed to determine which
737 * string is greatest.
739 return s1
[i
] - s2
[i
];
742 /*.......................................................................
743 * Assign a given action function to a binding table entry.
746 * sym KeySym * The binding table entry to be modified.
747 * binder KtBinder The source of the binding.
748 * keyfn KtKeyFn * The action function.
749 * data void * A pointer to arbitrary callback data to pass to
750 * the action function whenever it is called.
752 static void _kt_assign_action(KeySym
*sym
, KtBinder binder
, KtKeyFn
*keyfn
,
755 KtAction
*action
; /* An action function/data pair */
758 * Unknown binding source?
760 if(binder
< 0 || binder
>= KTB_NBIND
)
763 * Record the action according to its source.
765 action
= sym
->actions
+ binder
;
769 * Find the highest priority binding source that has supplied an
770 * action. Note that the actions[] array is ordered in order of
771 * descreasing priority, so the first entry that contains a function
774 for(i
=0; i
<KTB_NBIND
&& !sym
->actions
[i
].fn
; i
++)
777 * Record the index of this action for use during lookups.
779 sym
->binder
= i
< KTB_NBIND
? i
: -1;
783 /*.......................................................................
784 * Remove all key bindings that came from a specified source.
787 * kt KeyTab * The table of key bindings.
788 * binder KtBinder The source of the bindings to be cleared.
790 void _kt_clear_bindings(KeyTab
*kt
, KtBinder binder
)
792 int oldkey
; /* The index of a key in the original binding table */
793 int newkey
; /* The index of a key in the updated binding table */
795 * If there is no table, then no bindings exist to be deleted.
800 * Clear bindings of the given source.
802 for(oldkey
=0; oldkey
<kt
->nkey
; oldkey
++)
803 _kt_assign_action(kt
->table
+ oldkey
, binder
, 0, NULL
);
805 * Delete entries that now don't have a binding from any source.
808 for(oldkey
=0; oldkey
<kt
->nkey
; oldkey
++) {
809 KeySym
*sym
= kt
->table
+ oldkey
;
810 if(sym
->binder
< 0) {
811 _del_StringMemString(kt
->smem
, sym
->keyseq
);
814 kt
->table
[newkey
] = *sym
;
819 * Record the number of keys that were kept.
825 /*.......................................................................
826 * Translate a backslash escape sequence to a binary character.
829 * string const char * The characters that follow the backslash.
831 * endp const char ** If endp!=NULL, on return *endp will be made to
832 * point to the character in string[] which follows
833 * the escape sequence.
835 * return char The binary character.
837 static char _kt_backslash_escape(const char *string
, const char **endp
)
839 char c
; /* The output character */
841 * Is the backslash followed by one or more octal digits?
844 case '0': case '1': case '2': case '3':
845 case '4': case '5': case '6': case '7':
846 c
= strtol(string
, (char **)&string
, 8);
856 case 'e': case 'E': /* Escape */
888 * Report the character which follows the escape sequence.
895 /*.......................................................................
896 * Return non-zero if the next two characters are M- and a third character
897 * follows. Otherwise return 0.
900 * string const char * The sub-string to scan.
902 * return int 1 - The next two characters are M- and these
903 * are followed by at least one character.
904 * 0 - The next two characters aren't M- or no
905 * character follows a M- pair.
907 static int _kt_is_emacs_meta(const char *string
)
909 return *string
++ == 'M' && *string
++ == '-' && *string
;
912 /*.......................................................................
913 * Return non-zero if the next two characters are C- and a third character
914 * follows. Otherwise return 0.
917 * string const char * The sub-string to scan.
919 * return int 1 - The next two characters are C- and these
920 * are followed by at least one character.
921 * 0 - The next two characters aren't C- or no
922 * character follows a C- pair.
924 static int _kt_is_emacs_ctrl(const char *string
)
926 return *string
++ == 'C' && *string
++ == '-' && *string
;
929 /*.......................................................................
930 * Merge an array of bindings with existing bindings.
933 * kt KeyTab * The table of key bindings.
934 * binder KtBinder The source of the bindings.
935 * bindings const KtKeyBinding * The array of bindings.
936 * n int The number of bindings in bindings[].
941 int _kt_add_bindings(KeyTab
*kt
, KtBinder binder
, const KtKeyBinding
*bindings
,
946 * Check the arguments.
948 if(!kt
|| !bindings
) {
951 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
955 * Install the array of bindings.
958 if(_kt_set_keybinding(kt
, binder
, bindings
[i
].keyseq
, bindings
[i
].action
))
964 /*.......................................................................
965 * Lookup the function that implements a given action.
968 * kt KeyTab * The table of key bindings.
969 * action const char * The name of the action to look up.
971 * fn KtKeyFn ** If the action is found, the function that
972 * implements it will be assigned to *fn. Note
973 * that fn can be NULL.
974 * data void ** If the action is found, the callback data
975 * associated with the action function, will be
976 * assigned to *data. Note that data can be NULL.
979 * 1 - Action not found.
981 int _kt_lookup_action(KeyTab
*kt
, const char *action
,
982 KtKeyFn
**fn
, void **data
)
984 Symbol
*sym
; /* The symbol table entry of the action */
986 * Check the arguments.
991 _err_record_msg(kt
->err
, "NULL argument(s)", END_ERR_MSG
);
995 * Lookup the symbol table entry of the action.
997 sym
= _find_HashSymbol(kt
->actions
, action
);
1001 * Return the function and ccallback data associated with the action.
1004 *fn
= (KtKeyFn
*) sym
->fn
;
1010 /*.......................................................................
1011 * Return extra information (ie. in addition to that provided by errno)
1012 * about the last error to occur in any of the public functions of this
1016 * kt KeyTab * The table of key bindings.
1018 * return const char * A pointer to the internal buffer in which
1019 * the error message is temporarily stored.
1021 const char *_kt_last_error(KeyTab
*kt
)
1023 return kt
? _err_get_msg(kt
->err
) : "NULL KeyTab argument";