home *** CD-ROM | disk | FTP | other *** search
- /*
- * Key binding & rebinding & unbinding.
- */
- #include "no_macro.h"
-
- #include "def.h"
- #include "kbd.h"
- #include "buffer.h"
-
- #ifndef NO_MACRO
- #include "macro.h"
- #endif
-
- #ifdef ANSI
- #include <stdlib.h>
- #include <string.h>
- #endif
-
- static int remap
- PROTO((struct keymap * curmap, int c, struct function * funct));
- static int dobind
- PROTO((struct keymap * curmap, char *p, int unbind));
- static int growelement
- PROTO((struct keymap *, struct map_element *, int));
- static int initelement
- PROTO((struct keymap *, struct map_element *, int));
- static struct keymap *realocmap
- PROTO((struct keymap * curmap));
- static VOID fixmap
- PROTO((struct keymap *, struct keymap *, struct keymap *));
-
- /*
- * Bind a key to a function. No attempt is made to reclaim space no longer
- * used, if this is a problem flags must be added to indicate malloced verses
- * static storage in both keymaps and map_elements.
- */
- static int
- remap(curmap, c, funct)
- register struct keymap *curmap;
- int c;
- struct function *funct;
- {
- extern struct map_element *ele;
-
- /*
- * At this point, we know that A) curmap is the map that's going to
- * be changed; B) c is the key that's going to change in that map; C)
- * ele is one of three things: 1) beyond the end of the map, 2) above
- * c, and the preceeding element is below it, or 3) the element that
- * needs to be changed.
- *
- * We deal with this by changing the map for case 1 & 2, and then
- * letting the case 3 code deal with the changes.
- */
-
- if (ele >= &curmap->map_element[curmap->map_num]) {
- /*
- * Case 1: ele is past the end of the map. In this case, we
- * try to grow the last element to encompass the char if it's
- * close enough. If it isn't, we create a new map element,
- * and put the the char in that.
- */
- if ((--ele)->k_num + MAPELEDEF >= c) {
- if (growelement(curmap, ele, c) == NULL)
- return FALSE;
- } else if ((curmap = realocmap(curmap)) == NULL)
- return FALSE;
- else if (initelement(curmap, ++ele, c) == FALSE)
- return FALSE;
- else
- curmap->map_num += 1;
- } else if (c < ele->k_base) {
- /*
- * Case 2: c lands between map elements. Ele points to the
- * next one. As before, but with three cases: try to grow ele
- * down to c; try to grow ele - 1 up to c; and if all else
- * fails, get a new element inited for c put between them.
- */
-
- if (ele->k_base <= c + MAPELEDEF) {
- if (growelement(curmap, ele, c) == FALSE)
- return FALSE;
- } else if (ele > curmap->map_element
- && ele[-1].k_num + MAPELEDEF >= c) {
- if (growelement(curmap, --ele, c) == FALSE)
- return FALSE;
- } else if ((curmap = realocmap(curmap)) == NULL)
- return FALSE;
- else {
- /*
- * adding a new element to the map. If this code
- * didn't leak memory already, I'd seriously consider
- * checking on the possiblities of an element merge
- * here.
- */
- struct map_element save;
- register struct map_element *ep;
-
- if (initelement(curmap, &save, c) == FALSE)
- return FALSE;
-
- /* Shuffle upper elements up */
- for (ep = &curmap->map_element[curmap->map_num]; ep > ele; ep -= 1)
- ep[0] = ep[-1];
- *ep = save;
- curmap->map_num += 1;
- }
- }
- /*
- * Case 3: Just change the key in the existing map. The other two
- * cases twiddle the kemap so it's right, then fall through to this
- * code.
- */
- ele->k_entry[c - ele->k_base] = *funct;
- return TRUE;
- }
-
- /*
- * growelement - grow an element up/down to encompass the given character,
- * shuffling things as needed. We don't check the reasonableness of doing
- * that extension, as the caller (which should only be remap) has to do that
- * before calling us.
- */
- static int
- growelement(curmap, ele, c)
- struct keymap *curmap;
- register struct map_element *ele;
- register int c;
- {
- register int newnum, newbase, i;
- register struct function *fp;
-
- if (c < ele->k_base) { /* growing down */
- newbase = c;
- newnum = ele->k_num;
- } else { /* Growing up */
- newbase = ele->k_base;
- newnum = c;
- }
-
- if ((fp = (struct function *)
- malloc((newnum - newbase + 1) * sizeof(struct function))) == NULL) {
- ewprintf("Out of memory");
- return FALSE;
- }
- for (i = newbase; i < ele->k_base; i += 1)
- fp[i - newbase] = *curmap->map_default;
- for (; i <= ele->k_num; i += 1)
- fp[i - newbase] = ele->k_entry[i - ele->k_base];
- for (; i < newnum; i += 1)
- fp[i - newbase] = *curmap->map_default;
-
- ele->k_entry = fp;
- ele->k_base = newbase;
- ele->k_num = newnum;
- return TRUE;
- }
-
- /*
- * initelement sets up the existing element pointer as apropos for the
- * character and map it just got passed.
- */
- static int
- initelement(curmap, ele, c)
- struct keymap *curmap;
- register struct map_element *ele;
- int c;
- {
- register struct function *fp;
-
- if ((fp = (struct function *) malloc(sizeof(struct function))) == NULL)
- return FALSE;
- ele->k_base = c;
- ele->k_num = c;
- ele->k_entry = fp;
- return TRUE;
- }
-
- /*
- * Adds another element to the map - moving it if necessary. Also makes sure
- * that the global ele points to the same place afterwards.
- */
- static struct keymap *
- realocmap(curmap)
- register struct keymap *curmap;
- {
- register struct keymap *mp;
- register int i;
- extern int nmaps;
-
-
- if (curmap->map_num < curmap->map_max)
- return curmap;
-
- if ((mp = (struct keymap *) malloc((unsigned) (sizeof(struct keymap) +
- (curmap->map_max + MAPGROW - 1) * sizeof(struct map_element)))) == NULL) {
- ewprintf("Out of memory");
- return NULL;
- }
- mp->map_num = curmap->map_num;
- mp->map_max = curmap->map_max + MAPGROW;
- mp->map_default = curmap->map_default;
-
- for (i = curmap->map_num; i--;)
- mp->map_element[i] = curmap->map_element[i];
-
- for (i = nmaps; i--;) {
- if (map_table[i].p_map == curmap)
- map_table[i].p_map = mp;
- else
- fixmap(curmap, mp, map_table[i].p_map);
- }
- ele = &mp->map_element[ele - &curmap->map_element[0]];
- return mp;
- }
-
- /* fix references to a realocated keymap (recursive) */
- static VOID
- fixmap(curmap, mp, mt)
- struct keymap *curmap, *mp;
- register struct keymap *mt;
- {
- register int i, j;
- register struct map_element *ele;
- register struct function *fp;
-
- for (i = mt->map_num; i--;) {
- ele = &(mt->map_element[i]);
- for (j = ele->k_num; j >= ele->k_base; j -= 1) {
- fp = &(ele->k_entry[j - ele->k_base]);
- if (fp->f_type == F_PREFIX)
- if ((struct keymap *) fp->f_pref == curmap)
- fp->f_pref = (int (*) ()) mp;
- else
- fixmap(curmap, mp, (struct keymap *) fp->f_pref);
- }
- }
- }
-
- /*
- * do the input for local-set-key, global-set-key and define-key then call
- * remap to do the work.
- */
- static int
- dobind(curmap, p, unbind)
- register struct keymap *curmap;
- char *p;
- int unbind;
- {
- char prompt[80];
- char *pep;
- int c;
- int s;
- int rescan();
- struct function funct;
-
- (VOID) strcpy(prompt, p);
- pep = prompt + strlen(prompt);
- for (;;) {
- ewprintf("%s", prompt);
- pep[-1] = ' ';
- pep = keyname(pep, c = getkey(DISSCR));
- funct = *doscan(curmap, c);
- if (funct.f_type != F_PREFIX)
- break;
- *pep++ = '-';
- *pep = '\0';
- curmap = (struct keymap *) funct.f_pref;
- }
- if (unbind)
- funct.f_funcp = rescan;
- else {
- if ((s = eread("%s to command: ", prompt, 80, EFFUNC | EFNEW, prompt))
- != TRUE)
- return s;
- if ((funct.f_funcp = name_function(prompt)) != NULL)
- funct.f_type = F_CFUNCT;
- #ifndef NO_MACRO
- else if ((funct.f_macro = (int (*) ()) find_macro(prompt)) != NULL)
- funct.f_type = F_MACRO;
- #endif
- else if ((funct.f_pref = (int (*) ()) name_map(prompt)) != NULL)
- funct.f_type = F_PREFIX;
- else {
- ewprintf("[No match]");
- return FALSE;
- }
- }
- return remap(curmap, c, &funct);
- }
- /*
- * This function redefines a key in any keymap.
- */
- /* ARGSUSED */
- define_key(f, n)
- {
- static char buf[48] = "Define key map: ";
- struct maps *mp;
- char *strncat();
-
- buf[16] = '\0';
- if (eread(buf, &buf[16], 48 - 16, EFNEW) != TRUE)
- return FALSE;
- if ((mp = name_mode(&buf[16])) == NULL) {
- ewprintf("Unknown map %s", &buf[16]);
- return FALSE;
- }
- (VOID) strncat(&buf[16], " key: ", 48 - 16 - 1);
- return dobind(mp->p_map, buf, FALSE);
- }
- /*
- * This function modifies the fundamental keyboard map.
- */
- /* ARGSUSED */
- bindtokey(f, n)
- {
- return dobind(map_table[0].p_map, "Global set key: ", FALSE);
- }
-
- /*
- * This function modifies the current mode's keyboard map.
- */
- /* ARGSUSED */
- localbind(f, n)
- {
- return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, "Local set key: ",
- FALSE);
- }
-
- unbindtokey(f, n)
- int f, n;
- {
- return dobind(map_table[0].p_map, "Global unset key: ", TRUE);
- }
-
- localunbind(f, n)
- int f, n;
- {
- return dobind(curbp->b_modes[curbp->b_nmodes]->p_map, "Local unset key: ",
- TRUE);
- }
-