Annotation of src/usr.bin/mg/extend.c, Revision 1.44
1.44 ! kjell 1: /* $OpenBSD: extend.c,v 1.43 2005/12/20 05:04:28 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.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.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: #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.42 kjell 501: redefine_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:
1.43 kjell 507: (void)strlcpy(buf, "Define key map: ", sizeof(buf));
1.33 db 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.43 kjell 517: if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf))
518: return (FALSE);
1.19 vincent 519:
1.33 db 520: return (dobind(mp, buf, FALSE));
1.1 deraadt 521: }
522:
1.37 kjell 523: /* ARGSUSED */
1.4 millert 524: int
1.23 vincent 525: unbindtokey(int f, int n)
1.1 deraadt 526: {
1.33 db 527: return (dobind(fundamental_map, "Global unset key: ", TRUE));
1.1 deraadt 528: }
529:
1.37 kjell 530: /* ARGSUSED */
1.4 millert 531: int
1.27 vincent 532: localunbind(int f, int n)
1.1 deraadt 533: {
1.33 db 534: return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
535: "Local unset key: ", TRUE));
1.1 deraadt 536: }
537:
538: /*
1.15 mickey 539: * Extended command. Call the message line routine to read in the command
540: * name and apply autocompletion to it. When it comes back, look the name
541: * up in the symbol table and run the command if it is found. Print an
1.5 millert 542: * error if there is anything wrong.
1.1 deraadt 543: */
1.4 millert 544: int
1.23 vincent 545: extend(int f, int n)
1.1 deraadt 546: {
1.5 millert 547: PF funct;
1.31 vincent 548: char xname[NXNAME], *bufp;
1.4 millert 549:
550: if (!(f & FFARG))
1.31 vincent 551: bufp = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
1.4 millert 552: else
1.31 vincent 553: bufp = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
554: if (bufp == NULL)
1.33 db 555: return (ABORT);
1.31 vincent 556: else if (bufp[0] == '\0')
1.33 db 557: return (FALSE);
1.31 vincent 558: if ((funct = name_function(bufp)) != NULL) {
1.1 deraadt 559: #ifndef NO_MACRO
1.4 millert 560: if (macrodef) {
1.40 deraadt 561: struct line *lp = maclcur;
1.4 millert 562: macro[macrocount - 1].m_funct = funct;
563: maclcur = lp->l_bp;
564: maclcur->l_fp = lp->l_fp;
1.44 ! kjell 565: free(lp);
1.4 millert 566: }
1.5 millert 567: #endif /* !NO_MACRO */
1.33 db 568: return ((*funct)(f, n));
1.1 deraadt 569: }
570: ewprintf("[No match]");
1.33 db 571: return (FALSE);
1.1 deraadt 572: }
573:
574: #ifndef NO_STARTUP
575: /*
576: * Define the commands needed to do startup-file processing.
577: * This code is mostly a kludge just so we can get startup-file processing.
578: *
579: * If you're serious about having this code, you should rewrite it.
580: * To wit:
581: * It has lots of funny things in it to make the startup-file look
582: * like a GNU startup file; mostly dealing with parens and semicolons.
583: * This should all vanish.
584: *
585: * We define eval-expression because it's easy. It can make
586: * *-set-key or define-key set an arbitrary key sequence, so it isn't
587: * useless.
588: */
589:
590: /*
591: * evalexpr - get one line from the user, and run it.
592: */
1.4 millert 593: /* ARGSUSED */
594: int
1.23 vincent 595: evalexpr(int f, int n)
1.1 deraadt 596: {
1.31 vincent 597: char exbuf[128], *bufp;
1.1 deraadt 598:
1.35 kjell 599: if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
600: EFNEW | EFCR)) == NULL)
1.33 db 601: return (ABORT);
1.31 vincent 602: else if (bufp[0] == '\0')
1.33 db 603: return (FALSE);
604: return (excline(exbuf));
1.1 deraadt 605: }
1.4 millert 606:
1.1 deraadt 607: /*
1.15 mickey 608: * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5 millert 609: * testing startup files.
1.1 deraadt 610: */
1.4 millert 611: /* ARGSUSED */
612: int
1.23 vincent 613: evalbuffer(int f, int n)
1.1 deraadt 614: {
1.40 deraadt 615: struct line *lp;
616: struct buffer *bp = curbp;
1.5 millert 617: int s;
618: static char excbuf[128];
1.1 deraadt 619:
620: for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
1.4 millert 621: if (llength(lp) >= 128)
1.33 db 622: return (FALSE);
1.12 art 623: (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5 millert 624:
625: /* make sure it's terminated */
626: excbuf[llength(lp)] = '\0';
1.4 millert 627: if ((s = excline(excbuf)) != TRUE)
1.33 db 628: return (s);
1.1 deraadt 629: }
1.33 db 630: return (TRUE);
1.1 deraadt 631: }
1.4 millert 632:
1.1 deraadt 633: /*
634: * evalfile - go get a file and evaluate it as line commands. You can
635: * go get your own startup file if need be.
636: */
1.4 millert 637: /* ARGSUSED */
638: int
1.23 vincent 639: evalfile(int f, int n)
1.1 deraadt 640: {
1.31 vincent 641: char fname[NFILEN], *bufp;
1.1 deraadt 642:
1.35 kjell 643: if ((bufp = eread("Load file: ", fname, NFILEN,
644: EFNEW | EFCR)) == NULL)
1.33 db 645: return (ABORT);
1.31 vincent 646: else if (bufp[0] == '\0')
1.33 db 647: return (FALSE);
648: return (load(fname));
1.1 deraadt 649: }
650:
651: /*
652: * load - go load the file name we got passed.
653: */
1.4 millert 654: int
1.23 vincent 655: load(const char *fname)
1.4 millert 656: {
1.25 vincent 657: int s = TRUE, line;
1.18 matthieu 658: int nbytes = 0;
1.5 millert 659: char excbuf[128];
1.1 deraadt 660:
661: if ((fname = adjustname(fname)) == NULL)
1.5 millert 662: /* just to be careful */
1.33 db 663: return (FALSE);
1.1 deraadt 664:
1.13 art 665: if (ffropen(fname, NULL) != FIOSUC)
1.33 db 666: return (FALSE);
1.5 millert 667:
1.25 vincent 668: line = 0;
1.4 millert 669: while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.25 vincent 670: line++;
1.1 deraadt 671: excbuf[nbytes] = '\0';
672: if (excline(excbuf) != TRUE) {
673: s = FIOERR;
1.25 vincent 674: ewprintf("Error loading file %s at line %d", fname, line);
1.1 deraadt 675: break;
676: }
677: }
1.13 art 678: (void)ffclose(NULL);
1.1 deraadt 679: excbuf[nbytes] = '\0';
1.4 millert 680: if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.33 db 681: return (FALSE);
682: return (TRUE);
1.1 deraadt 683: }
684:
685: /*
1.33 db 686: * excline - run a line from a load file or eval-expression. If FKEYS is
687: * defined, duplicate functionality of dobind so function key values don't
1.5 millert 688: * have to fit in type char.
1.1 deraadt 689: */
1.4 millert 690: int
1.23 vincent 691: excline(char *line)
1.1 deraadt 692: {
1.5 millert 693: PF fp;
1.40 deraadt 694: struct line *lp, *np;
1.5 millert 695: int status, c, f, n;
1.22 ho 696: char *funcp, *tmp;
1.5 millert 697: char *argp = NULL;
1.22 ho 698: long nl;
1.5 millert 699: #ifdef FKEYS
700: int bind;
701: KEYMAP *curmap;
702: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
703: #define BINDNO 1 /* not binding or non-quoted BINDARG */
704: #define BINDNEXT 2 /* next arg " (define-key) */
705: #define BINDDO 3 /* already found key to bind */
706: #define BINDEXT 1 /* space for trailing \0 */
707: #else /* FKEYS */
708: #define BINDEXT 0
709: #endif /* FKEYS */
710:
711: lp = NULL;
1.1 deraadt 712:
1.4 millert 713: if (macrodef || inmacro) {
1.1 deraadt 714: ewprintf("Not now!");
1.33 db 715: return (FALSE);
1.1 deraadt 716: }
717: f = 0;
718: n = 1;
719: funcp = skipwhite(line);
1.4 millert 720: if (*funcp == '\0')
1.33 db 721: return (TRUE); /* No error on blank lines */
1.1 deraadt 722: line = parsetoken(funcp);
723: if (*line != '\0') {
724: *line++ = '\0';
725: line = skipwhite(line);
1.20 vincent 726: if (ISDIGIT(*line) || *line == '-') {
1.1 deraadt 727: argp = line;
728: line = parsetoken(line);
729: }
730: }
731: if (argp != NULL) {
732: f = FFARG;
1.22 ho 733: nl = strtol(argp, &tmp, 10);
1.20 vincent 734: if (*tmp != '\0')
1.33 db 735: return (FALSE);
1.22 ho 736: if (nl >= INT_MAX || nl <= INT_MIN)
1.33 db 737: return (FALSE);
1.22 ho 738: n = (int)nl;
1.1 deraadt 739: }
1.4 millert 740: if ((fp = name_function(funcp)) == NULL) {
741: ewprintf("Unknown function: %s", funcp);
1.33 db 742: return (FALSE);
1.1 deraadt 743: }
744: #ifdef FKEYS
1.4 millert 745: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 746: bind = BINDARG;
1.11 art 747: curmap = fundamental_map;
1.4 millert 748: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 749: bind = BINDARG;
750: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.42 kjell 751: } else if (fp == redefine_key)
1.4 millert 752: bind = BINDNEXT;
753: else
754: bind = BINDNO;
1.5 millert 755: #endif /* FKEYS */
756: /* Pack away all the args now... */
1.4 millert 757: if ((np = lalloc(0)) == FALSE)
1.33 db 758: return (FALSE);
1.1 deraadt 759: np->l_fp = np->l_bp = maclcur = np;
760: while (*line != '\0') {
761: argp = skipwhite(line);
1.4 millert 762: if (*argp == '\0')
763: break;
1.1 deraadt 764: line = parsetoken(argp);
765: if (*argp != '"') {
1.4 millert 766: if (*argp == '\'')
767: ++argp;
1.20 vincent 768: if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
769: NULL) {
1.4 millert 770: status = FALSE;
771: goto cleanup;
772: }
1.5 millert 773: bcopy(argp, ltext(lp), (int)(line - argp));
1.1 deraadt 774: #ifdef FKEYS
1.5 millert 775: /* don't count BINDEXT */
776: lp->l_used--;
1.4 millert 777: if (bind == BINDARG)
778: bind = BINDNO;
1.5 millert 779: #endif /* FKEYS */
780: } else {
781: /* quoted strings are special */
1.4 millert 782: ++argp;
1.1 deraadt 783: #ifdef FKEYS
1.4 millert 784: if (bind != BINDARG) {
1.5 millert 785: #endif /* FKEYS */
786: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 787: if (lp == NULL) {
788: status = FALSE;
789: goto cleanup;
790: }
791: lp->l_used = 0;
1.1 deraadt 792: #ifdef FKEYS
1.33 db 793: } else
1.4 millert 794: key.k_count = 0;
1.5 millert 795: #endif /* FKEYS */
1.4 millert 796: while (*argp != '"' && *argp != '\0') {
797: if (*argp != '\\')
798: c = *argp++;
799: else {
800: switch (*++argp) {
801: case 't':
802: case 'T':
803: c = CCHR('I');
804: break;
805: case 'n':
806: case 'N':
807: c = CCHR('J');
808: break;
809: case 'r':
810: case 'R':
811: c = CCHR('M');
812: break;
813: case 'e':
814: case 'E':
815: c = CCHR('[');
816: break;
817: case '^':
818: /*
819: * split into two statements
820: * due to bug in OSK cpp
821: */
822: c = CHARMASK(*++argp);
823: c = ISLOWER(c) ?
824: CCHR(TOUPPER(c)) : CCHR(c);
825: break;
826: case '0':
827: case '1':
828: case '2':
829: case '3':
830: case '4':
831: case '5':
832: case '6':
833: case '7':
834: c = *argp - '0';
1.15 mickey 835: if (argp[1] <= '7' &&
1.5 millert 836: argp[1] >= '0') {
1.4 millert 837: c <<= 3;
838: c += *++argp - '0';
839: if (argp[1] <= '7' &&
840: argp[1] >= '0') {
841: c <<= 3;
842: c += *++argp
843: - '0';
844: }
845: }
846: break;
847: #ifdef FKEYS
848: case 'f':
849: case 'F':
850: c = *++argp - '0';
851: if (ISDIGIT(argp[1])) {
852: c *= 10;
853: c += *++argp - '0';
854: }
855: c += KFIRST;
856: break;
1.5 millert 857: #endif /* FKEYS */
1.4 millert 858: default:
859: c = CHARMASK(*argp);
860: break;
861: }
862: argp++;
863: }
1.1 deraadt 864: #ifdef FKEYS
1.4 millert 865: if (bind == BINDARG)
866: key.k_chars[key.k_count++] = c;
867: else
1.5 millert 868: #endif /* FKEYS */
1.4 millert 869: lp->l_text[lp->l_used++] = c;
870: }
871: if (*line)
872: line++;
1.1 deraadt 873: }
874: #ifdef FKEYS
1.4 millert 875: switch (bind) {
876: case BINDARG:
1.1 deraadt 877: bind = BINDDO;
878: break;
1.4 millert 879: case BINDNEXT:
1.1 deraadt 880: lp->l_text[lp->l_used] = '\0';
1.10 art 881: if ((curmap = name_map(lp->l_text)) == NULL) {
1.4 millert 882: ewprintf("No such mode: %s", lp->l_text);
883: status = FALSE;
1.44 ! kjell 884: free(lp);
1.4 millert 885: goto cleanup;
1.1 deraadt 886: }
1.44 ! kjell 887: free(lp);
1.1 deraadt 888: bind = BINDARG;
889: break;
1.4 millert 890: default:
1.5 millert 891: #endif /* FKEYS */
1.1 deraadt 892: lp->l_fp = np->l_fp;
893: lp->l_bp = np;
894: np->l_fp = lp;
895: np = lp;
896: #ifdef FKEYS
897: }
1.5 millert 898: #endif /* FKEYS */
1.1 deraadt 899: }
900: #ifdef FKEYS
1.4 millert 901: switch (bind) {
902: default:
1.1 deraadt 903: ewprintf("Bad args to set key");
904: status = FALSE;
905: break;
1.4 millert 906: case BINDDO:
907: if (fp != unbindtokey && fp != localunbind) {
908: lp->l_text[lp->l_used] = '\0';
909: status = bindkey(&curmap, lp->l_text, key.k_chars,
910: key.k_count);
1.33 db 911: } else
1.13 art 912: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 913: key.k_count);
1.1 deraadt 914: break;
1.4 millert 915: case BINDNO:
1.5 millert 916: #endif /* FKEYS */
1.1 deraadt 917: inmacro = TRUE;
918: maclcur = maclcur->l_fp;
1.5 millert 919: status = (*fp)(f, n);
1.1 deraadt 920: inmacro = FALSE;
921: #ifdef FKEYS
922: }
1.5 millert 923: #endif /* FKEYS */
1.1 deraadt 924: cleanup:
925: lp = maclcur->l_fp;
1.4 millert 926: while (lp != maclcur) {
927: np = lp->l_fp;
1.44 ! kjell 928: free(lp);
1.4 millert 929: lp = np;
1.1 deraadt 930: }
1.44 ! kjell 931: free(lp);
1.33 db 932: return (status);
1.1 deraadt 933: }
934:
935: /*
936: * a pair of utility functions for the above
937: */
938: static char *
1.23 vincent 939: skipwhite(char *s)
1.1 deraadt 940: {
1.4 millert 941: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
942: s++;
943: if (*s == ';')
944: *s = '\0';
1.33 db 945: return (s);
1.1 deraadt 946: }
947:
948: static char *
1.23 vincent 949: parsetoken(char *s)
1.1 deraadt 950: {
951: if (*s != '"') {
1.4 millert 952: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
953: s++;
954: if (*s == ';')
955: *s = '\0';
1.1 deraadt 956: } else
1.5 millert 957: do {
1.15 mickey 958: /*
959: * Strings get special treatment.
960: * Beware: You can \ out the end of the string!
1.5 millert 961: */
1.4 millert 962: if (*s == '\\')
963: ++s;
964: } while (*++s != '"' && *s != '\0');
1.33 db 965: return (s);
1.1 deraadt 966: }
1.5 millert 967: #endif /* !NO_STARTUP */