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