Annotation of src/usr.bin/mg/extend.c, Revision 1.61
1.61 ! bcallah 1: /* $OpenBSD: extend.c,v 1.60 2015/03/19 21:22:15 bcallah Exp $ */
1.34 kjell 2:
3: /* This file is in the public domain. */
1.6 niklas 4:
1.1 deraadt 5: /*
1.5 millert 6: * Extended (M-X) commands, rebinding, and startup file processing.
1.1 deraadt 7: */
1.51 kjell 8:
1.60 bcallah 9: #include <sys/queue.h>
1.51 kjell 10: #include <sys/types.h>
11: #include <ctype.h>
1.57 guenther 12: #include <limits.h>
1.60 bcallah 13: #include <signal.h>
14: #include <stdio.h>
15: #include <stdlib.h>
16: #include <string.h>
1.39 kjell 17:
1.60 bcallah 18: #include "chrdef.h"
19: #include "def.h"
20: #include "funmap.h"
21: #include "kbd.h"
22: #include "key.h"
1.5 millert 23: #include "macro.h"
1.1 deraadt 24:
1.21 millert 25: static int remap(KEYMAP *, int, PF, KEYMAP *);
1.29 vincent 26: static KEYMAP *reallocmap(KEYMAP *);
1.21 millert 27: static void fixmap(KEYMAP *, KEYMAP *, KEYMAP *);
1.23 vincent 28: static int dobind(KEYMAP *, const char *, int);
1.21 millert 29: static char *skipwhite(char *);
30: static char *parsetoken(char *);
1.23 vincent 31: static int bindkey(KEYMAP **, const char *, KCHAR *, int);
1.1 deraadt 32:
1.15 mickey 33: /*
1.33 db 34: * Insert a string, mainly for use from macros (created by selfinsert).
1.5 millert 35: */
1.4 millert 36: /* ARGSUSED */
37: int
1.23 vincent 38: insert(int f, int n)
1.1 deraadt 39: {
1.31 vincent 40: char buf[128], *bufp, *cp;
1.5 millert 41: int count, c;
1.1 deraadt 42:
1.4 millert 43: if (inmacro) {
44: while (--n >= 0) {
45: for (count = 0; count < maclcur->l_used; count++) {
46: if ((((c = maclcur->l_text[count]) == '\n')
47: ? lnewline() : linsert(1, c)) != TRUE)
1.33 db 48: return (FALSE);
1.4 millert 49: }
50: }
51: maclcur = maclcur->l_fp;
1.33 db 52: return (TRUE);
1.1 deraadt 53: }
1.4 millert 54: if (n == 1)
1.5 millert 55: /* CFINS means selfinsert can tack on the end */
56: thisflag |= CFINS;
1.52 lum 57:
1.31 vincent 58: if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW)) == NULL)
1.33 db 59: return (ABORT);
1.31 vincent 60: else if (bufp[0] == '\0')
1.33 db 61: return (FALSE);
1.4 millert 62: while (--n >= 0) {
63: cp = buf;
64: while (*cp) {
65: if (((*cp == '\n') ? lnewline() : linsert(1, *cp))
66: != TRUE)
1.33 db 67: return (FALSE);
1.4 millert 68: cp++;
69: }
1.1 deraadt 70: }
1.33 db 71: return (TRUE);
1.1 deraadt 72: }
73:
74: /*
75: * Bind a key to a function. Cases range from the trivial (replacing an
1.33 db 76: * existing binding) to the extremely complex (creating a new prefix in a
1.1 deraadt 77: * map_element that already has one, so the map_element must be split,
78: * but the keymap doesn't have enough room for another map_element, so
79: * the keymap is reallocated). No attempt is made to reclaim space no
80: * longer used, if this is a problem flags must be added to indicate
1.50 martin 81: * malloced versus static storage in both keymaps and map_elements.
1.1 deraadt 82: * Structure assignments would come in real handy, but K&R based compilers
83: * don't have them. Care is taken so running out of memory will leave
84: * the keymap in a usable state.
1.49 kjell 85: * Parameters are:
86: * curmap: pointer to the map being changed
87: * c: character being changed
88: * funct: function being changed to
89: * pref_map: if funct==NULL, map to bind to or NULL for new
1.1 deraadt 90: */
1.4 millert 91: static int
1.49 kjell 92: remap(KEYMAP *curmap, int c, PF funct, KEYMAP *pref_map)
1.1 deraadt 93: {
1.5 millert 94: int i, n1, n2, nold;
1.30 vincent 95: KEYMAP *mp, *newmap;
1.5 millert 96: PF *pfp;
1.40 deraadt 97: struct map_element *mep;
1.4 millert 98:
99: if (ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) {
1.7 art 100: if (ele > &curmap->map_element[0] && (funct != NULL ||
1.5 millert 101: (ele - 1)->k_prefmap == NULL))
1.4 millert 102: n1 = c - (ele - 1)->k_num;
1.5 millert 103: else
1.4 millert 104: n1 = HUGE;
105: if (ele < &curmap->map_element[curmap->map_num] &&
1.7 art 106: (funct != NULL || ele->k_prefmap == NULL))
1.4 millert 107: n2 = ele->k_base - c;
1.5 millert 108: else
1.4 millert 109: n2 = HUGE;
110: if (n1 <= MAPELEDEF && n1 <= n2) {
111: ele--;
1.45 kjell 112: if ((pfp = calloc(c - ele->k_base + 1,
1.4 millert 113: sizeof(PF))) == NULL) {
1.54 lum 114: dobeep();
1.4 millert 115: ewprintf("Out of memory");
1.33 db 116: return (FALSE);
1.4 millert 117: }
118: nold = ele->k_num - ele->k_base + 1;
119: for (i = 0; i < nold; i++)
120: pfp[i] = ele->k_funcp[i];
121: while (--n1)
122: pfp[i++] = curmap->map_default;
123: pfp[i] = funct;
124: ele->k_num = c;
125: ele->k_funcp = pfp;
126: } else if (n2 <= MAPELEDEF) {
1.45 kjell 127: if ((pfp = calloc(ele->k_num - c + 1,
1.5 millert 128: sizeof(PF))) == NULL) {
1.54 lum 129: dobeep();
1.4 millert 130: ewprintf("Out of memory");
1.33 db 131: return (FALSE);
1.4 millert 132: }
133: nold = ele->k_num - ele->k_base + 1;
134: for (i = 0; i < nold; i++)
135: pfp[i + n2] = ele->k_funcp[i];
136: while (--n2)
137: pfp[n2] = curmap->map_default;
138: pfp[0] = funct;
139: ele->k_base = c;
140: ele->k_funcp = pfp;
1.1 deraadt 141: } else {
1.30 vincent 142: if (curmap->map_num >= curmap->map_max) {
143: if ((newmap = reallocmap(curmap)) == NULL)
1.33 db 144: return (FALSE);
1.30 vincent 145: curmap = newmap;
146: }
1.13 art 147: if ((pfp = malloc(sizeof(PF))) == NULL) {
1.54 lum 148: dobeep();
1.4 millert 149: ewprintf("Out of memory");
1.33 db 150: return (FALSE);
1.4 millert 151: }
152: pfp[0] = funct;
153: for (mep = &curmap->map_element[curmap->map_num];
154: mep > ele; mep--) {
155: mep->k_base = (mep - 1)->k_base;
156: mep->k_num = (mep - 1)->k_num;
157: mep->k_funcp = (mep - 1)->k_funcp;
158: mep->k_prefmap = (mep - 1)->k_prefmap;
159: }
160: ele->k_base = c;
161: ele->k_num = c;
162: ele->k_funcp = pfp;
163: ele->k_prefmap = NULL;
164: curmap->map_num++;
165: }
1.7 art 166: if (funct == NULL) {
1.29 vincent 167: if (pref_map != NULL)
1.4 millert 168: ele->k_prefmap = pref_map;
1.29 vincent 169: else {
1.45 kjell 170: if ((mp = malloc(sizeof(KEYMAP) +
1.40 deraadt 171: (MAPINIT - 1) * sizeof(struct map_element))) == NULL) {
1.54 lum 172: dobeep();
1.4 millert 173: ewprintf("Out of memory");
174: ele->k_funcp[c - ele->k_base] =
175: curmap->map_default;
1.33 db 176: return (FALSE);
1.4 millert 177: }
178: mp->map_num = 0;
179: mp->map_max = MAPINIT;
180: mp->map_default = rescan;
181: ele->k_prefmap = mp;
182: }
1.1 deraadt 183: }
184: } else {
1.4 millert 185: n1 = c - ele->k_base;
1.7 art 186: if (ele->k_funcp[n1] == funct && (funct != NULL ||
1.4 millert 187: pref_map == NULL || pref_map == ele->k_prefmap))
1.5 millert 188: /* no change */
1.33 db 189: return (TRUE);
1.7 art 190: if (funct != NULL || ele->k_prefmap == NULL) {
191: if (ele->k_funcp[n1] == NULL)
1.13 art 192: ele->k_prefmap = NULL;
1.5 millert 193: /* easy case */
194: ele->k_funcp[n1] = funct;
1.7 art 195: if (funct == NULL) {
1.4 millert 196: if (pref_map != NULL)
197: ele->k_prefmap = pref_map;
198: else {
1.28 vincent 199: if ((mp = malloc(sizeof(KEYMAP) +
1.15 mickey 200: (MAPINIT - 1) *
1.40 deraadt 201: sizeof(struct map_element))) == NULL) {
1.54 lum 202: dobeep();
1.4 millert 203: ewprintf("Out of memory");
204: ele->k_funcp[c - ele->k_base] =
205: curmap->map_default;
1.33 db 206: return (FALSE);
1.4 millert 207: }
208: mp->map_num = 0;
209: mp->map_max = MAPINIT;
210: mp->map_default = rescan;
211: ele->k_prefmap = mp;
212: }
213: }
214: } else {
215: /*
1.5 millert 216: * This case is the splits.
217: * Determine which side of the break c goes on
1.4 millert 218: * 0 = after break; 1 = before break
219: */
220: n2 = 1;
221: for (i = 0; n2 && i < n1; i++)
1.7 art 222: n2 &= ele->k_funcp[i] != NULL;
1.49 kjell 223: if (curmap->map_num >= curmap->map_max) {
224: if ((newmap = reallocmap(curmap)) == NULL)
225: return (FALSE);
226: curmap = newmap;
227: }
1.45 kjell 228: if ((pfp = calloc(ele->k_num - c + !n2,
1.5 millert 229: sizeof(PF))) == NULL) {
1.54 lum 230: dobeep();
1.4 millert 231: ewprintf("Out of memory");
1.33 db 232: return (FALSE);
1.4 millert 233: }
1.7 art 234: ele->k_funcp[n1] = NULL;
1.4 millert 235: for (i = n1 + n2; i <= ele->k_num - ele->k_base; i++)
236: pfp[i - n1 - n2] = ele->k_funcp[i];
237: for (mep = &curmap->map_element[curmap->map_num];
238: mep > ele; mep--) {
239: mep->k_base = (mep - 1)->k_base;
240: mep->k_num = (mep - 1)->k_num;
241: mep->k_funcp = (mep - 1)->k_funcp;
242: mep->k_prefmap = (mep - 1)->k_prefmap;
243: }
244: ele->k_num = c - !n2;
245: (ele + 1)->k_base = c + n2;
246: (ele + 1)->k_funcp = pfp;
247: ele += !n2;
248: ele->k_prefmap = NULL;
249: curmap->map_num++;
250: if (pref_map == NULL) {
251: if ((mp = malloc(sizeof(KEYMAP) + (MAPINIT - 1)
1.40 deraadt 252: * sizeof(struct map_element))) == NULL) {
1.54 lum 253: dobeep();
1.4 millert 254: ewprintf("Out of memory");
255: ele->k_funcp[c - ele->k_base] =
256: curmap->map_default;
1.33 db 257: return (FALSE);
1.4 millert 258: }
259: mp->map_num = 0;
260: mp->map_max = MAPINIT;
261: mp->map_default = rescan;
262: ele->k_prefmap = mp;
263: } else
264: ele->k_prefmap = pref_map;
265: }
1.1 deraadt 266: }
1.33 db 267: return (TRUE);
1.1 deraadt 268: }
269:
1.4 millert 270: /*
1.49 kjell 271: * Reallocate a keymap. Returns NULL (without trashing the current map)
272: * on failure.
1.4 millert 273: */
274: static KEYMAP *
1.29 vincent 275: reallocmap(KEYMAP *curmap)
1.4 millert 276: {
1.40 deraadt 277: struct maps_s *mps;
1.5 millert 278: KEYMAP *mp;
279: int i;
1.4 millert 280:
1.45 kjell 281: if (curmap->map_max > SHRT_MAX - MAPGROW) {
1.54 lum 282: dobeep();
1.45 kjell 283: ewprintf("keymap too large");
284: return (NULL);
285: }
286: if ((mp = malloc(sizeof(KEYMAP) + (curmap->map_max + (MAPGROW - 1)) *
287: sizeof(struct map_element))) == NULL) {
1.54 lum 288: dobeep();
1.4 millert 289: ewprintf("Out of memory");
1.33 db 290: return (NULL);
1.4 millert 291: }
292: mp->map_num = curmap->map_num;
293: mp->map_max = curmap->map_max + MAPGROW;
294: mp->map_default = curmap->map_default;
295: for (i = curmap->map_num; i--;) {
296: mp->map_element[i].k_base = curmap->map_element[i].k_base;
297: mp->map_element[i].k_num = curmap->map_element[i].k_num;
298: mp->map_element[i].k_funcp = curmap->map_element[i].k_funcp;
299: mp->map_element[i].k_prefmap = curmap->map_element[i].k_prefmap;
300: }
1.17 art 301: for (mps = maps; mps != NULL; mps = mps->p_next) {
302: if (mps->p_map == curmap)
303: mps->p_map = mp;
1.4 millert 304: else
1.17 art 305: fixmap(curmap, mp, mps->p_map);
1.4 millert 306: }
307: ele = &mp->map_element[ele - &curmap->map_element[0]];
1.33 db 308: return (mp);
1.4 millert 309: }
310:
311: /*
312: * Fix references to a reallocated keymap (recursive).
313: */
1.12 art 314: static void
1.23 vincent 315: fixmap(KEYMAP *curmap, KEYMAP *mp, KEYMAP *mt)
1.4 millert 316: {
1.5 millert 317: int i;
1.4 millert 318:
319: for (i = mt->map_num; i--;) {
320: if (mt->map_element[i].k_prefmap != NULL) {
321: if (mt->map_element[i].k_prefmap == curmap)
322: mt->map_element[i].k_prefmap = mp;
323: else
324: fixmap(curmap, mp, mt->map_element[i].k_prefmap);
325: }
1.1 deraadt 326: }
327: }
328:
329: /*
1.33 db 330: * Do the input for local-set-key, global-set-key and define-key
1.1 deraadt 331: * then call remap to do the work.
332: */
1.4 millert 333: static int
1.23 vincent 334: dobind(KEYMAP *curmap, const char *p, int unbind)
1.4 millert 335: {
1.5 millert 336: KEYMAP *pref_map = NULL;
337: PF funct;
1.41 kjell 338: char bprompt[80], *bufp, *pep;
1.26 vincent 339: int c, s, n;
1.1 deraadt 340:
1.4 millert 341: if (macrodef) {
342: /*
343: * Keystrokes aren't collected. Not hard, but pretty useless.
344: * Would not work for function keys in any case.
345: */
1.54 lum 346: dobeep();
1.4 millert 347: ewprintf("Can't rebind key in macro");
1.33 db 348: return (FALSE);
1.1 deraadt 349: }
1.4 millert 350: if (inmacro) {
351: for (s = 0; s < maclcur->l_used - 1; s++) {
1.8 art 352: if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap)
1.7 art 353: != NULL) {
1.13 art 354: if (remap(curmap, c, NULL, NULL)
1.4 millert 355: != TRUE)
1.33 db 356: return (FALSE);
1.4 millert 357: }
1.1 deraadt 358: }
1.12 art 359: (void)doscan(curmap, c = maclcur->l_text[s], NULL);
1.4 millert 360: maclcur = maclcur->l_fp;
1.1 deraadt 361: } else {
1.41 kjell 362: n = strlcpy(bprompt, p, sizeof(bprompt));
363: if (n >= sizeof(bprompt))
364: n = sizeof(bprompt) - 1;
365: pep = bprompt + n;
1.4 millert 366: for (;;) {
1.41 kjell 367: ewprintf("%s", bprompt);
1.4 millert 368: pep[-1] = ' ';
1.42 kjell 369: pep = getkeyname(pep, sizeof(bprompt) -
1.41 kjell 370: (pep - bprompt), c = getkey(FALSE));
1.8 art 371: if (doscan(curmap, c, &curmap) != NULL)
1.4 millert 372: break;
373: *pep++ = '-';
374: *pep = '\0';
375: }
1.1 deraadt 376: }
1.4 millert 377: if (unbind)
378: funct = rescan;
1.1 deraadt 379: else {
1.41 kjell 380: if ((bufp = eread("%s to command: ", bprompt, sizeof(bprompt),
381: EFFUNC | EFNEW, bprompt)) == NULL)
1.33 db 382: return (ABORT);
1.31 vincent 383: else if (bufp[0] == '\0')
1.33 db 384: return (FALSE);
1.41 kjell 385: if (((funct = name_function(bprompt)) == NULL) ?
386: (pref_map = name_map(bprompt)) == NULL : funct == NULL) {
1.54 lum 387: dobeep();
1.4 millert 388: ewprintf("[No match]");
1.33 db 389: return (FALSE);
1.4 millert 390: }
1.1 deraadt 391: }
1.33 db 392: return (remap(curmap, c, funct, pref_map));
1.1 deraadt 393: }
394:
395: /*
1.15 mickey 396: * bindkey: bind key sequence to a function in the specified map. Used by
397: * excline so it can bind function keys. To close to release to change
398: * calling sequence, should just pass KEYMAP *curmap rather than
1.5 millert 399: * KEYMAP **mapp.
400: */
401: static int
1.23 vincent 402: bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
1.5 millert 403: {
404: KEYMAP *curmap = *mapp;
405: KEYMAP *pref_map = NULL;
406: PF funct;
407: int c;
1.1 deraadt 408:
1.4 millert 409: if (fname == NULL)
410: funct = rescan;
1.7 art 411: else if (((funct = name_function(fname)) == NULL) ?
1.5 millert 412: (pref_map = name_map(fname)) == NULL : funct == NULL) {
1.54 lum 413: dobeep();
1.4 millert 414: ewprintf("[No match: %s]", fname);
1.33 db 415: return (FALSE);
1.4 millert 416: }
417: while (--kcount) {
1.8 art 418: if (doscan(curmap, c = *keys++, &curmap) != NULL) {
1.13 art 419: if (remap(curmap, c, NULL, NULL) != TRUE)
1.33 db 420: return (FALSE);
1.9 art 421: /*
422: * XXX - Bizzarreness. remap creates an empty KEYMAP
423: * that the last key is supposed to point to.
424: */
425: curmap = ele->k_prefmap;
1.4 millert 426: }
1.1 deraadt 427: }
1.12 art 428: (void)doscan(curmap, c = *keys, NULL);
1.33 db 429: return (remap(curmap, c, funct, pref_map));
1.1 deraadt 430: }
1.3 millert 431:
432: /*
433: * Wrapper for bindkey() that converts escapes.
434: */
435: int
1.23 vincent 436: dobindkey(KEYMAP *map, const char *func, const char *str)
1.3 millert 437: {
1.5 millert 438: int i;
1.3 millert 439:
440: for (i = 0; *str && i < MAXKEY; i++) {
441: /* XXX - convert numbers w/ strol()? */
1.38 kjell 442: if (*str == '^' && *(str + 1) != '\0') {
1.56 guenther 443: key.k_chars[i] = CCHR(toupper((unsigned char)*++str));
1.38 kjell 444: } else if (*str == '\\' && *(str + 1) != '\0') {
1.4 millert 445: switch (*++str) {
1.38 kjell 446: case '^':
447: key.k_chars[i] = '^';
448: break;
1.4 millert 449: case 't':
450: case 'T':
1.3 millert 451: key.k_chars[i] = '\t';
452: break;
1.4 millert 453: case 'n':
454: case 'N':
1.3 millert 455: key.k_chars[i] = '\n';
456: break;
1.4 millert 457: case 'r':
458: case 'R':
1.3 millert 459: key.k_chars[i] = '\r';
460: break;
1.4 millert 461: case 'e':
462: case 'E':
1.3 millert 463: key.k_chars[i] = CCHR('[');
464: break;
1.38 kjell 465: case '\\':
466: key.k_chars[i] = '\\';
467: break;
1.3 millert 468: }
1.38 kjell 469: } else
470: key.k_chars[i] = *str;
1.3 millert 471: str++;
472: }
473: key.k_count = i;
1.4 millert 474: return (bindkey(&map, func, key.k_chars, key.k_count));
1.3 millert 475: }
1.1 deraadt 476:
477: /*
478: * This function modifies the fundamental keyboard map.
479: */
1.4 millert 480: /* ARGSUSED */
481: int
1.23 vincent 482: bindtokey(int f, int n)
1.1 deraadt 483: {
1.33 db 484: return (dobind(fundamental_map, "Global set key: ", FALSE));
1.1 deraadt 485: }
486:
487: /*
488: * This function modifies the current mode's keyboard map.
489: */
1.4 millert 490: /* ARGSUSED */
491: int
1.23 vincent 492: localbind(int f, int n)
1.1 deraadt 493: {
1.33 db 494: return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
495: "Local set key: ", FALSE));
1.1 deraadt 496: }
497:
498: /*
499: * This function redefines a key in any keymap.
500: */
1.4 millert 501: /* ARGSUSED */
502: int
1.42 kjell 503: redefine_key(int f, int n)
1.1 deraadt 504: {
1.33 db 505: static char buf[48];
506: char tmp[32], *bufp;
507: KEYMAP *mp;
508:
1.43 kjell 509: (void)strlcpy(buf, "Define key map: ", sizeof(buf));
1.33 db 510: if ((bufp = eread(buf, tmp, sizeof(tmp), EFNEW)) == NULL)
511: return (ABORT);
1.31 vincent 512: else if (bufp[0] == '\0')
1.33 db 513: return (FALSE);
1.35 kjell 514: (void)strlcat(buf, tmp, sizeof(buf));
1.19 vincent 515: if ((mp = name_map(tmp)) == NULL) {
1.54 lum 516: dobeep();
1.19 vincent 517: ewprintf("Unknown map %s", tmp);
1.33 db 518: return (FALSE);
1.4 millert 519: }
1.43 kjell 520: if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf))
521: return (FALSE);
1.19 vincent 522:
1.33 db 523: return (dobind(mp, buf, FALSE));
1.1 deraadt 524: }
525:
1.37 kjell 526: /* ARGSUSED */
1.4 millert 527: int
1.23 vincent 528: unbindtokey(int f, int n)
1.1 deraadt 529: {
1.33 db 530: return (dobind(fundamental_map, "Global unset key: ", TRUE));
1.1 deraadt 531: }
532:
1.37 kjell 533: /* ARGSUSED */
1.4 millert 534: int
1.27 vincent 535: localunbind(int f, int n)
1.1 deraadt 536: {
1.33 db 537: return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
538: "Local unset key: ", TRUE));
1.1 deraadt 539: }
540:
541: /*
1.15 mickey 542: * Extended command. Call the message line routine to read in the command
543: * name and apply autocompletion to it. When it comes back, look the name
544: * up in the symbol table and run the command if it is found. Print an
1.5 millert 545: * error if there is anything wrong.
1.1 deraadt 546: */
1.4 millert 547: int
1.23 vincent 548: extend(int f, int n)
1.1 deraadt 549: {
1.5 millert 550: PF funct;
1.31 vincent 551: char xname[NXNAME], *bufp;
1.4 millert 552:
553: if (!(f & FFARG))
1.31 vincent 554: bufp = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
1.4 millert 555: else
1.31 vincent 556: bufp = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
557: if (bufp == NULL)
1.33 db 558: return (ABORT);
1.31 vincent 559: else if (bufp[0] == '\0')
1.33 db 560: return (FALSE);
1.31 vincent 561: if ((funct = name_function(bufp)) != NULL) {
1.4 millert 562: if (macrodef) {
1.40 deraadt 563: struct line *lp = maclcur;
1.4 millert 564: macro[macrocount - 1].m_funct = funct;
565: maclcur = lp->l_bp;
566: maclcur->l_fp = lp->l_fp;
1.44 kjell 567: free(lp);
1.4 millert 568: }
1.33 db 569: return ((*funct)(f, n));
1.1 deraadt 570: }
1.54 lum 571: dobeep();
1.1 deraadt 572: ewprintf("[No match]");
1.33 db 573: return (FALSE);
1.1 deraadt 574: }
575:
576: /*
577: * Define the commands needed to do startup-file processing.
578: * This code is mostly a kludge just so we can get startup-file processing.
579: *
580: * If you're serious about having this code, you should rewrite it.
581: * To wit:
582: * It has lots of funny things in it to make the startup-file look
583: * like a GNU startup file; mostly dealing with parens and semicolons.
584: * This should all vanish.
585: *
586: * We define eval-expression because it's easy. It can make
587: * *-set-key or define-key set an arbitrary key sequence, so it isn't
588: * useless.
589: */
590:
591: /*
592: * evalexpr - get one line from the user, and run it.
593: */
1.4 millert 594: /* ARGSUSED */
595: int
1.23 vincent 596: evalexpr(int f, int n)
1.1 deraadt 597: {
1.31 vincent 598: char exbuf[128], *bufp;
1.1 deraadt 599:
1.35 kjell 600: if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
601: EFNEW | EFCR)) == NULL)
1.33 db 602: return (ABORT);
1.31 vincent 603: else if (bufp[0] == '\0')
1.33 db 604: return (FALSE);
605: return (excline(exbuf));
1.1 deraadt 606: }
1.4 millert 607:
1.1 deraadt 608: /*
1.15 mickey 609: * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5 millert 610: * testing startup files.
1.1 deraadt 611: */
1.4 millert 612: /* ARGSUSED */
613: int
1.23 vincent 614: evalbuffer(int f, int n)
1.1 deraadt 615: {
1.40 deraadt 616: struct line *lp;
617: struct buffer *bp = curbp;
1.5 millert 618: int s;
619: static char excbuf[128];
1.1 deraadt 620:
1.48 kjell 621: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) {
1.4 millert 622: if (llength(lp) >= 128)
1.33 db 623: return (FALSE);
1.12 art 624: (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5 millert 625:
626: /* make sure it's terminated */
627: excbuf[llength(lp)] = '\0';
1.4 millert 628: if ((s = excline(excbuf)) != TRUE)
1.33 db 629: return (s);
1.1 deraadt 630: }
1.33 db 631: return (TRUE);
1.1 deraadt 632: }
1.4 millert 633:
1.1 deraadt 634: /*
635: * evalfile - go get a file and evaluate it as line commands. You can
636: * go get your own startup file if need be.
637: */
1.4 millert 638: /* ARGSUSED */
639: int
1.23 vincent 640: evalfile(int f, int n)
1.1 deraadt 641: {
1.31 vincent 642: char fname[NFILEN], *bufp;
1.1 deraadt 643:
1.35 kjell 644: if ((bufp = eread("Load file: ", fname, NFILEN,
645: EFNEW | EFCR)) == NULL)
1.33 db 646: return (ABORT);
1.31 vincent 647: else if (bufp[0] == '\0')
1.33 db 648: return (FALSE);
649: return (load(fname));
1.1 deraadt 650: }
651:
652: /*
653: * load - go load the file name we got passed.
654: */
1.4 millert 655: int
1.23 vincent 656: load(const char *fname)
1.4 millert 657: {
1.25 vincent 658: int s = TRUE, line;
1.18 matthieu 659: int nbytes = 0;
1.5 millert 660: char excbuf[128];
1.53 lum 661: FILE *ffp;
1.1 deraadt 662:
1.46 jason 663: if ((fname = adjustname(fname, TRUE)) == NULL)
1.5 millert 664: /* just to be careful */
1.33 db 665: return (FALSE);
1.1 deraadt 666:
1.53 lum 667: if (ffropen(&ffp, fname, NULL) != FIOSUC)
1.33 db 668: return (FALSE);
1.5 millert 669:
1.25 vincent 670: line = 0;
1.53 lum 671: while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, &nbytes))
672: == FIOSUC) {
1.25 vincent 673: line++;
1.1 deraadt 674: excbuf[nbytes] = '\0';
675: if (excline(excbuf) != TRUE) {
676: s = FIOERR;
1.54 lum 677: dobeep();
1.25 vincent 678: ewprintf("Error loading file %s at line %d", fname, line);
1.1 deraadt 679: break;
680: }
681: }
1.53 lum 682: (void)ffclose(ffp, NULL);
1.1 deraadt 683: excbuf[nbytes] = '\0';
1.4 millert 684: if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.33 db 685: return (FALSE);
686: return (TRUE);
1.1 deraadt 687: }
688:
689: /*
1.59 bcallah 690: * excline - run a line from a load file or eval-expression.
1.1 deraadt 691: */
1.4 millert 692: int
1.23 vincent 693: excline(char *line)
1.1 deraadt 694: {
1.5 millert 695: PF fp;
1.40 deraadt 696: struct line *lp, *np;
1.5 millert 697: int status, c, f, n;
1.22 ho 698: char *funcp, *tmp;
1.5 millert 699: char *argp = NULL;
1.22 ho 700: long nl;
1.5 millert 701: int bind;
702: KEYMAP *curmap;
703: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
704: #define BINDNO 1 /* not binding or non-quoted BINDARG */
705: #define BINDNEXT 2 /* next arg " (define-key) */
706: #define BINDDO 3 /* already found key to bind */
707: #define BINDEXT 1 /* space for trailing \0 */
708:
709: lp = NULL;
1.1 deraadt 710:
1.4 millert 711: if (macrodef || inmacro) {
1.54 lum 712: dobeep();
1.1 deraadt 713: ewprintf("Not now!");
1.33 db 714: return (FALSE);
1.1 deraadt 715: }
716: f = 0;
717: n = 1;
718: funcp = skipwhite(line);
1.4 millert 719: if (*funcp == '\0')
1.33 db 720: return (TRUE); /* No error on blank lines */
1.1 deraadt 721: line = parsetoken(funcp);
722: if (*line != '\0') {
723: *line++ = '\0';
724: line = skipwhite(line);
1.20 vincent 725: if (ISDIGIT(*line) || *line == '-') {
1.1 deraadt 726: argp = line;
727: line = parsetoken(line);
728: }
729: }
730: if (argp != NULL) {
731: f = FFARG;
1.22 ho 732: nl = strtol(argp, &tmp, 10);
1.20 vincent 733: if (*tmp != '\0')
1.33 db 734: return (FALSE);
1.22 ho 735: if (nl >= INT_MAX || nl <= INT_MIN)
1.33 db 736: return (FALSE);
1.22 ho 737: n = (int)nl;
1.1 deraadt 738: }
1.4 millert 739: if ((fp = name_function(funcp)) == NULL) {
1.54 lum 740: dobeep();
1.4 millert 741: ewprintf("Unknown function: %s", funcp);
1.33 db 742: return (FALSE);
1.1 deraadt 743: }
1.4 millert 744: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 745: bind = BINDARG;
1.11 art 746: curmap = fundamental_map;
1.4 millert 747: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 748: bind = BINDARG;
749: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.42 kjell 750: } else if (fp == redefine_key)
1.4 millert 751: bind = BINDNEXT;
752: else
753: bind = BINDNO;
1.5 millert 754: /* Pack away all the args now... */
1.4 millert 755: if ((np = lalloc(0)) == FALSE)
1.33 db 756: return (FALSE);
1.1 deraadt 757: np->l_fp = np->l_bp = maclcur = np;
758: while (*line != '\0') {
759: argp = skipwhite(line);
1.4 millert 760: if (*argp == '\0')
761: break;
1.1 deraadt 762: line = parsetoken(argp);
763: if (*argp != '"') {
1.4 millert 764: if (*argp == '\'')
765: ++argp;
1.20 vincent 766: if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
767: NULL) {
1.4 millert 768: status = FALSE;
769: goto cleanup;
770: }
1.5 millert 771: bcopy(argp, ltext(lp), (int)(line - argp));
772: /* don't count BINDEXT */
773: lp->l_used--;
1.4 millert 774: if (bind == BINDARG)
775: bind = BINDNO;
1.5 millert 776: } else {
777: /* quoted strings are special */
1.4 millert 778: ++argp;
779: if (bind != BINDARG) {
1.5 millert 780: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 781: if (lp == NULL) {
782: status = FALSE;
783: goto cleanup;
784: }
785: lp->l_used = 0;
1.33 db 786: } else
1.4 millert 787: key.k_count = 0;
788: while (*argp != '"' && *argp != '\0') {
789: if (*argp != '\\')
790: c = *argp++;
791: else {
792: switch (*++argp) {
793: case 't':
794: case 'T':
795: c = CCHR('I');
796: break;
797: case 'n':
798: case 'N':
799: c = CCHR('J');
800: break;
801: case 'r':
802: case 'R':
803: c = CCHR('M');
804: break;
805: case 'e':
806: case 'E':
807: c = CCHR('[');
808: break;
809: case '^':
810: /*
811: * split into two statements
812: * due to bug in OSK cpp
813: */
814: c = CHARMASK(*++argp);
815: c = ISLOWER(c) ?
816: CCHR(TOUPPER(c)) : CCHR(c);
817: break;
818: case '0':
819: case '1':
820: case '2':
821: case '3':
822: case '4':
823: case '5':
824: case '6':
825: case '7':
826: c = *argp - '0';
1.15 mickey 827: if (argp[1] <= '7' &&
1.5 millert 828: argp[1] >= '0') {
1.4 millert 829: c <<= 3;
830: c += *++argp - '0';
831: if (argp[1] <= '7' &&
832: argp[1] >= '0') {
833: c <<= 3;
834: c += *++argp
835: - '0';
836: }
837: }
838: break;
839: case 'f':
840: case 'F':
841: c = *++argp - '0';
842: if (ISDIGIT(argp[1])) {
843: c *= 10;
844: c += *++argp - '0';
845: }
846: c += KFIRST;
847: break;
848: default:
849: c = CHARMASK(*argp);
850: break;
851: }
852: argp++;
853: }
854: if (bind == BINDARG)
855: key.k_chars[key.k_count++] = c;
856: else
857: lp->l_text[lp->l_used++] = c;
858: }
859: if (*line)
860: line++;
1.1 deraadt 861: }
1.4 millert 862: switch (bind) {
863: case BINDARG:
1.1 deraadt 864: bind = BINDDO;
865: break;
1.4 millert 866: case BINDNEXT:
1.1 deraadt 867: lp->l_text[lp->l_used] = '\0';
1.10 art 868: if ((curmap = name_map(lp->l_text)) == NULL) {
1.54 lum 869: dobeep();
1.4 millert 870: ewprintf("No such mode: %s", lp->l_text);
871: status = FALSE;
1.44 kjell 872: free(lp);
1.4 millert 873: goto cleanup;
1.1 deraadt 874: }
1.44 kjell 875: free(lp);
1.1 deraadt 876: bind = BINDARG;
877: break;
1.4 millert 878: default:
1.1 deraadt 879: lp->l_fp = np->l_fp;
880: lp->l_bp = np;
881: np->l_fp = lp;
882: np = lp;
883: }
884: }
1.4 millert 885: switch (bind) {
886: default:
1.54 lum 887: dobeep();
1.1 deraadt 888: ewprintf("Bad args to set key");
889: status = FALSE;
890: break;
1.4 millert 891: case BINDDO:
892: if (fp != unbindtokey && fp != localunbind) {
893: lp->l_text[lp->l_used] = '\0';
894: status = bindkey(&curmap, lp->l_text, key.k_chars,
895: key.k_count);
1.33 db 896: } else
1.13 art 897: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 898: key.k_count);
1.1 deraadt 899: break;
1.4 millert 900: case BINDNO:
1.1 deraadt 901: inmacro = TRUE;
902: maclcur = maclcur->l_fp;
1.5 millert 903: status = (*fp)(f, n);
1.1 deraadt 904: inmacro = FALSE;
905: }
906: cleanup:
907: lp = maclcur->l_fp;
1.4 millert 908: while (lp != maclcur) {
909: np = lp->l_fp;
1.44 kjell 910: free(lp);
1.4 millert 911: lp = np;
1.1 deraadt 912: }
1.44 kjell 913: free(lp);
1.33 db 914: return (status);
1.1 deraadt 915: }
916:
917: /*
918: * a pair of utility functions for the above
919: */
920: static char *
1.23 vincent 921: skipwhite(char *s)
1.1 deraadt 922: {
1.4 millert 923: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
924: s++;
1.55 lum 925: if ((*s == ';') || (*s == '#'))
1.4 millert 926: *s = '\0';
1.33 db 927: return (s);
1.1 deraadt 928: }
929:
930: static char *
1.23 vincent 931: parsetoken(char *s)
1.1 deraadt 932: {
933: if (*s != '"') {
1.4 millert 934: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
935: s++;
936: if (*s == ';')
937: *s = '\0';
1.1 deraadt 938: } else
1.5 millert 939: do {
1.15 mickey 940: /*
941: * Strings get special treatment.
942: * Beware: You can \ out the end of the string!
1.5 millert 943: */
1.4 millert 944: if (*s == '\\')
945: ++s;
946: } while (*++s != '"' && *s != '\0');
1.33 db 947: return (s);
1.1 deraadt 948: }