Annotation of src/usr.bin/mg/extend.c, Revision 1.52
1.52 ! lum 1: /* $OpenBSD: extend.c,v 1.51 2011/01/21 19:10:13 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.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.1 deraadt 655:
1.46 jason 656: if ((fname = adjustname(fname, TRUE)) == NULL)
1.5 millert 657: /* just to be careful */
1.33 db 658: return (FALSE);
1.1 deraadt 659:
1.13 art 660: if (ffropen(fname, NULL) != FIOSUC)
1.33 db 661: return (FALSE);
1.5 millert 662:
1.25 vincent 663: line = 0;
1.4 millert 664: while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.25 vincent 665: line++;
1.1 deraadt 666: excbuf[nbytes] = '\0';
667: if (excline(excbuf) != TRUE) {
668: s = FIOERR;
1.25 vincent 669: ewprintf("Error loading file %s at line %d", fname, line);
1.1 deraadt 670: break;
671: }
672: }
1.13 art 673: (void)ffclose(NULL);
1.1 deraadt 674: excbuf[nbytes] = '\0';
1.4 millert 675: if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.33 db 676: return (FALSE);
677: return (TRUE);
1.1 deraadt 678: }
679:
680: /*
1.33 db 681: * excline - run a line from a load file or eval-expression. If FKEYS is
682: * defined, duplicate functionality of dobind so function key values don't
1.5 millert 683: * have to fit in type char.
1.1 deraadt 684: */
1.4 millert 685: int
1.23 vincent 686: excline(char *line)
1.1 deraadt 687: {
1.5 millert 688: PF fp;
1.40 deraadt 689: struct line *lp, *np;
1.5 millert 690: int status, c, f, n;
1.22 ho 691: char *funcp, *tmp;
1.5 millert 692: char *argp = NULL;
1.22 ho 693: long nl;
1.5 millert 694: #ifdef FKEYS
695: int bind;
696: KEYMAP *curmap;
697: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
698: #define BINDNO 1 /* not binding or non-quoted BINDARG */
699: #define BINDNEXT 2 /* next arg " (define-key) */
700: #define BINDDO 3 /* already found key to bind */
701: #define BINDEXT 1 /* space for trailing \0 */
702: #else /* FKEYS */
703: #define BINDEXT 0
704: #endif /* FKEYS */
705:
706: lp = NULL;
1.1 deraadt 707:
1.4 millert 708: if (macrodef || inmacro) {
1.1 deraadt 709: ewprintf("Not now!");
1.33 db 710: return (FALSE);
1.1 deraadt 711: }
712: f = 0;
713: n = 1;
714: funcp = skipwhite(line);
1.4 millert 715: if (*funcp == '\0')
1.33 db 716: return (TRUE); /* No error on blank lines */
1.1 deraadt 717: line = parsetoken(funcp);
718: if (*line != '\0') {
719: *line++ = '\0';
720: line = skipwhite(line);
1.20 vincent 721: if (ISDIGIT(*line) || *line == '-') {
1.1 deraadt 722: argp = line;
723: line = parsetoken(line);
724: }
725: }
726: if (argp != NULL) {
727: f = FFARG;
1.22 ho 728: nl = strtol(argp, &tmp, 10);
1.20 vincent 729: if (*tmp != '\0')
1.33 db 730: return (FALSE);
1.22 ho 731: if (nl >= INT_MAX || nl <= INT_MIN)
1.33 db 732: return (FALSE);
1.22 ho 733: n = (int)nl;
1.1 deraadt 734: }
1.4 millert 735: if ((fp = name_function(funcp)) == NULL) {
736: ewprintf("Unknown function: %s", funcp);
1.33 db 737: return (FALSE);
1.1 deraadt 738: }
739: #ifdef FKEYS
1.4 millert 740: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 741: bind = BINDARG;
1.11 art 742: curmap = fundamental_map;
1.4 millert 743: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 744: bind = BINDARG;
745: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.42 kjell 746: } else if (fp == redefine_key)
1.4 millert 747: bind = BINDNEXT;
748: else
749: bind = BINDNO;
1.5 millert 750: #endif /* FKEYS */
751: /* Pack away all the args now... */
1.4 millert 752: if ((np = lalloc(0)) == FALSE)
1.33 db 753: return (FALSE);
1.1 deraadt 754: np->l_fp = np->l_bp = maclcur = np;
755: while (*line != '\0') {
756: argp = skipwhite(line);
1.4 millert 757: if (*argp == '\0')
758: break;
1.1 deraadt 759: line = parsetoken(argp);
760: if (*argp != '"') {
1.4 millert 761: if (*argp == '\'')
762: ++argp;
1.20 vincent 763: if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
764: NULL) {
1.4 millert 765: status = FALSE;
766: goto cleanup;
767: }
1.5 millert 768: bcopy(argp, ltext(lp), (int)(line - argp));
1.1 deraadt 769: #ifdef FKEYS
1.5 millert 770: /* don't count BINDEXT */
771: lp->l_used--;
1.4 millert 772: if (bind == BINDARG)
773: bind = BINDNO;
1.5 millert 774: #endif /* FKEYS */
775: } else {
776: /* quoted strings are special */
1.4 millert 777: ++argp;
1.1 deraadt 778: #ifdef FKEYS
1.4 millert 779: if (bind != BINDARG) {
1.5 millert 780: #endif /* FKEYS */
781: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 782: if (lp == NULL) {
783: status = FALSE;
784: goto cleanup;
785: }
786: lp->l_used = 0;
1.1 deraadt 787: #ifdef FKEYS
1.33 db 788: } else
1.4 millert 789: key.k_count = 0;
1.5 millert 790: #endif /* FKEYS */
1.4 millert 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: #ifdef FKEYS
843: case 'f':
844: case 'F':
845: c = *++argp - '0';
846: if (ISDIGIT(argp[1])) {
847: c *= 10;
848: c += *++argp - '0';
849: }
850: c += KFIRST;
851: break;
1.5 millert 852: #endif /* FKEYS */
1.4 millert 853: default:
854: c = CHARMASK(*argp);
855: break;
856: }
857: argp++;
858: }
1.1 deraadt 859: #ifdef FKEYS
1.4 millert 860: if (bind == BINDARG)
861: key.k_chars[key.k_count++] = c;
862: else
1.5 millert 863: #endif /* FKEYS */
1.4 millert 864: lp->l_text[lp->l_used++] = c;
865: }
866: if (*line)
867: line++;
1.1 deraadt 868: }
869: #ifdef FKEYS
1.4 millert 870: switch (bind) {
871: case BINDARG:
1.1 deraadt 872: bind = BINDDO;
873: break;
1.4 millert 874: case BINDNEXT:
1.1 deraadt 875: lp->l_text[lp->l_used] = '\0';
1.10 art 876: if ((curmap = name_map(lp->l_text)) == NULL) {
1.4 millert 877: ewprintf("No such mode: %s", lp->l_text);
878: status = FALSE;
1.44 kjell 879: free(lp);
1.4 millert 880: goto cleanup;
1.1 deraadt 881: }
1.44 kjell 882: free(lp);
1.1 deraadt 883: bind = BINDARG;
884: break;
1.4 millert 885: default:
1.5 millert 886: #endif /* FKEYS */
1.1 deraadt 887: lp->l_fp = np->l_fp;
888: lp->l_bp = np;
889: np->l_fp = lp;
890: np = lp;
891: #ifdef FKEYS
892: }
1.5 millert 893: #endif /* FKEYS */
1.1 deraadt 894: }
895: #ifdef FKEYS
1.4 millert 896: switch (bind) {
897: default:
1.1 deraadt 898: ewprintf("Bad args to set key");
899: status = FALSE;
900: break;
1.4 millert 901: case BINDDO:
902: if (fp != unbindtokey && fp != localunbind) {
903: lp->l_text[lp->l_used] = '\0';
904: status = bindkey(&curmap, lp->l_text, key.k_chars,
905: key.k_count);
1.33 db 906: } else
1.13 art 907: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 908: key.k_count);
1.1 deraadt 909: break;
1.4 millert 910: case BINDNO:
1.5 millert 911: #endif /* FKEYS */
1.1 deraadt 912: inmacro = TRUE;
913: maclcur = maclcur->l_fp;
1.5 millert 914: status = (*fp)(f, n);
1.1 deraadt 915: inmacro = FALSE;
916: #ifdef FKEYS
917: }
1.5 millert 918: #endif /* FKEYS */
1.1 deraadt 919: cleanup:
920: lp = maclcur->l_fp;
1.4 millert 921: while (lp != maclcur) {
922: np = lp->l_fp;
1.44 kjell 923: free(lp);
1.4 millert 924: lp = np;
1.1 deraadt 925: }
1.44 kjell 926: free(lp);
1.33 db 927: return (status);
1.1 deraadt 928: }
929:
930: /*
931: * a pair of utility functions for the above
932: */
933: static char *
1.23 vincent 934: skipwhite(char *s)
1.1 deraadt 935: {
1.4 millert 936: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
937: s++;
938: if (*s == ';')
939: *s = '\0';
1.33 db 940: return (s);
1.1 deraadt 941: }
942:
943: static char *
1.23 vincent 944: parsetoken(char *s)
1.1 deraadt 945: {
946: if (*s != '"') {
1.4 millert 947: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
948: s++;
949: if (*s == ';')
950: *s = '\0';
1.1 deraadt 951: } else
1.5 millert 952: do {
1.15 mickey 953: /*
954: * Strings get special treatment.
955: * Beware: You can \ out the end of the string!
1.5 millert 956: */
1.4 millert 957: if (*s == '\\')
958: ++s;
959: } while (*++s != '"' && *s != '\0');
1.33 db 960: return (s);
1.1 deraadt 961: }