Annotation of src/usr.bin/mg/extend.c, Revision 1.80
1.80 ! op 1: /* $OpenBSD: extend.c,v 1.79 2023/03/30 22:56:47 op Exp $ */
1.34 kjell 2: /* This file is in the public domain. */
1.6 niklas 3:
1.1 deraadt 4: /*
1.65 lum 5: * Extended (M-x) commands, rebinding, and startup file processing.
1.1 deraadt 6: */
1.51 kjell 7:
1.60 bcallah 8: #include <sys/queue.h>
1.51 kjell 9: #include <sys/types.h>
1.67 lum 10: #include <regex.h>
1.51 kjell 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:
1.21 millert 25: static int remap(KEYMAP *, int, PF, KEYMAP *);
1.29 vincent 26: static KEYMAP *reallocmap(KEYMAP *);
1.21 millert 27: static void fixmap(KEYMAP *, KEYMAP *, KEYMAP *);
1.23 vincent 28: static int dobind(KEYMAP *, const char *, int);
1.21 millert 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: int
1.23 vincent 36: insert(int f, int n)
1.1 deraadt 37: {
1.69 lum 38: char buf[BUFSIZE], *bufp, *cp;
1.5 millert 39: int count, c;
1.1 deraadt 40:
1.4 millert 41: if (inmacro) {
42: while (--n >= 0) {
43: for (count = 0; count < maclcur->l_used; count++) {
1.72 lum 44: if ((((c = maclcur->l_text[count]) ==
45: *curbp->b_nlchr)
1.4 millert 46: ? lnewline() : linsert(1, c)) != TRUE)
1.33 db 47: return (FALSE);
1.4 millert 48: }
49: }
50: maclcur = maclcur->l_fp;
1.33 db 51: return (TRUE);
1.1 deraadt 52: }
1.4 millert 53: if (n == 1)
1.5 millert 54: /* CFINS means selfinsert can tack on the end */
55: thisflag |= CFINS;
1.52 lum 56:
1.31 vincent 57: if ((bufp = eread("Insert: ", buf, sizeof(buf), EFNEW)) == NULL)
1.33 db 58: return (ABORT);
1.31 vincent 59: else if (bufp[0] == '\0')
1.33 db 60: return (FALSE);
1.4 millert 61: while (--n >= 0) {
62: cp = buf;
63: while (*cp) {
1.72 lum 64: if (((*cp == *curbp->b_nlchr) ?
65: lnewline() : linsert(1, *cp))
1.4 millert 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
1.50 martin 81: * malloced versus static storage in both keymaps and map_elements.
1.1 deraadt 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.
1.49 kjell 85: * Parameters are:
86: * curmap: pointer to the map being changed
87: * c: character being changed
88: * funct: function being changed to
89: * pref_map: if funct==NULL, map to bind to or NULL for new
1.1 deraadt 90: */
1.4 millert 91: static int
1.49 kjell 92: remap(KEYMAP *curmap, int c, PF funct, KEYMAP *pref_map)
1.1 deraadt 93: {
1.5 millert 94: int i, n1, n2, nold;
1.30 vincent 95: KEYMAP *mp, *newmap;
1.5 millert 96: PF *pfp;
1.40 deraadt 97: struct map_element *mep;
1.4 millert 98:
99: if (ele >= &curmap->map_element[curmap->map_num] || c < ele->k_base) {
1.7 art 100: if (ele > &curmap->map_element[0] && (funct != NULL ||
1.5 millert 101: (ele - 1)->k_prefmap == NULL))
1.4 millert 102: n1 = c - (ele - 1)->k_num;
1.5 millert 103: else
1.4 millert 104: n1 = HUGE;
105: if (ele < &curmap->map_element[curmap->map_num] &&
1.7 art 106: (funct != NULL || ele->k_prefmap == NULL))
1.4 millert 107: n2 = ele->k_base - c;
1.5 millert 108: else
1.4 millert 109: n2 = HUGE;
110: if (n1 <= MAPELEDEF && n1 <= n2) {
111: ele--;
1.45 kjell 112: if ((pfp = calloc(c - ele->k_base + 1,
1.68 lum 113: sizeof(PF))) == NULL)
114: return (dobeep_msg("Out of memory"));
115:
1.4 millert 116: nold = ele->k_num - ele->k_base + 1;
117: for (i = 0; i < nold; i++)
118: pfp[i] = ele->k_funcp[i];
119: while (--n1)
120: pfp[i++] = curmap->map_default;
121: pfp[i] = funct;
122: ele->k_num = c;
123: ele->k_funcp = pfp;
124: } else if (n2 <= MAPELEDEF) {
1.45 kjell 125: if ((pfp = calloc(ele->k_num - c + 1,
1.68 lum 126: sizeof(PF))) == NULL)
127: return (dobeep_msg("Out of memory"));
128:
1.4 millert 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.68 lum 143: if ((pfp = malloc(sizeof(PF))) == NULL)
144: return (dobeep_msg("Out of memory"));
145:
1.4 millert 146: pfp[0] = funct;
147: for (mep = &curmap->map_element[curmap->map_num];
148: mep > ele; mep--) {
149: mep->k_base = (mep - 1)->k_base;
150: mep->k_num = (mep - 1)->k_num;
151: mep->k_funcp = (mep - 1)->k_funcp;
152: mep->k_prefmap = (mep - 1)->k_prefmap;
153: }
154: ele->k_base = c;
155: ele->k_num = c;
156: ele->k_funcp = pfp;
157: ele->k_prefmap = NULL;
158: curmap->map_num++;
159: }
1.7 art 160: if (funct == NULL) {
1.29 vincent 161: if (pref_map != NULL)
1.4 millert 162: ele->k_prefmap = pref_map;
1.29 vincent 163: else {
1.45 kjell 164: if ((mp = malloc(sizeof(KEYMAP) +
1.40 deraadt 165: (MAPINIT - 1) * sizeof(struct map_element))) == NULL) {
1.68 lum 166: (void)dobeep_msg("Out of memory");
1.4 millert 167: ele->k_funcp[c - ele->k_base] =
168: curmap->map_default;
1.33 db 169: return (FALSE);
1.4 millert 170: }
171: mp->map_num = 0;
172: mp->map_max = MAPINIT;
173: mp->map_default = rescan;
174: ele->k_prefmap = mp;
175: }
1.1 deraadt 176: }
177: } else {
1.4 millert 178: n1 = c - ele->k_base;
1.7 art 179: if (ele->k_funcp[n1] == funct && (funct != NULL ||
1.4 millert 180: pref_map == NULL || pref_map == ele->k_prefmap))
1.5 millert 181: /* no change */
1.33 db 182: return (TRUE);
1.7 art 183: if (funct != NULL || ele->k_prefmap == NULL) {
184: if (ele->k_funcp[n1] == NULL)
1.13 art 185: ele->k_prefmap = NULL;
1.5 millert 186: /* easy case */
187: ele->k_funcp[n1] = funct;
1.7 art 188: if (funct == NULL) {
1.4 millert 189: if (pref_map != NULL)
190: ele->k_prefmap = pref_map;
191: else {
1.28 vincent 192: if ((mp = malloc(sizeof(KEYMAP) +
1.15 mickey 193: (MAPINIT - 1) *
1.40 deraadt 194: sizeof(struct map_element))) == NULL) {
1.68 lum 195: (void)dobeep_msg("Out of memory");
1.4 millert 196: ele->k_funcp[c - ele->k_base] =
197: curmap->map_default;
1.33 db 198: return (FALSE);
1.4 millert 199: }
200: mp->map_num = 0;
201: mp->map_max = MAPINIT;
202: mp->map_default = rescan;
203: ele->k_prefmap = mp;
204: }
205: }
206: } else {
207: /*
1.5 millert 208: * This case is the splits.
209: * Determine which side of the break c goes on
1.4 millert 210: * 0 = after break; 1 = before break
211: */
212: n2 = 1;
213: for (i = 0; n2 && i < n1; i++)
1.7 art 214: n2 &= ele->k_funcp[i] != NULL;
1.49 kjell 215: if (curmap->map_num >= curmap->map_max) {
216: if ((newmap = reallocmap(curmap)) == NULL)
217: return (FALSE);
218: curmap = newmap;
219: }
1.45 kjell 220: if ((pfp = calloc(ele->k_num - c + !n2,
1.68 lum 221: sizeof(PF))) == NULL)
222: return (dobeep_msg("Out of memory"));
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)
1.40 deraadt 242: * sizeof(struct map_element))) == NULL) {
1.68 lum 243: (void)dobeep_msg("Out of memory");
1.4 millert 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: /*
1.49 kjell 260: * Reallocate a keymap. Returns NULL (without trashing the current map)
261: * on failure.
1.4 millert 262: */
263: static KEYMAP *
1.29 vincent 264: reallocmap(KEYMAP *curmap)
1.4 millert 265: {
1.40 deraadt 266: struct maps_s *mps;
1.5 millert 267: KEYMAP *mp;
268: int i;
1.4 millert 269:
1.45 kjell 270: if (curmap->map_max > SHRT_MAX - MAPGROW) {
1.68 lum 271: (void)dobeep_msg("keymap too large");
1.45 kjell 272: return (NULL);
273: }
274: if ((mp = malloc(sizeof(KEYMAP) + (curmap->map_max + (MAPGROW - 1)) *
275: sizeof(struct map_element))) == NULL) {
1.68 lum 276: (void)dobeep_msg("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.41 kjell 325: char bprompt[80], *bufp, *pep;
1.26 vincent 326: int c, s, n;
1.1 deraadt 327:
1.4 millert 328: if (macrodef) {
329: /*
330: * Keystrokes aren't collected. Not hard, but pretty useless.
331: * Would not work for function keys in any case.
332: */
1.68 lum 333: return (dobeep_msg("Can't rebind key in macro"));
1.1 deraadt 334: }
1.4 millert 335: if (inmacro) {
336: for (s = 0; s < maclcur->l_used - 1; s++) {
1.8 art 337: if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap)
1.7 art 338: != NULL) {
1.13 art 339: if (remap(curmap, c, NULL, NULL)
1.4 millert 340: != TRUE)
1.33 db 341: return (FALSE);
1.4 millert 342: }
1.1 deraadt 343: }
1.12 art 344: (void)doscan(curmap, c = maclcur->l_text[s], NULL);
1.4 millert 345: maclcur = maclcur->l_fp;
1.1 deraadt 346: } else {
1.41 kjell 347: n = strlcpy(bprompt, p, sizeof(bprompt));
348: if (n >= sizeof(bprompt))
349: n = sizeof(bprompt) - 1;
350: pep = bprompt + n;
1.4 millert 351: for (;;) {
1.41 kjell 352: ewprintf("%s", bprompt);
1.4 millert 353: pep[-1] = ' ';
1.42 kjell 354: pep = getkeyname(pep, sizeof(bprompt) -
1.41 kjell 355: (pep - bprompt), c = getkey(FALSE));
1.8 art 356: if (doscan(curmap, c, &curmap) != NULL)
1.4 millert 357: break;
358: *pep++ = '-';
359: *pep = '\0';
360: }
1.1 deraadt 361: }
1.4 millert 362: if (unbind)
363: funct = rescan;
1.1 deraadt 364: else {
1.41 kjell 365: if ((bufp = eread("%s to command: ", bprompt, sizeof(bprompt),
366: EFFUNC | EFNEW, bprompt)) == NULL)
1.33 db 367: return (ABORT);
1.31 vincent 368: else if (bufp[0] == '\0')
1.33 db 369: return (FALSE);
1.41 kjell 370: if (((funct = name_function(bprompt)) == NULL) ?
1.68 lum 371: (pref_map = name_map(bprompt)) == NULL : funct == NULL)
372: return (dobeep_msg("[No match]"));
373:
1.1 deraadt 374: }
1.33 db 375: return (remap(curmap, c, funct, pref_map));
1.1 deraadt 376: }
377:
378: /*
1.15 mickey 379: * bindkey: bind key sequence to a function in the specified map. Used by
380: * excline so it can bind function keys. To close to release to change
381: * calling sequence, should just pass KEYMAP *curmap rather than
1.5 millert 382: * KEYMAP **mapp.
383: */
384: static int
1.23 vincent 385: bindkey(KEYMAP **mapp, const char *fname, KCHAR *keys, int kcount)
1.5 millert 386: {
387: KEYMAP *curmap = *mapp;
388: KEYMAP *pref_map = NULL;
389: PF funct;
390: int c;
1.1 deraadt 391:
1.4 millert 392: if (fname == NULL)
393: funct = rescan;
1.7 art 394: else if (((funct = name_function(fname)) == NULL) ?
1.5 millert 395: (pref_map = name_map(fname)) == NULL : funct == NULL) {
1.54 lum 396: dobeep();
1.4 millert 397: ewprintf("[No match: %s]", fname);
1.33 db 398: return (FALSE);
1.4 millert 399: }
400: while (--kcount) {
1.8 art 401: if (doscan(curmap, c = *keys++, &curmap) != NULL) {
1.13 art 402: if (remap(curmap, c, NULL, NULL) != TRUE)
1.33 db 403: return (FALSE);
1.9 art 404: /*
405: * XXX - Bizzarreness. remap creates an empty KEYMAP
406: * that the last key is supposed to point to.
407: */
408: curmap = ele->k_prefmap;
1.4 millert 409: }
1.1 deraadt 410: }
1.12 art 411: (void)doscan(curmap, c = *keys, NULL);
1.33 db 412: return (remap(curmap, c, funct, pref_map));
1.1 deraadt 413: }
1.3 millert 414:
415: /*
416: * Wrapper for bindkey() that converts escapes.
417: */
418: int
1.23 vincent 419: dobindkey(KEYMAP *map, const char *func, const char *str)
1.3 millert 420: {
1.5 millert 421: int i;
1.3 millert 422:
423: for (i = 0; *str && i < MAXKEY; i++) {
424: /* XXX - convert numbers w/ strol()? */
1.38 kjell 425: if (*str == '^' && *(str + 1) != '\0') {
1.56 guenther 426: key.k_chars[i] = CCHR(toupper((unsigned char)*++str));
1.38 kjell 427: } else if (*str == '\\' && *(str + 1) != '\0') {
1.4 millert 428: switch (*++str) {
1.38 kjell 429: case '^':
430: key.k_chars[i] = '^';
431: break;
1.4 millert 432: case 't':
433: case 'T':
1.3 millert 434: key.k_chars[i] = '\t';
435: break;
1.4 millert 436: case 'n':
437: case 'N':
1.72 lum 438: key.k_chars[i] = *curbp->b_nlchr;
1.3 millert 439: break;
1.4 millert 440: case 'r':
441: case 'R':
1.3 millert 442: key.k_chars[i] = '\r';
443: break;
1.4 millert 444: case 'e':
445: case 'E':
1.3 millert 446: key.k_chars[i] = CCHR('[');
447: break;
1.38 kjell 448: case '\\':
449: key.k_chars[i] = '\\';
450: break;
1.3 millert 451: }
1.38 kjell 452: } else
453: key.k_chars[i] = *str;
1.3 millert 454: str++;
455: }
456: key.k_count = i;
1.4 millert 457: return (bindkey(&map, func, key.k_chars, key.k_count));
1.3 millert 458: }
1.1 deraadt 459:
460: /*
461: * This function modifies the fundamental keyboard map.
462: */
1.4 millert 463: int
1.23 vincent 464: bindtokey(int f, int n)
1.1 deraadt 465: {
1.33 db 466: return (dobind(fundamental_map, "Global set key: ", FALSE));
1.1 deraadt 467: }
468:
469: /*
470: * This function modifies the current mode's keyboard map.
471: */
1.4 millert 472: int
1.23 vincent 473: localbind(int f, int n)
1.1 deraadt 474: {
1.33 db 475: return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
476: "Local set key: ", FALSE));
1.1 deraadt 477: }
478:
479: /*
480: * This function redefines a key in any keymap.
481: */
1.4 millert 482: int
1.42 kjell 483: redefine_key(int f, int n)
1.1 deraadt 484: {
1.33 db 485: static char buf[48];
486: char tmp[32], *bufp;
487: KEYMAP *mp;
488:
1.43 kjell 489: (void)strlcpy(buf, "Define key map: ", sizeof(buf));
1.63 guenther 490: if ((bufp = eread("%s", tmp, sizeof(tmp), EFNEW, buf)) == NULL)
1.33 db 491: return (ABORT);
1.31 vincent 492: else if (bufp[0] == '\0')
1.33 db 493: return (FALSE);
1.35 kjell 494: (void)strlcat(buf, tmp, sizeof(buf));
1.68 lum 495: if ((mp = name_map(tmp)) == NULL)
1.80 ! op 496: return (dobeep_msgs("Unknown map", tmp));
1.68 lum 497:
1.43 kjell 498: if (strlcat(buf, "key: ", sizeof(buf)) >= sizeof(buf))
499: return (FALSE);
1.19 vincent 500:
1.33 db 501: return (dobind(mp, buf, FALSE));
1.1 deraadt 502: }
503:
1.4 millert 504: int
1.23 vincent 505: unbindtokey(int f, int n)
1.1 deraadt 506: {
1.33 db 507: return (dobind(fundamental_map, "Global unset key: ", TRUE));
1.1 deraadt 508: }
509:
1.4 millert 510: int
1.27 vincent 511: localunbind(int f, int n)
1.1 deraadt 512: {
1.33 db 513: return (dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
514: "Local unset key: ", TRUE));
1.1 deraadt 515: }
516:
517: /*
1.15 mickey 518: * Extended command. Call the message line routine to read in the command
519: * name and apply autocompletion to it. When it comes back, look the name
520: * up in the symbol table and run the command if it is found. Print an
1.5 millert 521: * error if there is anything wrong.
1.1 deraadt 522: */
1.4 millert 523: int
1.23 vincent 524: extend(int f, int n)
1.1 deraadt 525: {
1.5 millert 526: PF funct;
1.31 vincent 527: char xname[NXNAME], *bufp;
1.4 millert 528:
529: if (!(f & FFARG))
1.31 vincent 530: bufp = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
1.4 millert 531: else
1.31 vincent 532: bufp = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
533: if (bufp == NULL)
1.33 db 534: return (ABORT);
1.31 vincent 535: else if (bufp[0] == '\0')
1.33 db 536: return (FALSE);
1.31 vincent 537: if ((funct = name_function(bufp)) != NULL) {
1.4 millert 538: if (macrodef) {
1.40 deraadt 539: struct line *lp = maclcur;
1.4 millert 540: macro[macrocount - 1].m_funct = funct;
541: maclcur = lp->l_bp;
542: maclcur->l_fp = lp->l_fp;
1.44 kjell 543: free(lp);
1.4 millert 544: }
1.33 db 545: return ((*funct)(f, n));
1.1 deraadt 546: }
1.68 lum 547: return (dobeep_msg("[No match]"));
1.1 deraadt 548: }
549:
550: /*
551: * Define the commands needed to do startup-file processing.
552: * This code is mostly a kludge just so we can get startup-file processing.
553: *
554: * If you're serious about having this code, you should rewrite it.
555: * To wit:
556: * It has lots of funny things in it to make the startup-file look
557: * like a GNU startup file; mostly dealing with parens and semicolons.
558: * This should all vanish.
559: *
560: * We define eval-expression because it's easy. It can make
561: * *-set-key or define-key set an arbitrary key sequence, so it isn't
562: * useless.
563: */
564:
565: /*
566: * evalexpr - get one line from the user, and run it.
1.74 lum 567: * Use strlen for length of line, assume user is not typing in a '\0' in the
568: * modeline. llen only used for foundparen() so old-school will be ok.
1.1 deraadt 569: */
1.4 millert 570: int
1.23 vincent 571: evalexpr(int f, int n)
1.1 deraadt 572: {
1.69 lum 573: char exbuf[BUFSIZE], *bufp;
1.74 lum 574: int llen;
1.1 deraadt 575:
1.35 kjell 576: if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
577: EFNEW | EFCR)) == NULL)
1.33 db 578: return (ABORT);
1.31 vincent 579: else if (bufp[0] == '\0')
1.33 db 580: return (FALSE);
1.74 lum 581: llen = strlen(bufp);
582:
1.75 lum 583: return (excline(exbuf, llen, 1));
1.1 deraadt 584: }
1.4 millert 585:
1.1 deraadt 586: /*
1.15 mickey 587: * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5 millert 588: * testing startup files.
1.1 deraadt 589: */
1.4 millert 590: int
1.23 vincent 591: evalbuffer(int f, int n)
1.1 deraadt 592: {
1.40 deraadt 593: struct line *lp;
594: struct buffer *bp = curbp;
1.75 lum 595: int s, llen, lnum = 0;
1.69 lum 596: static char excbuf[BUFSIZE];
1.1 deraadt 597:
1.48 kjell 598: for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) {
1.75 lum 599: lnum++;
1.74 lum 600: llen = llength(lp);
601: if (llen >= BUFSIZE)
1.33 db 602: return (FALSE);
1.74 lum 603: (void)strncpy(excbuf, ltext(lp), llen);
1.5 millert 604:
1.74 lum 605: /* make sure the line is terminated */
606: excbuf[llen] = '\0';
1.75 lum 607: if ((s = excline(excbuf, llen, lnum)) != TRUE) {
1.73 lum 608: cleanup();
1.33 db 609: return (s);
1.71 lum 610: }
1.1 deraadt 611: }
1.73 lum 612: cleanup();
1.33 db 613: return (TRUE);
1.1 deraadt 614: }
1.4 millert 615:
1.1 deraadt 616: /*
617: * evalfile - go get a file and evaluate it as line commands. You can
618: * go get your own startup file if need be.
619: */
1.4 millert 620: int
1.23 vincent 621: evalfile(int f, int n)
1.1 deraadt 622: {
1.78 op 623: FILE *ffp;
1.31 vincent 624: char fname[NFILEN], *bufp;
1.78 op 625: int ret;
1.1 deraadt 626:
1.35 kjell 627: if ((bufp = eread("Load file: ", fname, NFILEN,
628: EFNEW | EFCR)) == NULL)
1.33 db 629: return (ABORT);
1.78 op 630: if (bufp[0] == '\0')
631: return (FALSE);
632: if ((bufp = adjustname(fname, TRUE)) == NULL)
633: return (FALSE);
634: ret = ffropen(&ffp, bufp, NULL);
635: if (ret == FIODIR)
636: (void)ffclose(ffp, NULL);
637: if (ret != FIOSUC)
1.33 db 638: return (FALSE);
1.78 op 639: ret = load(ffp, bufp);
640: (void)ffclose(ffp, NULL);
641: return (ret);
1.1 deraadt 642: }
643:
644: /*
645: * load - go load the file name we got passed.
646: */
1.4 millert 647: int
1.78 op 648: load(FILE *ffp, const char *fname)
1.4 millert 649: {
1.78 op 650: int s = TRUE, line;
1.18 matthieu 651: int nbytes = 0;
1.79 op 652: char excbuf[BUFSIZE];
1.5 millert 653:
1.25 vincent 654: line = 0;
1.53 lum 655: while ((s = ffgetline(ffp, excbuf, sizeof(excbuf) - 1, &nbytes))
656: == FIOSUC) {
1.25 vincent 657: line++;
1.1 deraadt 658: excbuf[nbytes] = '\0';
1.75 lum 659: if (excline(excbuf, nbytes, line) != TRUE) {
1.1 deraadt 660: s = FIOERR;
1.54 lum 661: dobeep();
1.79 op 662: ewprintf("Error loading file %s at line %d", fname, line);
1.1 deraadt 663: break;
664: }
665: }
666: excbuf[nbytes] = '\0';
1.75 lum 667: if (s != FIOEOF || (nbytes && excline(excbuf, nbytes, ++line) != TRUE))
1.33 db 668: return (FALSE);
669: return (TRUE);
1.1 deraadt 670: }
671:
672: /*
1.59 bcallah 673: * excline - run a line from a load file or eval-expression.
1.1 deraadt 674: */
1.4 millert 675: int
1.75 lum 676: excline(char *line, int llen, int lnum)
1.1 deraadt 677: {
1.5 millert 678: PF fp;
1.40 deraadt 679: struct line *lp, *np;
1.5 millert 680: int status, c, f, n;
1.22 ho 681: char *funcp, *tmp;
1.5 millert 682: char *argp = NULL;
1.22 ho 683: long nl;
1.5 millert 684: int bind;
685: KEYMAP *curmap;
686: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
687: #define BINDNO 1 /* not binding or non-quoted BINDARG */
688: #define BINDNEXT 2 /* next arg " (define-key) */
689: #define BINDDO 3 /* already found key to bind */
690: #define BINDEXT 1 /* space for trailing \0 */
691:
692: lp = NULL;
1.1 deraadt 693:
1.68 lum 694: if (macrodef || inmacro)
695: return (dobeep_msg("Not now!"));
696:
1.1 deraadt 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.67 lum 702: if (*funcp == '(')
1.75 lum 703: return (foundparen(funcp, llen, lnum));
1.1 deraadt 704: line = parsetoken(funcp);
705: if (*line != '\0') {
706: *line++ = '\0';
707: line = skipwhite(line);
1.20 vincent 708: if (ISDIGIT(*line) || *line == '-') {
1.1 deraadt 709: argp = line;
710: line = parsetoken(line);
711: }
712: }
713: if (argp != NULL) {
714: f = FFARG;
1.22 ho 715: nl = strtol(argp, &tmp, 10);
1.20 vincent 716: if (*tmp != '\0')
1.33 db 717: return (FALSE);
1.22 ho 718: if (nl >= INT_MAX || nl <= INT_MIN)
1.33 db 719: return (FALSE);
1.22 ho 720: n = (int)nl;
1.1 deraadt 721: }
1.68 lum 722: if ((fp = name_function(funcp)) == NULL)
1.80 ! op 723: return (dobeep_msgs("Unknown function:", funcp));
1.68 lum 724:
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.42 kjell 731: } else if (fp == redefine_key)
1.4 millert 732: bind = BINDNEXT;
733: else
734: bind = BINDNO;
1.5 millert 735: /* Pack away all the args now... */
1.4 millert 736: if ((np = lalloc(0)) == FALSE)
1.33 db 737: return (FALSE);
1.1 deraadt 738: np->l_fp = np->l_bp = maclcur = np;
739: while (*line != '\0') {
740: argp = skipwhite(line);
1.4 millert 741: if (*argp == '\0')
742: break;
1.1 deraadt 743: line = parsetoken(argp);
744: if (*argp != '"') {
1.4 millert 745: if (*argp == '\'')
746: ++argp;
1.20 vincent 747: if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
748: NULL) {
1.4 millert 749: status = FALSE;
750: goto cleanup;
751: }
1.5 millert 752: bcopy(argp, ltext(lp), (int)(line - argp));
753: /* don't count BINDEXT */
754: lp->l_used--;
1.4 millert 755: if (bind == BINDARG)
756: bind = BINDNO;
1.5 millert 757: } else {
758: /* quoted strings are special */
1.4 millert 759: ++argp;
760: if (bind != BINDARG) {
1.5 millert 761: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 762: if (lp == NULL) {
763: status = FALSE;
764: goto cleanup;
765: }
766: lp->l_used = 0;
1.33 db 767: } else
1.4 millert 768: key.k_count = 0;
769: while (*argp != '"' && *argp != '\0') {
770: if (*argp != '\\')
771: c = *argp++;
772: else {
773: switch (*++argp) {
774: case 't':
775: case 'T':
776: c = CCHR('I');
777: break;
778: case 'n':
779: case 'N':
780: c = CCHR('J');
781: break;
782: case 'r':
783: case 'R':
784: c = CCHR('M');
785: break;
786: case 'e':
787: case 'E':
788: c = CCHR('[');
789: break;
790: case '^':
791: /*
792: * split into two statements
793: * due to bug in OSK cpp
794: */
795: c = CHARMASK(*++argp);
796: c = ISLOWER(c) ?
797: CCHR(TOUPPER(c)) : CCHR(c);
798: break;
799: case '0':
800: case '1':
801: case '2':
802: case '3':
803: case '4':
804: case '5':
805: case '6':
806: case '7':
807: c = *argp - '0';
1.15 mickey 808: if (argp[1] <= '7' &&
1.5 millert 809: argp[1] >= '0') {
1.4 millert 810: c <<= 3;
811: c += *++argp - '0';
812: if (argp[1] <= '7' &&
813: argp[1] >= '0') {
814: c <<= 3;
815: c += *++argp
816: - '0';
817: }
818: }
819: break;
820: case 'f':
821: case 'F':
822: c = *++argp - '0';
823: if (ISDIGIT(argp[1])) {
824: c *= 10;
825: c += *++argp - '0';
826: }
827: c += KFIRST;
828: break;
829: default:
830: c = CHARMASK(*argp);
831: break;
832: }
833: argp++;
834: }
835: if (bind == BINDARG)
836: key.k_chars[key.k_count++] = c;
837: else
838: lp->l_text[lp->l_used++] = c;
839: }
840: if (*line)
841: line++;
1.1 deraadt 842: }
1.4 millert 843: switch (bind) {
844: case BINDARG:
1.1 deraadt 845: bind = BINDDO;
846: break;
1.4 millert 847: case BINDNEXT:
1.1 deraadt 848: lp->l_text[lp->l_used] = '\0';
1.10 art 849: if ((curmap = name_map(lp->l_text)) == NULL) {
1.80 ! op 850: (void)dobeep_msgs("No such mode:", lp->l_text);
1.4 millert 851: status = FALSE;
1.44 kjell 852: free(lp);
1.4 millert 853: goto cleanup;
1.1 deraadt 854: }
1.44 kjell 855: free(lp);
1.1 deraadt 856: bind = BINDARG;
857: break;
1.4 millert 858: default:
1.1 deraadt 859: lp->l_fp = np->l_fp;
860: lp->l_bp = np;
861: np->l_fp = lp;
862: np = lp;
863: }
864: }
1.4 millert 865: switch (bind) {
866: default:
1.68 lum 867: (void)dobeep_msg("Bad args to set key");
1.1 deraadt 868: status = FALSE;
869: break;
1.4 millert 870: case BINDDO:
871: if (fp != unbindtokey && fp != localunbind) {
872: lp->l_text[lp->l_used] = '\0';
873: status = bindkey(&curmap, lp->l_text, key.k_chars,
874: key.k_count);
1.33 db 875: } else
1.13 art 876: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 877: key.k_count);
1.1 deraadt 878: break;
1.4 millert 879: case BINDNO:
1.1 deraadt 880: inmacro = TRUE;
881: maclcur = maclcur->l_fp;
1.5 millert 882: status = (*fp)(f, n);
1.1 deraadt 883: inmacro = FALSE;
884: }
885: cleanup:
886: lp = maclcur->l_fp;
1.4 millert 887: while (lp != maclcur) {
888: np = lp->l_fp;
1.44 kjell 889: free(lp);
1.4 millert 890: lp = np;
1.1 deraadt 891: }
1.44 kjell 892: free(lp);
1.62 florian 893: maclhead = NULL;
894: macrodef = FALSE;
1.33 db 895: return (status);
1.1 deraadt 896: }
897:
898: /*
899: * a pair of utility functions for the above
900: */
1.70 lum 901: char *
1.23 vincent 902: skipwhite(char *s)
1.1 deraadt 903: {
1.67 lum 904: while (*s == ' ' || *s == '\t')
1.4 millert 905: s++;
1.55 lum 906: if ((*s == ';') || (*s == '#'))
1.4 millert 907: *s = '\0';
1.33 db 908: return (s);
1.1 deraadt 909: }
910:
911: static char *
1.23 vincent 912: parsetoken(char *s)
1.1 deraadt 913: {
914: if (*s != '"') {
1.4 millert 915: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
916: s++;
917: if (*s == ';')
918: *s = '\0';
1.1 deraadt 919: } else
1.5 millert 920: do {
1.15 mickey 921: /*
922: * Strings get special treatment.
923: * Beware: You can \ out the end of the string!
1.5 millert 924: */
1.4 millert 925: if (*s == '\\')
926: ++s;
927: } while (*++s != '"' && *s != '\0');
1.33 db 928: return (s);
1.1 deraadt 929: }