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