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