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