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