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