|
|
coherent
/*
* This program is in public domain; written by Dave G. Conroy.
* This file contains the functions that bind keys to macros and functions,
* as well as the execution of macros and functions.
* code, for the MicroEMACS screen editor.
*/
#include <stdio.h>
#include "ed.h"
BIND bind;
short *kbdm; /* Current Macro */
unsigned kbdlen; /* Curent Macro len in bytes */
short *kbdmip; /* Input for above */
short *kbdmop; /* Output for above */
int thisflag; /* Flags, this command */
int lastflag; /* Flags, last command */
extern char *realloc();
extern FILE *ffp;
/*
* find keybinding or return NULL
*/
static KEYTAB *
findBind(c, tab)
int c;
KEYTAB *tab;
{
register KEYTAB *ktp;
register int i;
for (i = c % HASHP; -1 != i; i = ktp->k_synonym)
if ((ktp = tab + i)->k_code == c)
return (ktp);
return (NULL);
}
/*
* This is the general command execution routine.
* It handles the fake binding of all the keys to "self-insert".
* It also clears out the "thisflag" word, and arranges to move it
* to the "lastflag", so that the next command can look at it.
* Return the status of command.
*/
execute(c, f, n)
register int c;
{
register KEYTAB *ktp;
int status;
if ((NULL != (ktp = findBind(c, bind.table))) ||
(NULL != (ktp = findBind((c & ~OBND), keytab)))) {
thisflag = 0;
status = (ktp->k_fun < 0) ?
doMac(bind.macs - (2 + ktp->k_fun), f, n) :
(*(funtab[ktp->k_fun].f_fp))(f, n);
lastflag = thisflag;
return (status);
}
if (c >= 0x20 && c <= 0xFF) { /* Self inserting. */
if (n <= 0) { /* Fenceposts. */
lastflag = 0;
return (n<0 ? FALSE : TRUE);
}
thisflag = 0; /* For the future. */
status = linsert(n, c);
lastflag = thisflag;
/*
* If fill column is defined perform word wrap.
*/
if (bind.fillcol)
wrapword();
return (status);
}
lastflag = 0; /* Fake last flags. */
return (FALSE);
}
/*
* Begin a keyboard macro.
* Error if not at the top level in keyboard processing.
* Set up variables and return.
*/
ctlxlp(f, n)
{
if (kbdmip!=NULL) {
mlwrite("Not now");
return (FALSE);
}
if (NULL != kbdm)
free(kbdm);
mlwrite("[Start macro]");
if (NULL == (kbdmip = kbdm = malloc(kbdlen = NKBDM))) {
mlwrite("Out of space");
return (FALSE);
}
return (TRUE);
}
/*
* End keyboard macro. Check for the same limit conditions as the
* above routine. Set up the variables and return to the caller.
*/
ctlxrp(f, n)
{
if (kbdmip == NULL) {
mlwrite("Not now");
return (FALSE);
}
mlwrite("[End macro]");
kbdmip[-1] = -1; /* unique end marker */
*kbdmip++ = 0;
kbdm = realloc(kbdm, kbdlen = ((char *)kbdmip) - ((char *)kbdm));
kbdmip = NULL;
return (TRUE);
}
/*
* Execute default macro.
*/
ctlxe(f, n)
{
if (kbdmip!=NULL) { /* close macro first */
mlwrite("Not now");
return (FALSE);
}
return (doMac(&kbdm, f, n));
}
/*
* Get a keybinding and remove it.
* return the binding.
*/
static
unBind(c)
{
register short i;
register KEYTAB *ktp;
mlerase();
if (NULL == (ktp = findBind(c, bind.table)))
return;
if ((i = ktp->k_fun) < 0) {
free(bind.macs[i = -(2 + i)]);
bind.macs[i] = NULL;
bind.maclen[i] = 0;
}
if (-1 != (i = ktp->k_synonym)) {
memcpy(ktp, (bind.table + i), sizeof(*ktp));
bind.table[i].k_code = bind.table[i].k_synonym = -1;
}
else
ktp->k_code = -1;
}
/*
* Create a new binding in bind.table.
*/
static
reBind(c, i)
{
register KEYTAB *ktp, *kh;
kh = ktp = bind.table + (c % HASHP);
if (-1 != ktp->k_code) {
for (ktp = bind.table + MAXREB; --ktp >= bind.table; )
if (-1 == ktp->k_code)
break;
if (ktp < bind.table) {
mlwrite("No free spaces in mod tab");
return (FALSE);
}
ktp->k_synonym = kh->k_synonym;
kh->k_synonym = ktp - bind.table;
}
ktp->k_code = c;
ktp->k_fun = i;
return (TRUE);
}
/*
* Bind a function PFX1|'R' to another function.
*/
bindFun()
{
register int c, d;
register KEYTAB *ktp;
mlwrite("Enter old keybinding ");
d = getbind(0);
ktp = findBind(d, keytab);
mlwrite("Enter new keybinding ");
if ((PFX1|'R') == (c = getbind(0))) {
mlwrite("Cannot rebind <ctl>-x r");
return (FALSE);
}
if (d == c) {
unBind(c);
return (TRUE);
}
if (NULL == ktp) {
mlwrite("Non existant binding");
return (FALSE);
}
unBind(c);
return (reBind(c, ktp->k_fun));
}
/*
* Load flexable bindings from file.
*/
loadBinds()
{
uchar fname[NFILEN];
if (mlreply("Load bindings file: ", fname, NFILEN) != TRUE)
return (FALSE);
return (loadBup(fname, FALSE));
}
/*
* report io error in various ways.
*/
ioTrouble(fname, startsw)
uchar *fname;
{
switch (startsw) {
case FALSE: /* callec from ctl-x l */
mlwrite("I/O toruble with %s", fname);
return (FALSE);
case ABORT: /* called from -f switch */
fprintf(stderr, "I/O trouble with %s\n", fname);
exit(1);
case TRUE: /* default bindings file */
return (TRUE);
}
}
/*
* Actual work of load bindings.
*/
loadBup(fname, startsw)
uchar *fname;
{
register int i;
short magic;
if (((ffp=fopen(fname, "rb")) == NULL) ||
(1 != fread(&magic, sizeof(magic), 1, ffp)) ||
(magic != BINDID))
return (ioTrouble(fname, startsw));
if (1 != fread(&bind, sizeof(bind), 1, ffp))
return (ioTrouble(fname, ABORT));
for (i = 0; i < (MAXMAC + 2); i++) {
if (NULL != bind.macs[i]) {
if (NULL == (bind.macs[i] = malloc(bind.maclen[i]))) {
mlwrite("Out of memory");
for (; i <= MAXMAC; i++)
bind.macs[i] = NULL;
return (FALSE);
}
if (1 != fread(bind.macs[i], bind.maclen[i], 1, ffp))
return (ioTrouble(fname, ABORT));
}
}
if (NULL != bind.macs[MAXMAC+1]) {
if (NULL != kbdm)
free(kbdm);
kbdmip = NULL;
kbdm = bind.macs[MAXMAC+1];
kbdlen = bind.maclen[MAXMAC+1];
}
ffclose();
return (TRUE);
}
/*
* Store flexable bindings to a file.
*/
storBinds()
{
register int i;
static short magic = BINDID;
uchar fname[NFILEN];
if (mlreply("Store bindings file: ", fname, NFILEN) != TRUE)
return (FALSE);
if (FIOSUC != ffwopen(fname, "wb"))
return (FALSE);
if (kbdmip != NULL || kbdm == NULL) /* store closed mac only */
bind.macs[MAXMAC+1] = NULL;
else {
bind.macs[MAXMAC+1] = kbdm;
bind.maclen[MAXMAC+1] = kbdlen;
}
fwrite(&magic, sizeof(magic), 1, ffp);
fwrite(&bind, sizeof(bind), 1, ffp);
for (i = 0; i < (MAXMAC + 2); i++)
if (NULL != bind.macs[i])
fwrite(bind.macs[i], bind.maclen[i], 1, ffp);
ffclose();
}
/*
* declare macro to be a binding. PFX1|'M'
*/
nameMac()
{
register int i, c;
if (kbdmip != NULL)
ctlxrp();
if (kbdm == NULL) {
mlwrite("Not now");
return (FALSE);
}
mlwrite("Enter keybinding for macro ");
if ((PFX1|'R') == (c = getbind(0))) {
mlwrite("Cannot rebind <ctl>-x r");
return (FALSE);
}
unBind(c);
for (i = 0; (i < MAXMAC) && (NULL != bind.macs[i]); i++)
;
if (MAXMAC == i) {
mlwrite("Too many macros bound");
return (FALSE);
}
if (reBind(c, -(i + 2)) == FALSE)
return (FALSE);
bind.macs[i] = kbdm;
bind.maclen[i] = kbdlen;
kbdm = NULL;
kbdlen = 0;
return (TRUE);
}
/*
* Bind current macro to initialization macro.
*/
initMac()
{
if (kbdmip!=NULL || kbdmop!=NULL) {
mlwrite("Not now");
return (FALSE);
}
bind.macs[MAXMAC] = kbdm;
bind.maclen[MAXMAC] = kbdlen;
kbdm = NULL;
kbdlen = 0;
mlwrite("init mac bound");
return (TRUE);
}
/*
* Execute a macro.
* The command argument is the number of times to loop. Quit as
* soon as a command gets an error.
* Return TRUE if all ok, else FALSE.
*/
doMac(macro, f, n)
uchar **macro;
{
register int c;
register int af;
register int an;
register int s;
short *kbdsav;
uchar *macsav;
if (!n)
return (TRUE);
if (NULL == (macsav = *macro)) {
mlwrite("Not now");
return (FALSE);
}
*macro = NULL; /* prevent regress */
kbdsav = kbdmop;
do {
kbdmop = macsav;
do {
af = FALSE;
an = 1;
if ((c = *kbdmop++) == bind.repeat) {
af = TRUE;
an = *kbdmop++;
c = *kbdmop++;
}
s = TRUE;
} while ((c != -1) && (s = execute(c, af, an)) == TRUE);
} while ((s == TRUE) && ((-1 == n) || --n));
if (-1 == n)
s = TRUE;
kbdmop = kbdsav;
*macro = macsav;
return (s);
}
static
setpf(loc, no)
int *loc, no;
{
mlwrite("Enter prefix character %d or space ", no);
if (' ' != (no = getkey()))
*loc = no;
}
/*
* Set prefix characters.
*/
setPrefix()
{
int c;
setpf(&bind.pfx1, 1);
setpf(&bind.pfx2, 2);
setpf(&bind.pfx3, 3);
mlwrite("Enter repeat code or space ");
if (' ' != (c = getkey()))
bind.repeat = c;
mlerase();
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.