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