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