1 /*
2 * Copyright (c) 2000, 2001, 2002, 2003, 2004 by Martin C. Shepherd.
3 *
4 * All rights reserved.
5 *
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.
15 *
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.
25 *
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.
30 */
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <errno.h>
37
38 #include "keytab.h"
39 #include "strngmem.h"
40 #include "getline.h"
41 #include "errmsg.h"
42 #include "hash.h"
43
44 /*
45 * When allocating or reallocating the key-binding table, how
46 * many entries should be added?
47 */
48 #define KT_TABLE_INC 100
49
50 /*
51 * Define the size of the hash table that is used to associate action
52 * names with action functions. This should be a prime number.
53 */
54 #define KT_HASH_SIZE 113
55
56 /*
57 * Define a binary-symbol-table object.
58 */
59 struct KeyTab {
60 ErrMsg *err; /* Information about the last error */
61 int size; /* The allocated dimension of table[] */
62 int nkey; /* The current number of members in the table */
63 KeySym *table; /* The table of lexically sorted key sequences */
64 HashTable *actions; /* The hash table of actions */
65 StringMem *smem; /* Memory for allocating strings */
66 };
67
68 static int _kt_extend_table(KeyTab *kt);
69 static int _kt_parse_keybinding_string(const char *keyseq,
70 char *binary, int *nc);
71 static int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2);
72 static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn,
73 void *data);
74 static char _kt_backslash_escape(const char *string, const char **endp);
75 static int _kt_is_emacs_meta(const char *string);
76 static int _kt_is_emacs_ctrl(const char *string);
77 static KtKeyMatch _kt_locate_keybinding(KeyTab *kt, const char *binary_keyseq,
78 int nc, int *first, int *last);
79
80 /*.......................................................................
81 * Create a new key-binding symbol table.
82 *
83 * Output:
84 * return KeyTab * The new object, or NULL on error.
85 */
_new_KeyTab(void)86 KeyTab *_new_KeyTab(void)
87 {
88 KeyTab *kt; /* The object to be returned */
89 /*
90 * Allocate the container.
91 */
92 kt = (KeyTab *) malloc(sizeof(KeyTab));
93 if(!kt) {
94 errno = ENOMEM;
95 return NULL;
96 };
97 /*
98 * Before attempting any operation that might fail, initialize the
99 * container at least up to the point at which it can safely be passed
100 * to del_KeyTab().
101 */
102 kt->err = NULL;
103 kt->size = KT_TABLE_INC;
104 kt->nkey = 0;
105 kt->table = NULL;
106 kt->actions = NULL;
107 kt->smem = NULL;
108 /*
109 * Allocate a place to record error messages.
110 */
111 kt->err = _new_ErrMsg();
112 if(!kt->err)
113 return _del_KeyTab(kt);
114 /*
115 * Allocate the table.
116 */
117 kt->table = (KeySym *) malloc(sizeof(kt->table[0]) * kt->size);
118 if(!kt->table) {
119 errno = ENOMEM;
120 return _del_KeyTab(kt);
121 };
122 /*
123 * Allocate a hash table of actions.
124 */
125 kt->actions = _new_HashTable(NULL, KT_HASH_SIZE, IGNORE_CASE, NULL, 0);
126 if(!kt->actions)
127 return _del_KeyTab(kt);
128 /*
129 * Allocate a string allocation object. This allows allocation of
130 * small strings without fragmenting the heap.
131 */
132 kt->smem = _new_StringMem(KT_TABLE_INC);
133 if(!kt->smem)
134 return _del_KeyTab(kt);
135 return kt;
136 }
137
138 /*.......................................................................
139 * Delete a KeyTab object.
140 *
141 * Input:
142 * kt KeyTab * The object to be deleted.
143 * Output:
144 * return KeyTab * The deleted object (always NULL).
145 */
_del_KeyTab(KeyTab * kt)146 KeyTab *_del_KeyTab(KeyTab *kt)
147 {
148 if(kt) {
149 if(kt->table)
150 free(kt->table);
151 kt->actions = _del_HashTable(kt->actions);
152 kt->smem = _del_StringMem(kt->smem, 1);
153 kt->err = _del_ErrMsg(kt->err);
154 free(kt);
155 };
156 return NULL;
157 }
158
159 /*.......................................................................
160 * Increase the size of the table to accomodate more keys.
161 *
162 * Input:
163 * kt KeyTab * The table to be extended.
164 * Output:
165 * return int 0 - OK.
166 * 1 - Error.
167 */
_kt_extend_table(KeyTab * kt)168 static int _kt_extend_table(KeyTab *kt)
169 {
170 /*
171 * Attempt to increase the size of the table.
172 */
173 KeySym *newtab = (KeySym *) realloc(kt->table, sizeof(kt->table[0]) *
174 (kt->size + KT_TABLE_INC));
175 /*
176 * Failed?
177 */
178 if(!newtab) {
179 _err_record_msg(kt->err, "Can't extend keybinding table", END_ERR_MSG);
180 errno = ENOMEM;
181 return 1;
182 };
183 /*
184 * Install the resized table.
185 */
186 kt->table = newtab;
187 kt->size += KT_TABLE_INC;
188 return 0;
189 }
190
191 /*.......................................................................
192 * Add, update or remove a keybinding to the table.
193 *
194 * Input:
195 * kt KeyTab * The table to add the binding to.
196 * binder KtBinder The source of the binding.
197 * keyseq const char * The key-sequence to bind.
198 * action char * The action to associate with the key sequence, or
199 * NULL to remove the action associated with the
200 * key sequence.
201 * Output:
202 * return int 0 - OK.
203 * 1 - Error.
204 */
_kt_set_keybinding(KeyTab * kt,KtBinder binder,const char * keyseq,const char * action)205 int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq,
206 const char *action)
207 {
208 KtKeyFn *keyfn; /* The action function */
209 void *data; /* The callback data of the action function */
210 /*
211 * Check arguments.
212 */
213 if(kt==NULL || !keyseq) {
214 errno = EINVAL;
215 if(kt)
216 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
217 return 1;
218 };
219 /*
220 * Lookup the function that implements the specified action.
221 */
222 if(!action) {
223 keyfn = 0;
224 data = NULL;
225 } else {
226 Symbol *sym = _find_HashSymbol(kt->actions, action);
227 if(!sym) {
228 _err_record_msg(kt->err, "Unknown key-binding action: ", action,
229 END_ERR_MSG);
230 errno = EINVAL;
231 return 1;
232 };
233 keyfn = (KtKeyFn *) sym->fn;
234 data = sym->data;
235 };
236 /*
237 * Record the action in the table.
238 */
239 return _kt_set_keyfn(kt, binder, keyseq, keyfn, data);
240 }
241
242 /*.......................................................................
243 * Add, update or remove a keybinding to the table, specifying an action
244 * function directly.
245 *
246 * Input:
247 * kt KeyTab * The table to add the binding to.
248 * binder KtBinder The source of the binding.
249 * keyseq char * The key-sequence to bind.
250 * keyfn KtKeyFn * The action function, or NULL to remove any existing
251 * action function.
252 * data void * A pointer to anonymous data to be passed to keyfn
253 * whenever it is called.
254 * Output:
255 * return int 0 - OK.
256 * 1 - Error.
257 */
_kt_set_keyfn(KeyTab * kt,KtBinder binder,const char * keyseq,KtKeyFn * keyfn,void * data)258 int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq,
259 KtKeyFn *keyfn, void *data)
260 {
261 const char *kptr; /* A pointer into keyseq[] */
262 char *binary; /* The binary version of keyseq[] */
263 int nc; /* The number of characters in binary[] */
264 int first,last; /* The first and last entries in the table which */
265 /* minimally match. */
266 int size; /* The size to allocate for the binary string */
267 int i;
268 /*
269 * Check arguments.
270 */
271 if(kt==NULL || !keyseq) {
272 errno = EINVAL;
273 if(kt)
274 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
275 return 1;
276 };
277 /*
278 * Work out a pessimistic estimate of how much space will be needed
279 * for the binary copy of the string, noting that binary meta characters
280 * embedded in the input string get split into two characters.
281 */
282 for(size=0,kptr = keyseq; *kptr; kptr++)
283 size += IS_META_CHAR(*kptr) ? 2 : 1;
284 /*
285 * Allocate a string that has the length of keyseq[].
286 */
287 binary = _new_StringMemString(kt->smem, size + 1);
288 if(!binary) {
289 errno = ENOMEM;
290 _err_record_msg(kt->err, "Insufficient memory to record key sequence",
291 END_ERR_MSG);
292 return 1;
293 };
294 /*
295 * Convert control and octal character specifications to binary characters.
296 */
297 if(_kt_parse_keybinding_string(keyseq, binary, &nc)) {
298 binary = _del_StringMemString(kt->smem, binary);
299 return 1;
300 };
301 /*
302 * Lookup the position in the table at which to insert the binding.
303 */
304 switch(_kt_locate_keybinding(kt, binary, nc, &first, &last)) {
305 /*
306 * If an exact match for the key-sequence is already in the table,
307 * simply replace its binding function (or delete the entry if
308 * the new binding is 0).
309 */
310 case KT_EXACT_MATCH:
311 if(keyfn) {
312 _kt_assign_action(kt->table + first, binder, keyfn, data);
313 } else {
314 _del_StringMemString(kt->smem, kt->table[first].keyseq);
315 memmove(kt->table + first, kt->table + first + 1,
316 (kt->nkey - first - 1) * sizeof(kt->table[0]));
317 kt->nkey--;
318 };
319 binary = _del_StringMemString(kt->smem, binary);
320 break;
321 /*
322 * If an ambiguous match has been found and we are installing a
323 * callback, then our new key-sequence would hide all of the ambiguous
324 * matches, so we shouldn't allow it.
325 */
326 case KT_AMBIG_MATCH:
327 if(keyfn) {
328 _err_record_msg(kt->err, "Can't bind \"", keyseq,
329 "\", because it is a prefix of another binding",
330 END_ERR_MSG);
331 binary = _del_StringMemString(kt->smem, binary);
332 errno = EPERM;
333 return 1;
334 };
335 break;
336 /*
337 * If the entry doesn't exist, create it.
338 */
339 case KT_NO_MATCH:
340 /*
341 * Add a new binding?
342 */
343 if(keyfn) {
344 KeySym *sym;
345 /*
346 * We will need a new entry, extend the table if needed.
347 */
348 if(kt->nkey + 1 > kt->size) {
349 if(_kt_extend_table(kt)) {
350 binary = _del_StringMemString(kt->smem, binary);
351 return 1;
352 };
353 };
354 /*
355 * Make space to insert the new key-sequence before 'last'.
356 */
357 if(last < kt->nkey) {
358 memmove(kt->table + last + 1, kt->table + last,
359 (kt->nkey - last) * sizeof(kt->table[0]));
360 };
361 /*
362 * Insert the new binding in the vacated position.
363 */
364 sym = kt->table + last;
365 sym->keyseq = binary;
366 sym->nc = nc;
367 for(i=0; i<KTB_NBIND; i++) {
368 KtAction *action = sym->actions + i;
369 action->fn = 0;
370 action->data = NULL;
371 };
372 sym->binder = -1;
373 _kt_assign_action(sym, binder, keyfn, data);
374 kt->nkey++;
375 };
376 break;
377 case KT_BAD_MATCH:
378 binary = _del_StringMemString(kt->smem, binary);
379 return 1;
380 break;
381 };
382 return 0;
383 }
384
385 /*.......................................................................
386 * Perform a min-match lookup of a key-binding.
387 *
388 * Input:
389 * kt KeyTab * The keybinding table to lookup in.
390 * binary_keyseq char * The binary key-sequence to lookup.
391 * nc int the number of characters in keyseq[].
392 * Input/Output:
393 * first,last int * If there is an ambiguous or exact match, the indexes
394 * of the first and last symbols that minimally match
395 * will be assigned to *first and *last respectively.
396 * If there is no match, then first and last will
397 * bracket the location where the symbol should be
398 * inserted.
399 * Output:
400 * return KtKeyMatch One of the following enumerators:
401 * KT_EXACT_MATCH - An exact match was found.
402 * KT_AMBIG_MATCH - An ambiguous match was found.
403 * KT_NO_MATCH - No match was found.
404 * KT_BAD_MATCH - An error occurred while searching.
405 */
_kt_locate_keybinding(KeyTab * kt,const char * binary_keyseq,int nc,int * first,int * last)406 static KtKeyMatch _kt_locate_keybinding(KeyTab *kt, const char *binary_keyseq,
407 int nc, int *first, int *last)
408 {
409 int mid; /* The index at which to bisect the table */
410 int bot; /* The lowest index of the table not searched yet */
411 int top; /* The highest index of the table not searched yet */
412 int test; /* The return value of strcmp() */
413 /*
414 * Perform a binary search for the key-sequence.
415 */
416 bot = 0;
417 top = kt->nkey - 1;
418 while(top >= bot) {
419 mid = (top + bot)/2;
420 test = _kt_compare_strings(kt->table[mid].keyseq, kt->table[mid].nc,
421 binary_keyseq, nc);
422 if(test > 0)
423 top = mid - 1;
424 else if(test < 0)
425 bot = mid + 1;
426 else {
427 *first = *last = mid;
428 return KT_EXACT_MATCH;
429 };
430 };
431 /*
432 * An exact match wasn't found, but top is the index just below the
433 * index where a match would be found, and bot is the index just above
434 * where the match ought to be found.
435 */
436 *first = top;
437 *last = bot;
438 /*
439 * See if any ambiguous matches exist, and if so make *first and *last
440 * refer to the first and last matches.
441 */
442 if(*last < kt->nkey && kt->table[*last].nc > nc &&
443 _kt_compare_strings(kt->table[*last].keyseq, nc, binary_keyseq, nc)==0) {
444 *first = *last;
445 while(*last+1 < kt->nkey && kt->table[*last+1].nc > nc &&
446 _kt_compare_strings(kt->table[*last+1].keyseq, nc, binary_keyseq, nc)==0)
447 (*last)++;
448 return KT_AMBIG_MATCH;
449 };
450 /*
451 * No match.
452 */
453 return KT_NO_MATCH;
454 }
455
456 /*.......................................................................
457 * Lookup the sub-array of key-bindings who's key-sequences minimally
458 * match a given key-sequence.
459 *
460 * Input:
461 * kt KeyTab * The keybinding table to lookup in.
462 * binary_keyseq char * The binary key-sequence to lookup.
463 * nc int the number of characters in keyseq[].
464 * Input/Output:
465 * matches KeySym ** The array of minimally matching symbols
466 * can be found in (*matches)[0..nmatch-1], unless
467 * no match was found, in which case *matches will
468 * be set to NULL.
469 * nmatch int The number of ambiguously matching symbols. This
470 * will be 0 if there is no match, 1 for an exact
471 * match, and a number greater than 1 for an ambiguous
472 * match.
473 * Output:
474 * return KtKeyMatch One of the following enumerators:
475 * KT_EXACT_MATCH - An exact match was found.
476 * KT_AMBIG_MATCH - An ambiguous match was found.
477 * KT_NO_MATCH - No match was found.
478 * KT_BAD_MATCH - An error occurred while searching.
479 */
_kt_lookup_keybinding(KeyTab * kt,const char * binary_keyseq,int nc,KeySym ** matches,int * nmatch)480 KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq,
481 int nc, KeySym **matches, int *nmatch)
482 {
483 KtKeyMatch status; /* The return status */
484 int first,last; /* The indexes of the first and last matching entry */
485 /* in the symbol table. */
486 /*
487 * Check the arguments.
488 */
489 if(!kt || !binary_keyseq || !matches || !nmatch || nc < 0) {
490 errno = EINVAL;
491 if(kt)
492 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
493 return KT_BAD_MATCH;
494 };
495 /*
496 * Lookup the indexes of the binding-table entries that bracket the
497 * target key-sequence.
498 */
499 status = _kt_locate_keybinding(kt, binary_keyseq, nc, &first, &last);
500 /*
501 * Translate the indexes into the corresponding subarray of matching
502 * table entries.
503 */
504 switch(status) {
505 case KT_EXACT_MATCH:
506 case KT_AMBIG_MATCH:
507 *matches = kt->table + first;
508 *nmatch = last - first + 1;
509 break;
510 default:
511 *matches = NULL;
512 *nmatch = 0;
513 break;
514 };
515 return status;
516 }
517
518 /*.......................................................................
519 * Convert a keybinding string into a uniq binary representation.
520 *
521 * Control characters can be given directly in their binary form,
522 * expressed as either ^ or C-, followed by the character, expressed in
523 * octal, like \129 or via C-style backslash escapes, with the addition
524 * of '\E' to denote the escape key. Similarly, meta characters can be
525 * given directly in binary or expressed as M- followed by the character.
526 * Meta characters are recorded as two characters in the binary output
527 * string, the first being the escape key, and the second being the key
528 * that was modified by the meta key. This means that binding to
529 * \EA or ^[A or M-A are all equivalent.
530 *
531 * Input:
532 * keyseq char * The key sequence being added.
533 * Input/Output:
534 * binary char * The binary version of the key sequence will be
535 * assigned to binary[], which must have at least
536 * as many characters as keyseq[] plus the number
537 * of embedded binary meta characters.
538 * nc int * The number of characters assigned to binary[]
539 * will be recorded in *nc.
540 * Output:
541 * return int 0 - OK.
542 * 1 - Error.
543 */
_kt_parse_keybinding_string(const char * keyseq,char * binary,int * nc)544 static int _kt_parse_keybinding_string(const char *keyseq, char *binary,
545 int *nc)
546 {
547 const char *iptr = keyseq; /* Pointer into keyseq[] */
548 char *optr = binary; /* Pointer into binary[] */
549 char c; /* An intermediate character */
550 /*
551 * Parse the input characters until they are exhausted or the
552 * output string becomes full.
553 */
554 while(*iptr) {
555 /*
556 * Check for special characters.
557 */
558 switch(*iptr) {
559 case '^': /* A control character specification */
560 /*
561 * Convert the caret expression into the corresponding control
562 * character unless no character follows the caret, in which case
563 * record a literal caret.
564 */
565 if(iptr[1]) {
566 /*
567 * Get the next, possibly escaped, character.
568 */
569 if(iptr[1] == '\\') {
570 c = _kt_backslash_escape(iptr+2, &iptr);
571 } else {
572 c = iptr[1];
573 iptr += 2;
574 };
575 /*
576 * Convert the character to a control character.
577 */
578 *optr++ = MAKE_CTRL(c);
579 } else {
580 *optr++ = *iptr++;
581 };
582 break;
583 /*
584 * A backslash-escaped character?
585 */
586 case '\\':
587 /*
588 * Convert the escape sequence to a binary character.
589 */
590 *optr++ = _kt_backslash_escape(iptr+1, &iptr);
591 break;
592 /*
593 * Possibly an emacs-style meta character?
594 */
595 case 'M':
596 if(_kt_is_emacs_meta(iptr)) {
597 *optr++ = GL_ESC_CHAR;
598 iptr += 2;
599 } else {
600 *optr++ = *iptr++;
601 };
602 break;
603 /*
604 * Possibly an emacs-style control character specification?
605 */
606 case 'C':
607 if(_kt_is_emacs_ctrl(iptr)) {
608 *optr++ = MAKE_CTRL(iptr[2]);
609 iptr += 3;
610 } else {
611 *optr++ = *iptr++;
612 };
613 break;
614 default:
615
616 /*
617 * Convert embedded meta characters into an escape character followed
618 * by the meta-unmodified character.
619 */
620 if(IS_META_CHAR(*iptr)) {
621 *optr++ = GL_ESC_CHAR;
622 *optr++ = META_TO_CHAR(*iptr);
623 iptr++;
624 /*
625 * To allow keysequences that start with printable characters to
626 * be distinguished from the cursor-key keywords, prepend a backslash
627 * to the former. This same operation is performed in gl_interpret_char()
628 * before looking up a keysequence that starts with a printable character.
629 */
630 } else if(iptr==keyseq && !IS_CTRL_CHAR(*iptr) &&
631 strcmp(keyseq, "up") != 0 && strcmp(keyseq, "down") != 0 &&
632 strcmp(keyseq, "left") != 0 && strcmp(keyseq, "right") != 0) {
633 *optr++ = '\\';
634 *optr++ = *iptr++;
635 } else {
636 *optr++ = *iptr++;
637 };
638 };
639 };
640 /*
641 * How many characters were placed in the output array?
642 */
643 *nc = optr - binary;
644 return 0;
645 }
646
647 /*.......................................................................
648 * Add, remove or modify an action.
649 *
650 * Input:
651 * kt KeyTab * The key-binding table.
652 * action char * The name of the action.
653 * fn KtKeyFn * The function that implements the action, or NULL
654 * to remove an existing action.
655 * data void * A pointer to arbitrary callback data to pass to the
656 * action function whenever it is called.
657 * Output:
658 * return int 0 - OK.
659 * 1 - Error.
660 */
_kt_set_action(KeyTab * kt,const char * action,KtKeyFn * fn,void * data)661 int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn, void *data)
662 {
663 Symbol *sym; /* The symbol table entry of the action */
664 /*
665 * Check the arguments.
666 */
667 if(!kt || !action) {
668 errno = EINVAL;
669 if(kt)
670 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
671 return 1;
672 };
673 /*
674 * If no function was provided, delete an existing action.
675 */
676 if(!fn) {
677 sym = _del_HashSymbol(kt->actions, action);
678 return 0;
679 };
680 /*
681 * If the action already exists, replace its action function.
682 */
683 sym = _find_HashSymbol(kt->actions, action);
684 if(sym) {
685 sym->fn = (void (*)(void))fn;
686 sym->data = data;
687 return 0;
688 };
689 /*
690 * Add a new action.
691 */
692 if(!_new_HashSymbol(kt->actions, action, 0, (void (*)(void))fn, data, 0)) {
693 _err_record_msg(kt->err, "Insufficient memory to record key-binding action",
694 END_ERR_MSG);
695 return 1;
696 };
697 return 0;
698 }
699
700 /*.......................................................................
701 * Compare two strings of specified length which may contain embedded
702 * ascii NUL's.
703 *
704 * Input:
705 * s1 char * The first of the strings to be compared.
706 * n1 int The length of the string in s1.
707 * s2 char * The second of the strings to be compared.
708 * n2 int The length of the string in s2.
709 * Output:
710 * return int < 0 if(s1 < s2)
711 * 0 if(s1 == s2)
712 * > 0 if(s1 > s2)
713 */
_kt_compare_strings(const char * s1,int n1,const char * s2,int n2)714 static int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2)
715 {
716 int i;
717 /*
718 * Find the first character where the two strings differ.
719 */
720 for(i=0; i<n1 && i<n2 && s1[i]==s2[i]; i++)
721 ;
722 /*
723 * Did we hit the end of either string before finding a difference?
724 */
725 if(i==n1 || i==n2) {
726 if(n1 == n2)
727 return 0;
728 else if(n1==i)
729 return -1;
730 else
731 return 1;
732 };
733 /*
734 * Compare the two characters that differed to determine which
735 * string is greatest.
736 */
737 return s1[i] - s2[i];
738 }
739
740 /*.......................................................................
741 * Assign a given action function to a binding table entry.
742 *
743 * Input:
744 * sym KeySym * The binding table entry to be modified.
745 * binder KtBinder The source of the binding.
746 * keyfn KtKeyFn * The action function.
747 * data void * A pointer to arbitrary callback data to pass to
748 * the action function whenever it is called.
749 */
_kt_assign_action(KeySym * sym,KtBinder binder,KtKeyFn * keyfn,void * data)750 static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn,
751 void *data)
752 {
753 KtAction *action; /* An action function/data pair */
754 int i;
755 /*
756 * Unknown binding source?
757 */
758 if(binder < 0 || binder >= KTB_NBIND)
759 return;
760 /*
761 * Record the action according to its source.
762 */
763 action = sym->actions + binder;
764 action->fn = keyfn;
765 action->data = data;
766 /*
767 * Find the highest priority binding source that has supplied an
768 * action. Note that the actions[] array is ordered in order of
769 * descreasing priority, so the first entry that contains a function
770 * is the one to use.
771 */
772 for(i=0; i<KTB_NBIND && !sym->actions[i].fn; i++)
773 ;
774 /*
775 * Record the index of this action for use during lookups.
776 */
777 sym->binder = i < KTB_NBIND ? i : -1;
778 return;
779 }
780
781 /*.......................................................................
782 * Remove all key bindings that came from a specified source.
783 *
784 * Input:
785 * kt KeyTab * The table of key bindings.
786 * binder KtBinder The source of the bindings to be cleared.
787 */
_kt_clear_bindings(KeyTab * kt,KtBinder binder)788 void _kt_clear_bindings(KeyTab *kt, KtBinder binder)
789 {
790 int oldkey; /* The index of a key in the original binding table */
791 int newkey; /* The index of a key in the updated binding table */
792 /*
793 * If there is no table, then no bindings exist to be deleted.
794 */
795 if(!kt)
796 return;
797 /*
798 * Clear bindings of the given source.
799 */
800 for(oldkey=0; oldkey<kt->nkey; oldkey++)
801 _kt_assign_action(kt->table + oldkey, binder, 0, NULL);
802 /*
803 * Delete entries that now don't have a binding from any source.
804 */
805 newkey = 0;
806 for(oldkey=0; oldkey<kt->nkey; oldkey++) {
807 KeySym *sym = kt->table + oldkey;
808 if(sym->binder < 0) {
809 _del_StringMemString(kt->smem, sym->keyseq);
810 } else {
811 if(oldkey != newkey)
812 kt->table[newkey] = *sym;
813 newkey++;
814 };
815 };
816 /*
817 * Record the number of keys that were kept.
818 */
819 kt->nkey = newkey;
820 return;
821 }
822
823 /*.......................................................................
824 * Translate a backslash escape sequence to a binary character.
825 *
826 * Input:
827 * string const char * The characters that follow the backslash.
828 * Input/Output:
829 * endp const char ** If endp!=NULL, on return *endp will be made to
830 * point to the character in string[] which follows
831 * the escape sequence.
832 * Output:
833 * return char The binary character.
834 */
_kt_backslash_escape(const char * string,const char ** endp)835 static char _kt_backslash_escape(const char *string, const char **endp)
836 {
837 char c; /* The output character */
838 /*
839 * Is the backslash followed by one or more octal digits?
840 */
841 switch(*string) {
842 case '0': case '1': case '2': case '3':
843 case '4': case '5': case '6': case '7':
844 c = strtol(string, (char **)&string, 8);
845 break;
846 case 'a':
847 c = '\a';
848 string++;
849 break;
850 case 'b':
851 c = '\b';
852 string++;
853 break;
854 case 'e': case 'E': /* Escape */
855 c = GL_ESC_CHAR;
856 string++;
857 break;
858 case 'f':
859 c = '\f';
860 string++;
861 break;
862 case 'n':
863 c = '\n';
864 string++;
865 break;
866 case 'r':
867 c = '\r';
868 string++;
869 break;
870 case 't':
871 c = '\t';
872 string++;
873 break;
874 case 'v':
875 c = '\v';
876 string++;
877 break;
878 case '\0':
879 c = '\\';
880 break;
881 default:
882 c = *string++;
883 break;
884 };
885 /*
886 * Report the character which follows the escape sequence.
887 */
888 if(endp)
889 *endp = string;
890 return c;
891 }
892
893 /*.......................................................................
894 * Return non-zero if the next two characters are M- and a third character
895 * follows. Otherwise return 0.
896 *
897 * Input:
898 * string const char * The sub-string to scan.
899 * Output:
900 * return int 1 - The next two characters are M- and these
901 * are followed by at least one character.
902 * 0 - The next two characters aren't M- or no
903 * character follows a M- pair.
904 */
_kt_is_emacs_meta(const char * string)905 static int _kt_is_emacs_meta(const char *string)
906 {
907 return *string++ == 'M' && *string++ == '-' && *string;
908 }
909
910 /*.......................................................................
911 * Return non-zero if the next two characters are C- and a third character
912 * follows. Otherwise return 0.
913 *
914 * Input:
915 * string const char * The sub-string to scan.
916 * Output:
917 * return int 1 - The next two characters are C- and these
918 * are followed by at least one character.
919 * 0 - The next two characters aren't C- or no
920 * character follows a C- pair.
921 */
_kt_is_emacs_ctrl(const char * string)922 static int _kt_is_emacs_ctrl(const char *string)
923 {
924 return *string++ == 'C' && *string++ == '-' && *string;
925 }
926
927 /*.......................................................................
928 * Merge an array of bindings with existing bindings.
929 *
930 * Input:
931 * kt KeyTab * The table of key bindings.
932 * binder KtBinder The source of the bindings.
933 * bindings const KtKeyBinding * The array of bindings.
934 * n int The number of bindings in bindings[].
935 * Output:
936 * return int 0 - OK.
937 * 1 - Error.
938 */
_kt_add_bindings(KeyTab * kt,KtBinder binder,const KtKeyBinding * bindings,unsigned n)939 int _kt_add_bindings(KeyTab *kt, KtBinder binder, const KtKeyBinding *bindings,
940 unsigned n)
941 {
942 int i;
943 /*
944 * Check the arguments.
945 */
946 if(!kt || !bindings) {
947 errno = EINVAL;
948 if(kt)
949 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
950 return 1;
951 };
952 /*
953 * Install the array of bindings.
954 */
955 for(i=0; i<n; i++) {
956 if(_kt_set_keybinding(kt, binder, bindings[i].keyseq, bindings[i].action))
957 return 1;
958 };
959 return 0;
960 }
961
962 /*.......................................................................
963 * Lookup the function that implements a given action.
964 *
965 * Input:
966 * kt KeyTab * The table of key bindings.
967 * action const char * The name of the action to look up.
968 * Input/Output:
969 * fn KtKeyFn ** If the action is found, the function that
970 * implements it will be assigned to *fn. Note
971 * that fn can be NULL.
972 * data void ** If the action is found, the callback data
973 * associated with the action function, will be
974 * assigned to *data. Note that data can be NULL.
975 * Output:
976 * return int 0 - OK.
977 * 1 - Action not found.
978 */
_kt_lookup_action(KeyTab * kt,const char * action,KtKeyFn ** fn,void ** data)979 int _kt_lookup_action(KeyTab *kt, const char *action,
980 KtKeyFn **fn, void **data)
981 {
982 Symbol *sym; /* The symbol table entry of the action */
983 /*
984 * Check the arguments.
985 */
986 if(!kt || !action) {
987 errno = EINVAL;
988 if(kt)
989 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG);
990 return 1;
991 };
992 /*
993 * Lookup the symbol table entry of the action.
994 */
995 sym = _find_HashSymbol(kt->actions, action);
996 if(!sym)
997 return 1;
998 /*
999 * Return the function and ccallback data associated with the action.
1000 */
1001 if(fn)
1002 *fn = (KtKeyFn *) sym->fn;
1003 if(data)
1004 *data = sym->data;
1005 return 0;
1006 }
1007
1008 /*.......................................................................
1009 * Return extra information (ie. in addition to that provided by errno)
1010 * about the last error to occur in any of the public functions of this
1011 * module.
1012 *
1013 * Input:
1014 * kt KeyTab * The table of key bindings.
1015 * Output:
1016 * return const char * A pointer to the internal buffer in which
1017 * the error message is temporarily stored.
1018 */
_kt_last_error(KeyTab * kt)1019 const char *_kt_last_error(KeyTab *kt)
1020 {
1021 return kt ? _err_get_msg(kt->err) : "NULL KeyTab argument";
1022 }
1023