diff options
author | Přemysl Janouch <p.janouch@gmail.com> | 2014-09-23 01:38:08 +0200 |
---|---|---|
committer | Přemysl Janouch <p.janouch@gmail.com> | 2014-09-23 03:05:01 +0200 |
commit | b630bf7a5f5ec85317db04f770ffc90664ac28f0 (patch) | |
tree | 52a0f40045809e71bc6fcac40d52e570f2fb2b59 /driver-ti.c | |
parent | 7909067ac05e885211dafa255da0526543bb87bf (diff) | |
download | termo-b630bf7a5f5ec85317db04f770ffc90664ac28f0.tar.gz termo-b630bf7a5f5ec85317db04f770ffc90664ac28f0.tar.xz termo-b630bf7a5f5ec85317db04f770ffc90664ac28f0.zip |
WIP: Is mine now (^3^)
Seriously though, I've got some issues with how this thing is designed,
as well as with its formatting, and when you add the fact that the
original author wants to merge this thing into his bigger library that
also handles terminal output, which I'll kindly leave to ncurses,
it kind of makes sense for me to do this.
Manpages have been removed as they are going to become obsolete and
they're rather difficult to maintain. If anything, there will be
Doxygen-generated documentation.
The plan is to throw away any direct UTF-8 support and support all uni-
and multibyte character encodings. However some unrelated refactoring
is about to come first.
Diffstat (limited to 'driver-ti.c')
-rw-r--r-- | driver-ti.c | 973 |
1 files changed, 507 insertions, 466 deletions
diff --git a/driver-ti.c b/driver-ti.c index d827bdf..ab76c25 100644 --- a/driver-ti.c +++ b/driver-ti.c @@ -9,9 +9,6 @@ #else # include <curses.h> # include <term.h> - -/* curses.h has just poluted our namespace. We want this back */ -# undef buttons #endif #include <ctype.h> @@ -27,563 +24,607 @@ * vector to store an extent map after the database is loaded. */ -typedef enum { - TYPE_KEY, - TYPE_ARR, - TYPE_MOUSE, -} trie_nodetype; - -struct trie_node { - trie_nodetype type; -}; - -struct trie_node_key { - trie_nodetype type; - struct keyinfo key; -}; - -struct trie_node_arr { - trie_nodetype type; - unsigned char min, max; /* INCLUSIVE endpoints of the extent range */ - struct trie_node *arr[]; /* dynamic size at allocation time */ -}; - -typedef struct { - TermKey *tk; +typedef enum +{ + TYPE_KEY, + TYPE_ARRAY, + TYPE_MOUSE, +} +trie_nodetype_t; - struct trie_node *root; +typedef struct trie_node +{ + trie_nodetype_t type; +} +trie_node_t; - char *start_string; - char *stop_string; -} TermKeyTI; +typedef struct trie_node_key +{ + trie_nodetype_t type; + keyinfo_t key; +} +trie_node_key_t; -static int funcname2keysym(const char *funcname, TermKeyType *typep, TermKeySym *symp, int *modmask, int *modsetp); -static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node); +typedef struct trie_node_array +{ + trie_nodetype_t type; + unsigned char min, max; /* INCLUSIVE endpoints of the extent range */ + trie_node_t *arr[]; /* dynamic size at allocation time */ +} +trie_node_array_t; -static struct trie_node *new_node_key(TermKeyType type, TermKeySym sym, int modmask, int modset) +typedef struct { - struct trie_node_key *n = malloc(sizeof(*n)); - if(!n) - return NULL; + termkey_t *tk; + trie_node_t *root; - n->type = TYPE_KEY; + char *start_string; + char *stop_string; +} +termkey_ti_t; - n->key.type = type; - n->key.sym = sym; - n->key.modifier_mask = modmask; - n->key.modifier_set = modset; +static int funcname2keysym (const char *funcname, termkey_type_t *typep, + termkey_sym_t *symp, int *modmask, int *modsetp); +static int insert_seq (termkey_ti_t *ti, const char *seq, trie_node_t *node); - return (struct trie_node*)n; +static trie_node_t * +new_node_key (termkey_type_t type, termkey_sym_t sym, int modmask, int modset) +{ + trie_node_key_t *n = malloc (sizeof *n); + if (!n) + return NULL; + + n->type = TYPE_KEY; + n->key.type = type; + n->key.sym = sym; + n->key.modifier_mask = modmask; + n->key.modifier_set = modset; + return (trie_node_t *) n; } -static struct trie_node *new_node_arr(unsigned char min, unsigned char max) +static trie_node_t * +new_node_arr (unsigned char min, unsigned char max) { - struct trie_node_arr *n = malloc(sizeof(*n) + ((int)max-min+1) * sizeof(n->arr[0])); - if(!n) - return NULL; + trie_node_array_t *n = malloc (sizeof *n + + ((int) max - min + 1) * sizeof n->arr[0]); + if (!n) + return NULL; - n->type = TYPE_ARR; - n->min = min; n->max = max; + n->type = TYPE_ARRAY; + n->min = min; + n->max = max; - int i; - for(i = min; i <= max; i++) - n->arr[i-min] = NULL; + int i; + for (i = min; i <= max; i++) + n->arr[i - min] = NULL; - return (struct trie_node*)n; + return (trie_node_t *) n; } -static struct trie_node *lookup_next(struct trie_node *n, unsigned char b) +static trie_node_t * +lookup_next (trie_node_t *n, unsigned char b) { - switch(n->type) { - case TYPE_KEY: - case TYPE_MOUSE: - fprintf(stderr, "ABORT: lookup_next within a TYPE_KEY node\n"); - abort(); - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - if(b < nar->min || b > nar->max) - return NULL; - return nar->arr[b - nar->min]; - } - } - - return NULL; // Never reached but keeps compiler happy + switch (n->type) + { + case TYPE_KEY: + case TYPE_MOUSE: + // FIXME + fprintf (stderr, "ABORT: lookup_next within a TYPE_KEY node\n"); + abort (); + case TYPE_ARRAY: + { + trie_node_array_t *nar = (trie_node_array_t *) n; + if (b < nar->min || b > nar->max) + return NULL; + return nar->arr[b - nar->min]; + } + } + + return NULL; // Never reached but keeps compiler happy } -static void free_trie(struct trie_node *n) +static void +free_trie (trie_node_t *n) { - switch(n->type) { - case TYPE_KEY: - case TYPE_MOUSE: - break; - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - int i; - for(i = nar->min; i <= nar->max; i++) - if(nar->arr[i - nar->min]) - free_trie(nar->arr[i - nar->min]); - break; - } - } - - free(n); + switch (n->type) + { + case TYPE_KEY: + case TYPE_MOUSE: + break; + case TYPE_ARRAY: + { + trie_node_array_t *nar = (trie_node_array_t *) n; + int i; + for (i = nar->min; i <= nar->max; i++) + if (nar->arr[i - nar->min]) + free_trie (nar->arr[i - nar->min]); + } + } + free (n); } -static struct trie_node *compress_trie(struct trie_node *n) +static trie_node_t * +compress_trie (struct trie_node *n) { - if(!n) - return NULL; - - switch(n->type) { - case TYPE_KEY: - case TYPE_MOUSE: - return n; - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)n; - unsigned char min, max; - // Find the real bounds - for(min = 0; !nar->arr[min]; min++) - ; - for(max = 0xff; !nar->arr[max]; max--) - ; - - struct trie_node_arr *new = (struct trie_node_arr*)new_node_arr(min, max); - int i; - for(i = min; i <= max; i++) - new->arr[i - min] = compress_trie(nar->arr[i]); - - free(nar); - return (struct trie_node*)new; - } - } - - return n; + if (!n) + return NULL; + + switch (n->type) + { + case TYPE_KEY: + case TYPE_MOUSE: + return n; + case TYPE_ARRAY: + { + trie_node_array_t *nar = (trie_node_array_t *) n; + // Find the real bounds + unsigned char min, max; + for (min = 0; !nar->arr[min]; min++) + ; + for (max = 0xff; !nar->arr[max]; max--) + ; + + trie_node_array_t *new = (trie_node_array_t *) new_node_arr (min, max); + int i; + for (i = min; i <= max; i++) + new->arr[i - min] = compress_trie (nar->arr[i]); + + free (nar); + return (trie_node_t *) new; + } + } + return n; } -static int load_terminfo(TermKeyTI *ti, const char *term) +static int +load_terminfo (termkey_ti_t *ti, const char *term) { - int i; + int i; #ifdef HAVE_UNIBILIUM - unibi_term *unibi = unibi_from_term(term); - if(!unibi) - return 0; + unibi_term *unibi = unibi_from_term (term); + if (!unibi) + return 0; #else - int err; + int err; - /* Have to cast away the const. But it's OK - we know terminfo won't really - * modify term */ - if(setupterm((char*)term, 1, &err) != OK) - return 0; + /* Have to cast away the const. But it's OK - we know terminfo won't really + * modify term */ + if (setupterm ((char *) term, 1, &err) != OK) + return 0; #endif #ifdef HAVE_UNIBILIUM - for(i = unibi_string_begin_+1; i < unibi_string_end_; i++) + for (i = unibi_string_begin_ + 1; i < unibi_string_end_; i++) #else - for(i = 0; strfnames[i]; i++) + for (i = 0; strfnames[i]; i++) #endif - { - // Only care about the key_* constants + { + // Only care about the key_* constants #ifdef HAVE_UNIBILIUM - const char *name = unibi_name_str(i); + const char *name = unibi_name_str (i); #else - const char *name = strfnames[i]; + const char *name = strfnames[i]; #endif - if(strncmp(name, "key_", 4) != 0) - continue; + if (strncmp (name, "key_", 4) != 0) + continue; #ifdef HAVE_UNIBILIUM - const char *value = unibi_get_str(unibi, i); + const char *value = unibi_get_str (unibi, i); #else - const char *value = tigetstr(strnames[i]); + const char *value = tigetstr (strnames[i]); #endif - if(!value || value == (char*)-1) - continue; - - struct trie_node *node = NULL; - - if(strcmp(name + 4, "mouse") == 0) { - node = malloc(sizeof(*node)); - if(!node) - return 0; - - node->type = TYPE_MOUSE; - } - else { - TermKeyType type; - TermKeySym sym; - int mask = 0; - int set = 0; - - if(!funcname2keysym(name + 4, &type, &sym, &mask, &set)) - continue; - - if(sym == TERMKEY_SYM_NONE) - continue; - - node = new_node_key(type, sym, mask, set); - } - - if(node) - if(!insert_seq(ti, value, node)) { - free(node); - return 0; - } - } - - /* Take copies of these terminfo strings, in case we build multiple termkey - * instances for multiple different termtypes, and it's different by the - * time we want to use it - */ + if (!value || value == (char*) -1) + continue; + + struct trie_node *node = NULL; + if (strcmp (name + 4, "mouse") == 0) + { + node = malloc (sizeof *node); + if (!node) + return 0; + + node->type = TYPE_MOUSE; + } + else + { + termkey_type_t type; + termkey_sym_t sym; + int mask = 0; + int set = 0; + + if (!funcname2keysym (name + 4, &type, &sym, &mask, &set)) + continue; + + if (sym == TERMKEY_SYM_NONE) + continue; + + node = new_node_key (type, sym, mask, set); + } + + if (node && !insert_seq (ti, value, node)) + { + free(node); + return 0; + } + } + + /* Take copies of these terminfo strings, in case we build multiple termkey + * instances for multiple different termtypes, and it's different by the + * time we want to use it + */ #ifdef HAVE_UNIBILIUM - const char *keypad_xmit = unibi_get_str(unibi, unibi_pkey_xmit); + const char *keypad_xmit = unibi_get_str (unibi, unibi_pkey_xmit); #endif - if(keypad_xmit) - ti->start_string = strdup(keypad_xmit); - else - ti->start_string = NULL; + if (keypad_xmit) + ti->start_string = strdup (keypad_xmit); + else + ti->start_string = NULL; #ifdef HAVE_UNIBILIUM - const char *keypad_local = unibi_get_str(unibi, unibi_pkey_local); + const char *keypad_local = unibi_get_str (unibi, unibi_pkey_local); #endif - if(keypad_local) - ti->stop_string = strdup(keypad_local); - else - ti->stop_string = NULL; + if (keypad_local) + ti->stop_string = strdup (keypad_local); + else + ti->stop_string = NULL; #ifdef HAVE_UNIBILIUM - unibi_destroy(unibi); + unibi_destroy (unibi); #endif - return 1; + return 1; } -static void *new_driver(TermKey *tk, const char *term) +static void * +new_driver (termkey_t *tk, const char *term) { - TermKeyTI *ti = malloc(sizeof *ti); - if(!ti) - return NULL; - - ti->tk = tk; + termkey_ti_t *ti = malloc (sizeof *ti); + if (!ti) + return NULL; - ti->root = new_node_arr(0, 0xff); - if(!ti->root) - goto abort_free_ti; + ti->tk = tk; + ti->root = new_node_arr (0, 0xff); + if (!ti->root) + goto abort_free_ti; - if(!load_terminfo(ti, term)) - goto abort_free_trie; + if (!load_terminfo (ti, term)) + goto abort_free_trie; - ti->root = compress_trie(ti->root); - - return ti; + ti->root = compress_trie (ti->root); + return ti; abort_free_trie: - free_trie(ti->root); + free_trie(ti->root); abort_free_ti: - free(ti); + free(ti); - return NULL; + return NULL; } -static int start_driver(TermKey *tk, void *info) +static int +start_driver (termkey_t *tk, void *info) { - TermKeyTI *ti = info; - struct stat statbuf; - char *start_string = ti->start_string; - size_t len; - - if(tk->fd == -1 || !start_string) - return 1; - - /* The terminfo database will contain keys in application cursor key mode. - * We may need to enable that mode - */ - - /* There's no point trying to write() to a pipe */ - if(fstat(tk->fd, &statbuf) == -1) - return 0; - - if(S_ISFIFO(statbuf.st_mode)) - return 1; - - // Can't call putp or tputs because they suck and don't give us fd control - len = strlen(start_string); - while(len) { - size_t written = write(tk->fd, start_string, len); - if(written == -1) - return 0; - start_string += written; - len -= written; - } - return 1; + termkey_ti_t *ti = info; + struct stat statbuf; + char *start_string = ti->start_string; + size_t len; + + if (tk->fd == -1 || !start_string) + return 1; + + /* The terminfo database will contain keys in application cursor key mode. + * We may need to enable that mode + */ + + // FIXME: isatty() should suffice + /* There's no point trying to write() to a pipe */ + if (fstat (tk->fd, &statbuf) == -1) + return 0; + + if (S_ISFIFO (statbuf.st_mode)) + return 1; + + // Can't call putp or tputs because they suck and don't give us fd control + len = strlen (start_string); + while (len) + { + size_t written = write (tk->fd, start_string, len); + if (written == -1) + return 0; + start_string += written; + len -= written; + } + return 1; } -static int stop_driver(TermKey *tk, void *info) +// XXX: this is the same as above only with a different string +static int +stop_driver (termkey_t *tk, void *info) { - TermKeyTI *ti = info; - struct stat statbuf; - char *stop_string = ti->stop_string; - size_t len; - - if(tk->fd == -1 || !stop_string) - return 1; - - /* There's no point trying to write() to a pipe */ - if(fstat(tk->fd, &statbuf) == -1) - return 0; - - if(S_ISFIFO(statbuf.st_mode)) - return 1; - - /* The terminfo database will contain keys in application cursor key mode. - * We may need to enable that mode - */ - - // Can't call putp or tputs because they suck and don't give us fd control - len = strlen(stop_string); - while(len) { - size_t written = write(tk->fd, stop_string, len); - if(written == -1) - return 0; - stop_string += written; - len -= written; - } - return 1; + termkey_ti_t *ti = info; + struct stat statbuf; + char *stop_string = ti->stop_string; + size_t len; + + if (tk->fd == -1 || !stop_string) + return 1; + + /* There's no point trying to write() to a pipe */ + if (fstat (tk->fd, &statbuf) == -1) + return 0; + + if (S_ISFIFO (statbuf.st_mode)) + return 1; + + /* The terminfo database will contain keys in application cursor key mode. + * We may need to enable that mode + */ + + // Can't call putp or tputs because they suck and don't give us fd control + len = strlen (stop_string); + while (len) + { + size_t written = write (tk->fd, stop_string, len); + if (written == -1) + return 0; + stop_string += written; + len -= written; + } + return 1; } -static void free_driver(void *info) +static void +free_driver (void *info) { - TermKeyTI *ti = info; - - free_trie(ti->root); - - if(ti->start_string) - free(ti->start_string); - - if(ti->stop_string) - free(ti->stop_string); - - free(ti); + termkey_ti_t *ti = info; + free_trie (ti->root); + free (ti->start_string); + free (ti->stop_string); + free (ti); } #define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) -static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep) +static termkey_result_t +peekkey (termkey_t *tk, void *info, + termkey_key_t *key, int force, size_t *nbytep) { - TermKeyTI *ti = info; - - if(tk->buffcount == 0) - return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; - - struct trie_node *p = ti->root; - - unsigned int pos = 0; - while(pos < tk->buffcount) { - p = lookup_next(p, CHARAT(pos)); - if(!p) - break; - - pos++; - - if(p->type == TYPE_KEY) { - struct trie_node_key *nk = (struct trie_node_key*)p; - key->type = nk->key.type; - key->code.sym = nk->key.sym; - key->modifiers = nk->key.modifier_set; - *nbytep = pos; - return TERMKEY_RES_KEY; - } - else if(p->type == TYPE_MOUSE) { - tk->buffstart += pos; - tk->buffcount -= pos; - - TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep); - - tk->buffstart -= pos; - tk->buffcount += pos; - - if(mouse_result == TERMKEY_RES_KEY) - *nbytep += pos; - - return mouse_result; - } - } - - // If p is not NULL then we hadn't walked off the end yet, so we have a - // partial match - if(p && !force) - return TERMKEY_RES_AGAIN; - - return TERMKEY_RES_NONE; + termkey_ti_t *ti = info; + + if (tk->buffcount == 0) + return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE; + + trie_node_t *p = ti->root; + unsigned int pos = 0; + while (pos < tk->buffcount) + { + p = lookup_next (p, CHARAT (pos)); + if (!p) + break; + + pos++; + + if (p->type == TYPE_KEY) + { + trie_node_key_t *nk = (trie_node_key_t *) p; + key->type = nk->key.type; + key->code.sym = nk->key.sym; + key->modifiers = nk->key.modifier_set; + *nbytep = pos; + return TERMKEY_RES_KEY; + } + else if (p->type == TYPE_MOUSE) + { + tk->buffstart += pos; + tk->buffcount -= pos; + + termkey_result_t mouse_result = + (*tk->method.peekkey_mouse) (tk, key, nbytep); + + tk->buffstart -= pos; + tk->buffcount += pos; + + if (mouse_result == TERMKEY_RES_KEY) + *nbytep += pos; + + return mouse_result; + } + } + + // If p is not NULL then we hadn't walked off the end yet, so we have a + // partial match + if (p && !force) + return TERMKEY_RES_AGAIN; + + return TERMKEY_RES_NONE; } -static struct { - const char *funcname; - TermKeyType type; - TermKeySym sym; - int mods; -} funcs[] = +static struct +{ + const char *funcname; + termkey_type_t type; + termkey_sym_t sym; + int mods; +} +funcs[] = { - /* THIS LIST MUST REMAIN SORTED! */ - { "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 }, - { "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, - { "beg", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, - { "btab", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT }, - { "cancel", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CANCEL, 0 }, - { "clear", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLEAR, 0 }, - { "close", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLOSE, 0 }, - { "command", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COMMAND, 0 }, - { "copy", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COPY, 0 }, - { "dc", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 0 }, - { "down", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 0 }, - { "end", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 0 }, - { "enter", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_ENTER, 0 }, - { "exit", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_EXIT, 0 }, - { "find", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 0 }, - { "help", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HELP, 0 }, - { "home", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 0 }, - { "ic", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 0 }, - { "left", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 0 }, - { "mark", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 }, - { "message", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 }, - { "mouse", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_NONE, 0 }, - { "move", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 }, - { "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, // Not quite, but it's the best we can do - { "npage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, - { "open", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPEN, 0 }, - { "options", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPTIONS, 0 }, - { "ppage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, - { "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, // Not quite, but it's the best we can do - { "print", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PRINT, 0 }, - { "redo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REDO, 0 }, - { "reference", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFERENCE, 0 }, - { "refresh", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFRESH, 0 }, - { "replace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REPLACE, 0 }, - { "restart", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESTART, 0 }, - { "resume", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESUME, 0 }, - { "right", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 0 }, - { "save", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SAVE, 0 }, - { "select", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 0 }, - { "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 }, - { "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 }, - { "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 }, - { NULL }, + /* THIS LIST MUST REMAIN SORTED! */ + { "backspace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BACKSPACE, 0 }, + { "begin", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, + { "beg", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 0 }, + { "btab", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT }, + { "cancel", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CANCEL, 0 }, + { "clear", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLEAR, 0 }, + { "close", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_CLOSE, 0 }, + { "command", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COMMAND, 0 }, + { "copy", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_COPY, 0 }, + { "dc", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 0 }, + { "down", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 0 }, + { "end", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 0 }, + { "enter", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_ENTER, 0 }, + { "exit", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_EXIT, 0 }, + { "find", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 0 }, + { "help", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HELP, 0 }, + { "home", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 0 }, + { "ic", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 0 }, + { "left", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 0 }, + { "mark", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MARK, 0 }, + { "message", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MESSAGE, 0 }, + { "mouse", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_NONE, 0 }, + { "move", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_MOVE, 0 }, + // Not quite, but it's the best we can do + { "next", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, + { "npage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 0 }, + { "open", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPEN, 0 }, + { "options", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_OPTIONS, 0 }, + { "ppage", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, + // Not quite, but it's the best we can do + { "previous", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 0 }, + { "print", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PRINT, 0 }, + { "redo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REDO, 0 }, + { "reference", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFERENCE, 0 }, + { "refresh", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REFRESH, 0 }, + { "replace", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_REPLACE, 0 }, + { "restart", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESTART, 0 }, + { "resume", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RESUME, 0 }, + { "right", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 0 }, + { "save", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SAVE, 0 }, + { "select", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 0 }, + { "suspend", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SUSPEND, 0 }, + { "undo", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UNDO, 0 }, + { "up", TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 0 }, + { NULL }, }; -static int funcname2keysym(const char *funcname, TermKeyType *typep, TermKeySym *symp, int *modmaskp, int *modsetp) +static int +funcname2keysym (const char *funcname, + termkey_type_t *typep, termkey_sym_t *symp, int *modmaskp, int *modsetp) { - // Binary search - - int start = 0; - int end = sizeof(funcs)/sizeof(funcs[0]); // is "one past" the end of the range - - while(1) { - int i = (start+end) / 2; - int cmp = strcmp(funcname, funcs[i].funcname); - - if(cmp == 0) { - *typep = funcs[i].type; - *symp = funcs[i].sym; - *modmaskp = funcs[i].mods; - *modsetp = funcs[i].mods; - return 1; - } - else if(end == start + 1) - // That was our last choice and it wasn't it - not found - break; - else if(cmp > 0) - start = i; - else - end = i; - } - - if(funcname[0] == 'f' && isdigit(funcname[1])) { - *typep = TERMKEY_TYPE_FUNCTION; - *symp = atoi(funcname + 1); - return 1; - } - - // Last-ditch attempt; maybe it's a shift key? - if(funcname[0] == 's' && funcname2keysym(funcname + 1, typep, symp, modmaskp, modsetp)) { - *modmaskp |= TERMKEY_KEYMOD_SHIFT; - *modsetp |= TERMKEY_KEYMOD_SHIFT; - return 1; - } + // Binary search + + int start = 0; + int end = sizeof funcs / sizeof funcs[0]; + // is "one past" the end of the range + + // XXX: bsearch()? + while (1) + { + int i = (start + end) / 2; + int cmp = strcmp (funcname, funcs[i].funcname); + + if (cmp == 0) + { + *typep = funcs[i].type; + *symp = funcs[i].sym; + *modmaskp = funcs[i].mods; + *modsetp = funcs[i].mods; + return 1; + } + else if (end == start + 1) + // That was our last choice and it wasn't it - not found + break; + else if (cmp > 0) + start = i; + else + end = i; + } + + if (funcname[0] == 'f' && isdigit (funcname[1])) + { + *typep = TERMKEY_TYPE_FUNCTION; + // FIXME + *symp = atoi (funcname + 1); + return 1; + } + + // Last-ditch attempt; maybe it's a shift key? + if (funcname[0] == 's' && funcname2keysym + (funcname + 1, typep, symp, modmaskp, modsetp)) + { + *modmaskp |= TERMKEY_KEYMOD_SHIFT; + *modsetp |= TERMKEY_KEYMOD_SHIFT; + return 1; + } #ifdef DEBUG - fprintf(stderr, "TODO: Need to convert funcname %s to a type/sym\n", funcname); + fprintf (stderr, "TODO: Need to convert funcname %s to a type/sym\n", funcname); #endif - return 0; + return 0; } -static int insert_seq(TermKeyTI *ti, const char *seq, struct trie_node *node) +static int +insert_seq (termkey_ti_t *ti, const char *seq, trie_node_t *node) { - int pos = 0; - struct trie_node *p = ti->root; - - // Unsigned because we'll be using it as an array subscript - unsigned char b; - - while((b = seq[pos])) { - struct trie_node *next = lookup_next(p, b); - if(!next) - break; - p = next; - pos++; - } - - while((b = seq[pos])) { - struct trie_node *next; - if(seq[pos+1]) - // Intermediate node - next = new_node_arr(0, 0xff); - else - // Final key node - next = node; - - if(!next) - return 0; - - switch(p->type) { - case TYPE_ARR: - { - struct trie_node_arr *nar = (struct trie_node_arr*)p; - if(b < nar->min || b > nar->max) { - fprintf(stderr, "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n", - b, nar->min, nar->max); - abort(); - } - nar->arr[b - nar->min] = next; - p = next; - break; - } - case TYPE_KEY: - case TYPE_MOUSE: - fprintf(stderr, "ASSERT FAIL: Tried to insert child node in TYPE_KEY\n"); - abort(); - } - - pos++; - } - - return 1; + int pos = 0; + trie_node_t *p = ti->root; + + // Unsigned because we'll be using it as an array subscript + unsigned char b; + + while ((b = seq[pos])) + { + trie_node_t *next = lookup_next (p, b); + if (!next) + break; + p = next; + pos++; + } + + while ((b = seq[pos])) + { + trie_node_t *next; + if (seq[pos+1]) + // Intermediate node + next = new_node_arr (0, 0xff); + else + // Final key node + next = node; + + if (!next) + return 0; + + switch (p->type) + { + case TYPE_ARRAY: + { + trie_node_array_t *nar = (trie_node_array_t *) p; + if (b < nar->min || b > nar->max) + { + // FIXME + fprintf (stderr, "ASSERT FAIL: Trie insert at 0x%02x is outside of extent bounds (0x%02x..0x%02x)\n", + b, nar->min, nar->max); + abort (); + } + nar->arr[b - nar->min] = next; + p = next; + break; + } + case TYPE_KEY: + case TYPE_MOUSE: + // FIXME + fprintf (stderr, "ASSERT FAIL: Tried to insert child node in TYPE_KEY\n"); + abort (); + } + + pos++; + } + return 1; } -struct TermKeyDriver termkey_driver_ti = { - .name = "terminfo", +termkey_driver_t termkey_driver_ti = +{ + .name = "terminfo", - .new_driver = new_driver, - .free_driver = free_driver, + .new_driver = new_driver, + .free_driver = free_driver, - .start_driver = start_driver, - .stop_driver = stop_driver, + .start_driver = start_driver, + .stop_driver = stop_driver, - .peekkey = peekkey, + .peekkey = peekkey, }; |