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