|
|
1.1 root 1: /*
2: * This program is in public domain; written by Dave G. Conroy.
3: * This file contains the functions that bind keys to macros and functions,
4: * as well as the execution of macros and functions.
5: * code, for the MicroEMACS screen editor.
6: */
7: #include <stdio.h>
8: #include "ed.h"
9: BIND bind;
10: short *kbdm; /* Current Macro */
11: unsigned kbdlen; /* Curent Macro len in bytes */
12: short *kbdmip; /* Input for above */
13: short *kbdmop; /* Output for above */
14: int thisflag; /* Flags, this command */
15: int lastflag; /* Flags, last command */
16: extern char *realloc();
17: extern FILE *ffp;
18: /*
19: * find keybinding or return NULL
20: */
21: static KEYTAB *
22: findBind(c, tab)
23: int c;
24: KEYTAB *tab;
25: {
26: register KEYTAB *ktp;
27: register int i;
28:
29: for (i = c % HASHP; -1 != i; i = ktp->k_synonym)
30: if ((ktp = tab + i)->k_code == c)
31: return (ktp);
32: return (NULL);
33: }
34:
35: /*
36: * This is the general command execution routine.
37: * It handles the fake binding of all the keys to "self-insert".
38: * It also clears out the "thisflag" word, and arranges to move it
39: * to the "lastflag", so that the next command can look at it.
40: * Return the status of command.
41: */
42: execute(c, f, n)
43: register int c;
44: {
45: register KEYTAB *ktp;
46: int status;
47:
48: if ((NULL != (ktp = findBind(c, bind.table))) ||
49: (NULL != (ktp = findBind((c & ~OBND), keytab)))) {
50: thisflag = 0;
51: status = (ktp->k_fun < 0) ?
52: doMac(bind.macs - (2 + ktp->k_fun), f, n) :
53: (*(funtab[ktp->k_fun].f_fp))(f, n);
54: lastflag = thisflag;
55: return (status);
56: }
57:
58: if (c >= 0x20 && c <= 0xFF) { /* Self inserting. */
59: if (n <= 0) { /* Fenceposts. */
60: lastflag = 0;
61: return (n<0 ? FALSE : TRUE);
62: }
63: thisflag = 0; /* For the future. */
64: status = linsert(n, c);
65: lastflag = thisflag;
66:
67: /*
68: * If fill column is defined perform word wrap.
69: */
70: if (bind.fillcol)
71: wrapword();
72:
73: return (status);
74: }
75: lastflag = 0; /* Fake last flags. */
76: return (FALSE);
77: }
78:
79: /*
80: * Begin a keyboard macro.
81: * Error if not at the top level in keyboard processing.
82: * Set up variables and return.
83: */
84: ctlxlp(f, n)
85: {
86: if (kbdmip!=NULL) {
87: mlwrite("Not now");
88: return (FALSE);
89: }
90: if (NULL != kbdm)
91: free(kbdm);
92: mlwrite("[Start macro]");
93: if (NULL == (kbdmip = kbdm = malloc(kbdlen = NKBDM))) {
94: mlwrite("Out of space");
95: return (FALSE);
96: }
97: return (TRUE);
98: }
99:
100: /*
101: * End keyboard macro. Check for the same limit conditions as the
102: * above routine. Set up the variables and return to the caller.
103: */
104: ctlxrp(f, n)
105: {
106: if (kbdmip == NULL) {
107: mlwrite("Not now");
108: return (FALSE);
109: }
110: mlwrite("[End macro]");
111: kbdmip[-1] = -1; /* unique end marker */
112: *kbdmip++ = 0;
113: kbdm = realloc(kbdm, kbdlen = ((char *)kbdmip) - ((char *)kbdm));
114: kbdmip = NULL;
115: return (TRUE);
116: }
117:
118: /*
119: * Execute default macro.
120: */
121: ctlxe(f, n)
122: {
123: if (kbdmip!=NULL) { /* close macro first */
124: mlwrite("Not now");
125: return (FALSE);
126: }
127: return (doMac(&kbdm, f, n));
128: }
129:
130: /*
131: * Get a keybinding and remove it.
132: * return the binding.
133: */
134: static
135: unBind(c)
136: {
137: register short i;
138: register KEYTAB *ktp;
139:
140: mlerase();
141: if (NULL == (ktp = findBind(c, bind.table)))
142: return;
143: if ((i = ktp->k_fun) < 0) {
144: free(bind.macs[i = -(2 + i)]);
145: bind.macs[i] = NULL;
146: bind.maclen[i] = 0;
147: }
148: if (-1 != (i = ktp->k_synonym)) {
149: memcpy(ktp, (bind.table + i), sizeof(*ktp));
150: bind.table[i].k_code = bind.table[i].k_synonym = -1;
151: }
152: else
153: ktp->k_code = -1;
154: }
155:
156: /*
157: * Create a new binding in bind.table.
158: */
159: static
160: reBind(c, i)
161: {
162: register KEYTAB *ktp, *kh;
163:
164: kh = ktp = bind.table + (c % HASHP);
165: if (-1 != ktp->k_code) {
166: for (ktp = bind.table + MAXREB; --ktp >= bind.table; )
167: if (-1 == ktp->k_code)
168: break;
169: if (ktp < bind.table) {
170: mlwrite("No free spaces in mod tab");
171: return (FALSE);
172: }
173: ktp->k_synonym = kh->k_synonym;
174: kh->k_synonym = ktp - bind.table;
175: }
176: ktp->k_code = c;
177: ktp->k_fun = i;
178: return (TRUE);
179: }
180:
181: /*
182: * Bind a function PFX1|'R' to another function.
183: */
184: bindFun()
185: {
186: register int c, d;
187: register KEYTAB *ktp;
188:
189: mlwrite("Enter old keybinding ");
190: d = getbind(0);
191: ktp = findBind(d, keytab);
192: mlwrite("Enter new keybinding ");
193: if ((PFX1|'R') == (c = getbind(0))) {
194: mlwrite("Cannot rebind <ctl>-x r");
195: return (FALSE);
196: }
197: if (d == c) {
198: unBind(c);
199: return (TRUE);
200: }
201: if (NULL == ktp) {
202: mlwrite("Non existant binding");
203: return (FALSE);
204: }
205: unBind(c);
206: return (reBind(c, ktp->k_fun));
207: }
208:
209: /*
210: * Load flexable bindings from file.
211: */
212: loadBinds()
213: {
214: uchar fname[NFILEN];
215:
216: if (mlreply("Load bindings file: ", fname, NFILEN) != TRUE)
217: return (FALSE);
218: return (loadBup(fname, FALSE));
219: }
220:
221: /*
222: * report io error in various ways.
223: */
224: ioTrouble(fname, startsw)
225: uchar *fname;
226: {
227: switch (startsw) {
228: case FALSE: /* callec from ctl-x l */
229: mlwrite("I/O toruble with %s", fname);
230: return (FALSE);
231: case ABORT: /* called from -f switch */
232: fprintf(stderr, "I/O trouble with %s\n", fname);
233: exit(1);
234: case TRUE: /* default bindings file */
235: return (TRUE);
236: }
237: }
238: /*
239: * Actual work of load bindings.
240: */
241: loadBup(fname, startsw)
242: uchar *fname;
243: {
244: register int i;
245: short magic;
246:
247: if (((ffp=fopen(fname, "rb")) == NULL) ||
248: (1 != fread(&magic, sizeof(magic), 1, ffp)) ||
249: (magic != BINDID))
250: return (ioTrouble(fname, startsw));
251:
252: if (1 != fread(&bind, sizeof(bind), 1, ffp))
253: return (ioTrouble(fname, ABORT));
254:
255: for (i = 0; i < (MAXMAC + 2); i++) {
256: if (NULL != bind.macs[i]) {
257: if (NULL == (bind.macs[i] = malloc(bind.maclen[i]))) {
258: mlwrite("Out of memory");
259: for (; i <= MAXMAC; i++)
260: bind.macs[i] = NULL;
261: return (FALSE);
262: }
263: if (1 != fread(bind.macs[i], bind.maclen[i], 1, ffp))
264: return (ioTrouble(fname, ABORT));
265: }
266: }
267: if (NULL != bind.macs[MAXMAC+1]) {
268: if (NULL != kbdm)
269: free(kbdm);
270: kbdmip = NULL;
271: kbdm = bind.macs[MAXMAC+1];
272: kbdlen = bind.maclen[MAXMAC+1];
273: }
274: ffclose();
275: return (TRUE);
276: }
277:
278: /*
279: * Store flexable bindings to a file.
280: */
281: storBinds()
282: {
283: register int i;
284: static short magic = BINDID;
285: uchar fname[NFILEN];
286:
287: if (mlreply("Store bindings file: ", fname, NFILEN) != TRUE)
288: return (FALSE);
289: if (FIOSUC != ffwopen(fname, "wb"))
290: return (FALSE);
291: if (kbdmip != NULL || kbdm == NULL) /* store closed mac only */
292: bind.macs[MAXMAC+1] = NULL;
293: else {
294: bind.macs[MAXMAC+1] = kbdm;
295: bind.maclen[MAXMAC+1] = kbdlen;
296: }
297: fwrite(&magic, sizeof(magic), 1, ffp);
298: fwrite(&bind, sizeof(bind), 1, ffp);
299: for (i = 0; i < (MAXMAC + 2); i++)
300: if (NULL != bind.macs[i])
301: fwrite(bind.macs[i], bind.maclen[i], 1, ffp);
302: ffclose();
303: }
304:
305: /*
306: * declare macro to be a binding. PFX1|'M'
307: */
308: nameMac()
309: {
310: register int i, c;
311:
312: if (kbdmip != NULL)
313: ctlxrp();
314: if (kbdm == NULL) {
315: mlwrite("Not now");
316: return (FALSE);
317: }
318: mlwrite("Enter keybinding for macro ");
319: if ((PFX1|'R') == (c = getbind(0))) {
320: mlwrite("Cannot rebind <ctl>-x r");
321: return (FALSE);
322: }
323: unBind(c);
324:
325: for (i = 0; (i < MAXMAC) && (NULL != bind.macs[i]); i++)
326: ;
327: if (MAXMAC == i) {
328: mlwrite("Too many macros bound");
329: return (FALSE);
330: }
331: if (reBind(c, -(i + 2)) == FALSE)
332: return (FALSE);
333: bind.macs[i] = kbdm;
334: bind.maclen[i] = kbdlen;
335: kbdm = NULL;
336: kbdlen = 0;
337: return (TRUE);
338: }
339:
340: /*
341: * Bind current macro to initialization macro.
342: */
343: initMac()
344: {
345: if (kbdmip!=NULL || kbdmop!=NULL) {
346: mlwrite("Not now");
347: return (FALSE);
348: }
349: bind.macs[MAXMAC] = kbdm;
350: bind.maclen[MAXMAC] = kbdlen;
351: kbdm = NULL;
352: kbdlen = 0;
353: mlwrite("init mac bound");
354: return (TRUE);
355: }
356:
357: /*
358: * Execute a macro.
359: * The command argument is the number of times to loop. Quit as
360: * soon as a command gets an error.
361: * Return TRUE if all ok, else FALSE.
362: */
363: doMac(macro, f, n)
364: uchar **macro;
365: {
366: register int c;
367: register int af;
368: register int an;
369: register int s;
370: short *kbdsav;
371: uchar *macsav;
372:
373: if (!n)
374: return (TRUE);
375: if (NULL == (macsav = *macro)) {
376: mlwrite("Not now");
377: return (FALSE);
378: }
379: *macro = NULL; /* prevent regress */
380: kbdsav = kbdmop;
381: do {
382: kbdmop = macsav;
383: do {
384: af = FALSE;
385: an = 1;
386: if ((c = *kbdmop++) == bind.repeat) {
387: af = TRUE;
388: an = *kbdmop++;
389: c = *kbdmop++;
390: }
391: s = TRUE;
392: } while ((c != -1) && (s = execute(c, af, an)) == TRUE);
393: } while ((s == TRUE) && ((-1 == n) || --n));
394: if (-1 == n)
395: s = TRUE;
396: kbdmop = kbdsav;
397: *macro = macsav;
398: return (s);
399: }
400:
401: static
402: setpf(loc, no)
403: int *loc, no;
404: {
405: mlwrite("Enter prefix character %d or space ", no);
406: if (' ' != (no = getkey()))
407: *loc = no;
408: }
409:
410: /*
411: * Set prefix characters.
412: */
413: setPrefix()
414: {
415: int c;
416:
417: setpf(&bind.pfx1, 1);
418: setpf(&bind.pfx2, 2);
419: setpf(&bind.pfx3, 3);
420: mlwrite("Enter repeat code or space ");
421: if (' ' != (c = getkey()))
422: bind.repeat = c;
423: mlerase();
424: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.