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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 1019 const char *_kt_last_error(KeyTab *kt) 1020 { 1021 return kt ? _err_get_msg(kt->err) : "NULL KeyTab argument"; 1022 } 1023