|
|
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.