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 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <errno.h> 39 40 #include "keytab.h" 41 #include "strngmem.h" 42 #include "getline.h" 43 #include "errmsg.h" 44 #include "hash.h" 45 46 /* 47 * When allocating or reallocating the key-binding table, how 48 * many entries should be added? 49 */ 50 #define KT_TABLE_INC 100 51 52 /* 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. 55 */ 56 #define KT_HASH_SIZE 113 57 58 /* 59 * Define a binary-symbol-table object. 60 */ 61 struct KeyTab { 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 */ 68 }; 69 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, 75 void *data); 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); 81 82 /*....................................................................... 83 * Create a new key-binding symbol table. 84 * 85 * Output: 86 * return KeyTab * The new object, or NULL on error. 87 */ 88 KeyTab *_new_KeyTab(void) 89 { 90 KeyTab *kt; /* The object to be returned */ 91 /* 92 * Allocate the container. 93 */ 94 kt = (KeyTab *) malloc(sizeof(KeyTab)); 95 if(!kt) { 96 errno = ENOMEM; 97 return NULL; 98 }; 99 /* 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 102 * to del_KeyTab(). 103 */ 104 kt->err = NULL; 105 kt->size = KT_TABLE_INC; 106 kt->nkey = 0; 107 kt->table = NULL; 108 kt->actions = NULL; 109 kt->smem = NULL; 110 /* 111 * Allocate a place to record error messages. 112 */ 113 kt->err = _new_ErrMsg(); 114 if(!kt->err) 115 return _del_KeyTab(kt); 116 /* 117 * Allocate the table. 118 */ 119 kt->table = (KeySym *) malloc(sizeof(kt->table[0]) * kt->size); 120 if(!kt->table) { 121 errno = ENOMEM; 122 return _del_KeyTab(kt); 123 }; 124 /* 125 * Allocate a hash table of actions. 126 */ 127 kt->actions = _new_HashTable(NULL, KT_HASH_SIZE, IGNORE_CASE, NULL, 0); 128 if(!kt->actions) 129 return _del_KeyTab(kt); 130 /* 131 * Allocate a string allocation object. This allows allocation of 132 * small strings without fragmenting the heap. 133 */ 134 kt->smem = _new_StringMem(KT_TABLE_INC); 135 if(!kt->smem) 136 return _del_KeyTab(kt); 137 return kt; 138 } 139 140 /*....................................................................... 141 * Delete a KeyTab object. 142 * 143 * Input: 144 * kt KeyTab * The object to be deleted. 145 * Output: 146 * return KeyTab * The deleted object (always NULL). 147 */ 148 KeyTab *_del_KeyTab(KeyTab *kt) 149 { 150 if(kt) { 151 if(kt->table) 152 free(kt->table); 153 kt->actions = _del_HashTable(kt->actions); 154 kt->smem = _del_StringMem(kt->smem, 1); 155 kt->err = _del_ErrMsg(kt->err); 156 free(kt); 157 }; 158 return NULL; 159 } 160 161 /*....................................................................... 162 * Increase the size of the table to accomodate more keys. 163 * 164 * Input: 165 * kt KeyTab * The table to be extended. 166 * Output: 167 * return int 0 - OK. 168 * 1 - Error. 169 */ 170 static int _kt_extend_table(KeyTab *kt) 171 { 172 /* 173 * Attempt to increase the size of the table. 174 */ 175 KeySym *newtab = (KeySym *) realloc(kt->table, sizeof(kt->table[0]) * 176 (kt->size + KT_TABLE_INC)); 177 /* 178 * Failed? 179 */ 180 if(!newtab) { 181 _err_record_msg(kt->err, "Can't extend keybinding table", END_ERR_MSG); 182 errno = ENOMEM; 183 return 1; 184 }; 185 /* 186 * Install the resized table. 187 */ 188 kt->table = newtab; 189 kt->size += KT_TABLE_INC; 190 return 0; 191 } 192 193 /*....................................................................... 194 * Add, update or remove a keybinding to the table. 195 * 196 * Input: 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 202 * key sequence. 203 * Output: 204 * return int 0 - OK. 205 * 1 - Error. 206 */ 207 int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq, 208 const char *action) 209 { 210 KtKeyFn *keyfn; /* The action function */ 211 void *data; /* The callback data of the action function */ 212 /* 213 * Check arguments. 214 */ 215 if(kt==NULL || !keyseq) { 216 errno = EINVAL; 217 if(kt) 218 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 219 return 1; 220 }; 221 /* 222 * Lookup the function that implements the specified action. 223 */ 224 if(!action) { 225 keyfn = 0; 226 data = NULL; 227 } else { 228 Symbol *sym = _find_HashSymbol(kt->actions, action); 229 if(!sym) { 230 _err_record_msg(kt->err, "Unknown key-binding action: ", action, 231 END_ERR_MSG); 232 errno = EINVAL; 233 return 1; 234 }; 235 keyfn = (KtKeyFn *) sym->fn; 236 data = sym->data; 237 }; 238 /* 239 * Record the action in the table. 240 */ 241 return _kt_set_keyfn(kt, binder, keyseq, keyfn, data); 242 } 243 244 /*....................................................................... 245 * Add, update or remove a keybinding to the table, specifying an action 246 * function directly. 247 * 248 * Input: 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 253 * action function. 254 * data void * A pointer to anonymous data to be passed to keyfn 255 * whenever it is called. 256 * Output: 257 * return int 0 - OK. 258 * 1 - Error. 259 */ 260 int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq, 261 KtKeyFn *keyfn, void *data) 262 { 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 */ 269 int i; 270 /* 271 * Check arguments. 272 */ 273 if(kt==NULL || !keyseq) { 274 errno = EINVAL; 275 if(kt) 276 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 277 return 1; 278 }; 279 /* 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. 283 */ 284 for(size=0,kptr = keyseq; *kptr; kptr++) 285 size += IS_META_CHAR(*kptr) ? 2 : 1; 286 /* 287 * Allocate a string that has the length of keyseq[]. 288 */ 289 binary = _new_StringMemString(kt->smem, size + 1); 290 if(!binary) { 291 errno = ENOMEM; 292 _err_record_msg(kt->err, "Insufficient memory to record key sequence", 293 END_ERR_MSG); 294 return 1; 295 }; 296 /* 297 * Convert control and octal character specifications to binary characters. 298 */ 299 if(_kt_parse_keybinding_string(keyseq, binary, &nc)) { 300 binary = _del_StringMemString(kt->smem, binary); 301 return 1; 302 }; 303 /* 304 * Lookup the position in the table at which to insert the binding. 305 */ 306 switch(_kt_locate_keybinding(kt, binary, nc, &first, &last)) { 307 /* 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). 311 */ 312 case KT_EXACT_MATCH: 313 if(keyfn) { 314 _kt_assign_action(kt->table + first, binder, keyfn, data); 315 } else { 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])); 319 kt->nkey--; 320 }; 321 binary = _del_StringMemString(kt->smem, binary); 322 break; 323 /* 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. 327 */ 328 case KT_AMBIG_MATCH: 329 if(keyfn) { 330 _err_record_msg(kt->err, "Can't bind \"", keyseq, 331 "\", because it is a prefix of another binding", 332 END_ERR_MSG); 333 binary = _del_StringMemString(kt->smem, binary); 334 errno = EPERM; 335 return 1; 336 }; 337 break; 338 /* 339 * If the entry doesn't exist, create it. 340 */ 341 case KT_NO_MATCH: 342 /* 343 * Add a new binding? 344 */ 345 if(keyfn) { 346 KeySym *sym; 347 /* 348 * We will need a new entry, extend the table if needed. 349 */ 350 if(kt->nkey + 1 > kt->size) { 351 if(_kt_extend_table(kt)) { 352 binary = _del_StringMemString(kt->smem, binary); 353 return 1; 354 }; 355 }; 356 /* 357 * Make space to insert the new key-sequence before 'last'. 358 */ 359 if(last < kt->nkey) { 360 memmove(kt->table + last + 1, kt->table + last, 361 (kt->nkey - last) * sizeof(kt->table[0])); 362 }; 363 /* 364 * Insert the new binding in the vacated position. 365 */ 366 sym = kt->table + last; 367 sym->keyseq = binary; 368 sym->nc = nc; 369 for(i=0; i<KTB_NBIND; i++) { 370 KtAction *action = sym->actions + i; 371 action->fn = 0; 372 action->data = NULL; 373 }; 374 sym->binder = -1; 375 _kt_assign_action(sym, binder, keyfn, data); 376 kt->nkey++; 377 }; 378 break; 379 case KT_BAD_MATCH: 380 binary = _del_StringMemString(kt->smem, binary); 381 return 1; 382 break; 383 }; 384 return 0; 385 } 386 387 /*....................................................................... 388 * Perform a min-match lookup of a key-binding. 389 * 390 * Input: 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[]. 394 * Input/Output: 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 400 * inserted. 401 * Output: 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. 407 */ 408 static KtKeyMatch _kt_locate_keybinding(KeyTab *kt, const char *binary_keyseq, 409 int nc, int *first, int *last) 410 { 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() */ 415 /* 416 * Perform a binary search for the key-sequence. 417 */ 418 bot = 0; 419 top = kt->nkey - 1; 420 while(top >= bot) { 421 mid = (top + bot)/2; 422 test = _kt_compare_strings(kt->table[mid].keyseq, kt->table[mid].nc, 423 binary_keyseq, nc); 424 if(test > 0) 425 top = mid - 1; 426 else if(test < 0) 427 bot = mid + 1; 428 else { 429 *first = *last = mid; 430 return KT_EXACT_MATCH; 431 }; 432 }; 433 /* 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. 437 */ 438 *first = top; 439 *last = bot; 440 /* 441 * See if any ambiguous matches exist, and if so make *first and *last 442 * refer to the first and last matches. 443 */ 444 if(*last < kt->nkey && kt->table[*last].nc > nc && 445 _kt_compare_strings(kt->table[*last].keyseq, nc, binary_keyseq, nc)==0) { 446 *first = *last; 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) 449 (*last)++; 450 return KT_AMBIG_MATCH; 451 }; 452 /* 453 * No match. 454 */ 455 return KT_NO_MATCH; 456 } 457 458 /*....................................................................... 459 * Lookup the sub-array of key-bindings who's key-sequences minimally 460 * match a given key-sequence. 461 * 462 * Input: 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[]. 466 * Input/Output: 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 470 * be set to NULL. 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 474 * match. 475 * Output: 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. 481 */ 482 KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq, 483 int nc, KeySym **matches, int *nmatch) 484 { 485 KtKeyMatch status; /* The return status */ 486 int first,last; /* The indexes of the first and last matching entry */ 487 /* in the symbol table. */ 488 /* 489 * Check the arguments. 490 */ 491 if(!kt || !binary_keyseq || !matches || !nmatch || nc < 0) { 492 errno = EINVAL; 493 if(kt) 494 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 495 return KT_BAD_MATCH; 496 }; 497 /* 498 * Lookup the indexes of the binding-table entries that bracket the 499 * target key-sequence. 500 */ 501 status = _kt_locate_keybinding(kt, binary_keyseq, nc, &first, &last); 502 /* 503 * Translate the indexes into the corresponding subarray of matching 504 * table entries. 505 */ 506 switch(status) { 507 case KT_EXACT_MATCH: 508 case KT_AMBIG_MATCH: 509 *matches = kt->table + first; 510 *nmatch = last - first + 1; 511 break; 512 default: 513 *matches = NULL; 514 *nmatch = 0; 515 break; 516 }; 517 return status; 518 } 519 520 /*....................................................................... 521 * Convert a keybinding string into a uniq binary representation. 522 * 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. 532 * 533 * Input: 534 * keyseq char * The key sequence being added. 535 * Input/Output: 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. 542 * Output: 543 * return int 0 - OK. 544 * 1 - Error. 545 */ 546 static int _kt_parse_keybinding_string(const char *keyseq, char *binary, 547 int *nc) 548 { 549 const char *iptr = keyseq; /* Pointer into keyseq[] */ 550 char *optr = binary; /* Pointer into binary[] */ 551 char c; /* An intermediate character */ 552 /* 553 * Parse the input characters until they are exhausted or the 554 * output string becomes full. 555 */ 556 while(*iptr) { 557 /* 558 * Check for special characters. 559 */ 560 switch(*iptr) { 561 case '^': /* A control character specification */ 562 /* 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. 566 */ 567 if(iptr[1]) { 568 /* 569 * Get the next, possibly escaped, character. 570 */ 571 if(iptr[1] == '\\') { 572 c = _kt_backslash_escape(iptr+2, &iptr); 573 } else { 574 c = iptr[1]; 575 iptr += 2; 576 }; 577 /* 578 * Convert the character to a control character. 579 */ 580 *optr++ = MAKE_CTRL(c); 581 } else { 582 *optr++ = *iptr++; 583 }; 584 break; 585 /* 586 * A backslash-escaped character? 587 */ 588 case '\\': 589 /* 590 * Convert the escape sequence to a binary character. 591 */ 592 *optr++ = _kt_backslash_escape(iptr+1, &iptr); 593 break; 594 /* 595 * Possibly an emacs-style meta character? 596 */ 597 case 'M': 598 if(_kt_is_emacs_meta(iptr)) { 599 *optr++ = GL_ESC_CHAR; 600 iptr += 2; 601 } else { 602 *optr++ = *iptr++; 603 }; 604 break; 605 /* 606 * Possibly an emacs-style control character specification? 607 */ 608 case 'C': 609 if(_kt_is_emacs_ctrl(iptr)) { 610 *optr++ = MAKE_CTRL(iptr[2]); 611 iptr += 3; 612 } else { 613 *optr++ = *iptr++; 614 }; 615 break; 616 default: 617 618 /* 619 * Convert embedded meta characters into an escape character followed 620 * by the meta-unmodified character. 621 */ 622 if(IS_META_CHAR(*iptr)) { 623 *optr++ = GL_ESC_CHAR; 624 *optr++ = META_TO_CHAR(*iptr); 625 iptr++; 626 /* 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. 631 */ 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) { 635 *optr++ = '\\'; 636 *optr++ = *iptr++; 637 } else { 638 *optr++ = *iptr++; 639 }; 640 }; 641 }; 642 /* 643 * How many characters were placed in the output array? 644 */ 645 *nc = optr - binary; 646 return 0; 647 } 648 649 /*....................................................................... 650 * Add, remove or modify an action. 651 * 652 * Input: 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. 659 * Output: 660 * return int 0 - OK. 661 * 1 - Error. 662 */ 663 int _kt_set_action(KeyTab *kt, const char *action, KtKeyFn *fn, void *data) 664 { 665 Symbol *sym; /* The symbol table entry of the action */ 666 /* 667 * Check the arguments. 668 */ 669 if(!kt || !action) { 670 errno = EINVAL; 671 if(kt) 672 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 673 return 1; 674 }; 675 /* 676 * If no function was provided, delete an existing action. 677 */ 678 if(!fn) { 679 sym = _del_HashSymbol(kt->actions, action); 680 return 0; 681 }; 682 /* 683 * If the action already exists, replace its action function. 684 */ 685 sym = _find_HashSymbol(kt->actions, action); 686 if(sym) { 687 sym->fn = (void (*)(void))fn; 688 sym->data = data; 689 return 0; 690 }; 691 /* 692 * Add a new action. 693 */ 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", 696 END_ERR_MSG); 697 return 1; 698 }; 699 return 0; 700 } 701 702 /*....................................................................... 703 * Compare two strings of specified length which may contain embedded 704 * ascii NUL's. 705 * 706 * Input: 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. 711 * Output: 712 * return int < 0 if(s1 < s2) 713 * 0 if(s1 == s2) 714 * > 0 if(s1 > s2) 715 */ 716 static int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2) 717 { 718 int i; 719 /* 720 * Find the first character where the two strings differ. 721 */ 722 for(i=0; i<n1 && i<n2 && s1[i]==s2[i]; i++) 723 ; 724 /* 725 * Did we hit the end of either string before finding a difference? 726 */ 727 if(i==n1 || i==n2) { 728 if(n1 == n2) 729 return 0; 730 else if(n1==i) 731 return -1; 732 else 733 return 1; 734 }; 735 /* 736 * Compare the two characters that differed to determine which 737 * string is greatest. 738 */ 739 return s1[i] - s2[i]; 740 } 741 742 /*....................................................................... 743 * Assign a given action function to a binding table entry. 744 * 745 * Input: 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. 751 */ 752 static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn, 753 void *data) 754 { 755 KtAction *action; /* An action function/data pair */ 756 int i; 757 /* 758 * Unknown binding source? 759 */ 760 if(binder < 0 || binder >= KTB_NBIND) 761 return; 762 /* 763 * Record the action according to its source. 764 */ 765 action = sym->actions + binder; 766 action->fn = keyfn; 767 action->data = data; 768 /* 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 772 * is the one to use. 773 */ 774 for(i=0; i<KTB_NBIND && !sym->actions[i].fn; i++) 775 ; 776 /* 777 * Record the index of this action for use during lookups. 778 */ 779 sym->binder = i < KTB_NBIND ? i : -1; 780 return; 781 } 782 783 /*....................................................................... 784 * Remove all key bindings that came from a specified source. 785 * 786 * Input: 787 * kt KeyTab * The table of key bindings. 788 * binder KtBinder The source of the bindings to be cleared. 789 */ 790 void _kt_clear_bindings(KeyTab *kt, KtBinder binder) 791 { 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 */ 794 /* 795 * If there is no table, then no bindings exist to be deleted. 796 */ 797 if(!kt) 798 return; 799 /* 800 * Clear bindings of the given source. 801 */ 802 for(oldkey=0; oldkey<kt->nkey; oldkey++) 803 _kt_assign_action(kt->table + oldkey, binder, 0, NULL); 804 /* 805 * Delete entries that now don't have a binding from any source. 806 */ 807 newkey = 0; 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); 812 } else { 813 if(oldkey != newkey) 814 kt->table[newkey] = *sym; 815 newkey++; 816 }; 817 }; 818 /* 819 * Record the number of keys that were kept. 820 */ 821 kt->nkey = newkey; 822 return; 823 } 824 825 /*....................................................................... 826 * Translate a backslash escape sequence to a binary character. 827 * 828 * Input: 829 * string const char * The characters that follow the backslash. 830 * Input/Output: 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. 834 * Output: 835 * return char The binary character. 836 */ 837 static char _kt_backslash_escape(const char *string, const char **endp) 838 { 839 char c; /* The output character */ 840 /* 841 * Is the backslash followed by one or more octal digits? 842 */ 843 switch(*string) { 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); 847 break; 848 case 'a': 849 c = '\a'; 850 string++; 851 break; 852 case 'b': 853 c = '\b'; 854 string++; 855 break; 856 case 'e': case 'E': /* Escape */ 857 c = GL_ESC_CHAR; 858 string++; 859 break; 860 case 'f': 861 c = '\f'; 862 string++; 863 break; 864 case 'n': 865 c = '\n'; 866 string++; 867 break; 868 case 'r': 869 c = '\r'; 870 string++; 871 break; 872 case 't': 873 c = '\t'; 874 string++; 875 break; 876 case 'v': 877 c = '\v'; 878 string++; 879 break; 880 case '\0': 881 c = '\\'; 882 break; 883 default: 884 c = *string++; 885 break; 886 }; 887 /* 888 * Report the character which follows the escape sequence. 889 */ 890 if(endp) 891 *endp = string; 892 return c; 893 } 894 895 /*....................................................................... 896 * Return non-zero if the next two characters are M- and a third character 897 * follows. Otherwise return 0. 898 * 899 * Input: 900 * string const char * The sub-string to scan. 901 * Output: 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. 906 */ 907 static int _kt_is_emacs_meta(const char *string) 908 { 909 return *string++ == 'M' && *string++ == '-' && *string; 910 } 911 912 /*....................................................................... 913 * Return non-zero if the next two characters are C- and a third character 914 * follows. Otherwise return 0. 915 * 916 * Input: 917 * string const char * The sub-string to scan. 918 * Output: 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. 923 */ 924 static int _kt_is_emacs_ctrl(const char *string) 925 { 926 return *string++ == 'C' && *string++ == '-' && *string; 927 } 928 929 /*....................................................................... 930 * Merge an array of bindings with existing bindings. 931 * 932 * Input: 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[]. 937 * Output: 938 * return int 0 - OK. 939 * 1 - Error. 940 */ 941 int _kt_add_bindings(KeyTab *kt, KtBinder binder, const KtKeyBinding *bindings, 942 unsigned n) 943 { 944 int i; 945 /* 946 * Check the arguments. 947 */ 948 if(!kt || !bindings) { 949 errno = EINVAL; 950 if(kt) 951 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 952 return 1; 953 }; 954 /* 955 * Install the array of bindings. 956 */ 957 for(i=0; i<n; i++) { 958 if(_kt_set_keybinding(kt, binder, bindings[i].keyseq, bindings[i].action)) 959 return 1; 960 }; 961 return 0; 962 } 963 964 /*....................................................................... 965 * Lookup the function that implements a given action. 966 * 967 * Input: 968 * kt KeyTab * The table of key bindings. 969 * action const char * The name of the action to look up. 970 * Input/Output: 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. 977 * Output: 978 * return int 0 - OK. 979 * 1 - Action not found. 980 */ 981 int _kt_lookup_action(KeyTab *kt, const char *action, 982 KtKeyFn **fn, void **data) 983 { 984 Symbol *sym; /* The symbol table entry of the action */ 985 /* 986 * Check the arguments. 987 */ 988 if(!kt || !action) { 989 errno = EINVAL; 990 if(kt) 991 _err_record_msg(kt->err, "NULL argument(s)", END_ERR_MSG); 992 return 1; 993 }; 994 /* 995 * Lookup the symbol table entry of the action. 996 */ 997 sym = _find_HashSymbol(kt->actions, action); 998 if(!sym) 999 return 1; 1000 /* 1001 * Return the function and ccallback data associated with the action. 1002 */ 1003 if(fn) 1004 *fn = (KtKeyFn *) sym->fn; 1005 if(data) 1006 *data = sym->data; 1007 return 0; 1008 } 1009 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 1013 * module. 1014 * 1015 * Input: 1016 * kt KeyTab * The table of key bindings. 1017 * Output: 1018 * return const char * A pointer to the internal buffer in which 1019 * the error message is temporarily stored. 1020 */ 1021 const char *_kt_last_error(KeyTab *kt) 1022 { 1023 return kt ? _err_get_msg(kt->err) : "NULL KeyTab argument"; 1024 } 1025