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