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