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