home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d3xx
/
d352
/
mg.lha
/
MG
/
src.LZH
/
mg
/
bind.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-23
|
9KB
|
342 lines
/*
* 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);
}