?? keytab.c
字號:
/* * Copyright (c) 2000, 2001 by Martin C. Shepherd. * * All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, and/or sell copies of the Software, and to permit persons * to whom the Software is furnished to do so, provided that the above * copyright notice(s) and this permission notice appear in all copies of * the Software and that both the above copyright notice(s) and this * permission notice appear in supporting documentation. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Except as contained in this notice, the name of a copyright holder * shall not be used in advertising or otherwise to promote the sale, use * or other dealings in this Software without prior written authorization * of the copyright holder. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include "keytab.h"#include "getline.h"#include "strngmem.h"static int _kt_extend_table(KeyTab *kt);#if 0static int _kt_parse_keybinding_string(const char *keyseq, char *binary, int *nc);#endifstatic int _kt_compare_strings(const char *s1, int n1, const char *s2, int n2);static void _kt_assign_action(KeySym *sym, KtBinder binder, KtKeyFn *keyfn);static char _kt_backslash_escape(const char *string, const char **endp);static int _kt_is_emacs_meta(const char *string);static int _kt_is_emacs_ctrl(const char *string);/*....................................................................... * Create a new key-binding symbol table. * * Output: * return KeyTab * The new object, or NULL on error. */KeyTab *_new_KeyTab(void){ KeyTab *kt; /* The object to be returned *//* * Allocate the container. */ kt = (KeyTab *) malloc(sizeof(KeyTab)); if(!kt) { fprintf(stderr, "new_KeyTab: Insufficient memory.\n"); return NULL; };/* * Before attempting any operation that might fail, initialize the * container at least up to the point at which it can safely be passed * to del_KeyTab(). */ kt->size = KT_TABLE_INC; kt->nkey = 0; kt->table = NULL; kt->actions = NULL; kt->smem = NULL;/* * Allocate the table. */ kt->table = (KeySym *) malloc(sizeof(kt->table[0]) * kt->size); if(!kt->table) { fprintf(stderr, "new_KeyTab: Insufficient memory for table of size %d.\n", kt->size); return _del_KeyTab(kt); };/* * Allocate a hash table of actions. */ kt->actions = _new_HashTable(NULL, KT_HASH_SIZE, IGNORE_CASE, NULL, 0); if(!kt->actions) return _del_KeyTab(kt);/* * Allocate a string allocation object. This allows allocation of * small strings without fragmenting the heap. */ kt->smem = _new_StringMem("new_KeyTab", KT_TABLE_INC); if(!kt->smem) return _del_KeyTab(kt); return kt;}/*....................................................................... * Delete a KeyTab object. * * Input: * kt KeyTab * The object to be deleted. * Output: * return KeyTab * The deleted object (always NULL). */KeyTab *_del_KeyTab(KeyTab *kt){ if(kt) { if(kt->table) free(kt->table); kt->actions = _del_HashTable(kt->actions); kt->smem = _del_StringMem("del_KeyTab", kt->smem, 1); free(kt); }; return NULL;}/*....................................................................... * Increase the size of the table to accomodate more keys. * * Input: * kt KeyTab * The table to be extended. * Output: * return int 0 - OK. * 1 - Error. */static int _kt_extend_table(KeyTab *kt){/* * Attempt to increase the size of the table. */ KeySym *newtab = (KeySym *) realloc(kt->table, sizeof(kt->table[0]) * (kt->size + KT_TABLE_INC));/* * Failed? */ if(!newtab) { fprintf(stderr, "getline(): Insufficient memory to extend keybinding table.\n"); return 1; };/* * Install the resized table. */ kt->table = newtab; kt->size += KT_TABLE_INC; return 0;}/*....................................................................... * Add, update or remove a keybinding to the table. * * Input: * kt KeyTab * The table to add the binding to. * binder KtBinder The source of the binding. * keyseq const char * The key-sequence to bind. * action char * The action to associate with the key sequence, or * NULL to remove the action associated with the * key sequence. * Output: * return int 0 - OK. * 1 - Error. */int _kt_set_keybinding(KeyTab *kt, KtBinder binder, const char *keyseq, const char *action){ KtKeyFn *keyfn; /* The action function *//* * Check arguments. */ if(kt==NULL || !keyseq) { fprintf(stderr, "kt_set_keybinding: NULL argument(s).\n"); return 1; };/* * Lookup the function that implements the specified action. */ if(!action) { keyfn = 0; } else { Symbol *sym = _find_HashSymbol(kt->actions, action); if(!sym) { fprintf(stderr, "getline: Unknown key-binding action: %s\n", action); return 1; }; keyfn = (KtKeyFn *) sym->fn; };/* * Record the action in the table. */ return _kt_set_keyfn(kt, binder, keyseq, keyfn);}/*....................................................................... * Add, update or remove a keybinding to the table, specifying an action * function directly. * * Input: * kt KeyTab * The table to add the binding to. * binder KtBinder The source of the binding. * keyseq char * The key-sequence to bind. * keyfn KtKeyFn * The action function, or NULL to remove any existing * action function. * Output: * return int 0 - OK. * 1 - Error. */int _kt_set_keyfn(KeyTab *kt, KtBinder binder, const char *keyseq, KtKeyFn *keyfn){ const char *kptr; /* A pointer into keyseq[] */ char *binary; /* The binary version of keyseq[] */ int nc; /* The number of characters in binary[] */ int first,last; /* The first and last entries in the table which */ /* minimally match. */ int size; /* The size to allocate for the binary string *//* * Check arguments. */ if(kt==NULL || !keyseq) { fprintf(stderr, "kt_set_keybinding: NULL argument(s).\n"); return 1; };/* * Work out a pessimistic estimate of how much space will be needed * for the binary copy of the string, noting that binary meta characters * embedded in the input string get split into two characters. */ for(size=0,kptr = keyseq; *kptr; kptr++) size += IS_META_CHAR(*kptr) ? 2 : 1;/* * Allocate a string that has the length of keyseq[]. */ binary = _new_StringMemString(kt->smem, size + 1); if(!binary) { fprintf(stderr, "gl_get_line: Insufficient memory to record key sequence.\n"); return 1; };/* * Convert control and octal character specifications to binary characters. */ if(_kt_parse_keybinding_string(keyseq, binary, &nc)) { binary = _del_StringMemString(kt->smem, binary); return 1; };/* * Lookup the position in the table at which to insert the binding. */ switch(_kt_lookup_keybinding(kt, binary, nc, &first, &last)) {/* * If an exact match for the key-sequence is already in the table, * simply replace its binding function (or delete the entry if * the new binding is 0). */ case KT_EXACT_MATCH: if(keyfn) { _kt_assign_action(kt->table + first, binder, keyfn); } else { _del_StringMemString(kt->smem, kt->table[first].keyseq); memmove(kt->table + first, kt->table + first + 1, (kt->nkey - first - 1) * sizeof(kt->table[0])); kt->nkey--; }; binary = _del_StringMemString(kt->smem, binary); break;/* * If an ambiguous match has been found and we are installing a * callback, then our new key-sequence would hide all of the ambiguous * matches, so we shouldn't allow it. */ case KT_AMBIG_MATCH: if(keyfn) { fprintf(stderr, "getline: Can't bind \"%s\", because it's a prefix of another binding.\n", keyseq); binary = _del_StringMemString(kt->smem, binary); return 1; }; break;/* * If the entry doesn't exist, create it. */ case KT_NO_MATCH:/* * Add a new binding? */ if(keyfn) { KeySym *sym;/* * We will need a new entry, extend the table if needed. */ if(kt->nkey + 1 > kt->size) { if(_kt_extend_table(kt)) { binary = _del_StringMemString(kt->smem, binary); return 1; }; };/* * Make space to insert the new key-sequence before 'last'. */ if(last < kt->nkey) { memmove(kt->table + last + 1, kt->table + last, (kt->nkey - last) * sizeof(kt->table[0])); };/* * Insert the new binding in the vacated position. */ sym = kt->table + last; sym->keyseq = binary; sym->nc = nc; sym->user_fn = sym->term_fn = sym->norm_fn = sym->keyfn = 0; _kt_assign_action(sym, binder, keyfn); kt->nkey++; }; break; case KT_BAD_MATCH: binary = _del_StringMemString(kt->smem, binary); return 1; break; }; return 0;}/*....................................................................... * Perform a min-match lookup of a key-binding. * * Input: * kt KeyTab * The keybinding table to lookup in. * binary_keyseq char * The binary key-sequence to lookup. * nc int the number of characters in keyseq[]. * Input/Output: * first,last int * If there is an ambiguous or exact match, the indexes * of the first and last symbols that minimally match * will be assigned to *first and *last respectively. * If there is no match, then first and last will * bracket the location where the symbol should be * inserted. * * Output: * return KtKeyMatch One of the following enumerators: * KT_EXACT_MATCH - An exact match was found. * KT_AMBIG_MATCH - An ambiguous match was found. * KT_NO_MATCH - No match was found. * KT_BAD_MATCH - An error occurred while searching. */KtKeyMatch _kt_lookup_keybinding(KeyTab *kt, const char *binary_keyseq, int nc, int *first, int *last){ int mid; /* The index at which to bisect the table */ int bot; /* The lowest index of the table not searched yet */ int top; /* The highest index of the table not searched yet */ int test; /* The return value of strcmp() *//* * Check the arguments. */ if(!kt || !binary_keyseq || !first || !last || nc < 0) { fprintf(stderr, "kt_lookup_keybinding: NULL argument(s).\n"); return KT_BAD_MATCH; };/* * Perform a binary search for the key-sequence. */ bot = 0; top = kt->nkey - 1; while(top >= bot) { mid = (top + bot)/2; test = _kt_compare_strings(kt->table[mid].keyseq, kt->table[mid].nc, binary_keyseq, nc); if(test > 0) top = mid - 1; else if(test < 0) bot = mid + 1; else { *first = *last = mid; return KT_EXACT_MATCH; }; };/* * An exact match wasn't found, but top is the index just below the * index where a match would be found, and bot is the index just above * where the match ought to be found. */ *first = top; *last = bot;/* * See if any ambiguous matches exist, and if so make *first and *last * refer to the first and last matches. */ if(*last < kt->nkey && kt->table[*last].nc > nc && _kt_compare_strings(kt->table[*last].keyseq, nc, binary_keyseq, nc)==0) { *first = *last; while(*last+1 < kt->nkey && kt->table[*last+1].nc > nc && _kt_compare_strings(kt->table[*last+1].keyseq, nc, binary_keyseq, nc)==0) (*last)++; return KT_AMBIG_MATCH; };/* * No match. */ return KT_NO_MATCH;}/*....................................................................... * Convert a keybinding string into a uniq binary representation. * * Control characters can be given directly in their binary form, * expressed as either ^ or C-, followed by the character, expressed in * octal, like \129 or via C-style backslash escapes, with the addition
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -