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