Annotation of src/usr.bin/mg/extend.c, Revision 1.15
1.15 ! mickey 1: /* $OpenBSD: extend.c,v 1.14 2001/05/23 23:29:47 mickey 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.5 millert 6:
7: #include "def.h"
8: #include "kbd.h"
1.1 deraadt 9:
10: #ifndef NO_MACRO
1.5 millert 11: #include "macro.h"
12: #endif /* !NO_MACRO */
1.1 deraadt 13:
14: #ifdef FKEYS
1.5 millert 15: #include "key.h"
1.1 deraadt 16: #ifndef NO_STARTUP
17: #ifndef BINDKEY
1.4 millert 18: #define BINDKEY /* bindkey is used by FKEYS startup code */
1.5 millert 19: #endif /* !BINDKEY */
20: #endif /* !NO_STARTUP */
21: #endif /* FKEYS */
22:
23: static int remap __P((KEYMAP *, int, PF, KEYMAP *));
24: static KEYMAP *realocmap __P((KEYMAP *));
1.12 art 25: static void fixmap __P((KEYMAP *, KEYMAP *, KEYMAP *));
1.5 millert 26: static int dobind __P((KEYMAP *, char *, int));
27: static char *skipwhite __P((char *));
28: static char *parsetoken __P((char *));
29: static int bindkey __P((KEYMAP **, char *, KCHAR *, int));
1.1 deraadt 30:
1.15 ! mickey 31: /*
! 32: * Insert a string, mainly for use from macros (created by selfinsert)
1.5 millert 33: */
1.4 millert 34: /* ARGSUSED */
35: int
1.1 deraadt 36: insert(f, n)
1.4 millert 37: int f, 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
86: remap(curmap, c, funct, pref_map)
1.15 ! mickey 87: KEYMAP *curmap; /* pointer to the map being changed */
! 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
1.4 millert 91: NULL for new */
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 *
262: realocmap(curmap)
1.5 millert 263: KEYMAP *curmap;
1.4 millert 264: {
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: }
283: for (i = nmaps; i--;) {
284: if (map_table[i].p_map == curmap)
285: map_table[i].p_map = mp;
286: else
287: fixmap(curmap, mp, map_table[i].p_map);
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.4 millert 297: fixmap(curmap, mp, mt)
298: KEYMAP *mt;
299: KEYMAP *curmap;
300: KEYMAP *mp;
301: {
1.5 millert 302: int i;
1.4 millert 303:
304: for (i = mt->map_num; i--;) {
305: if (mt->map_element[i].k_prefmap != NULL) {
306: if (mt->map_element[i].k_prefmap == curmap)
307: mt->map_element[i].k_prefmap = mp;
308: else
309: fixmap(curmap, mp, mt->map_element[i].k_prefmap);
310: }
1.1 deraadt 311: }
312: }
313:
314: /*
315: * do the input for local-set-key, global-set-key and define-key
316: * then call remap to do the work.
317: */
1.4 millert 318: static int
319: dobind(curmap, p, unbind)
1.15 ! mickey 320: KEYMAP *curmap;
! 321: char *p;
! 322: int unbind;
1.4 millert 323: {
1.5 millert 324: KEYMAP *pref_map = NULL;
325: PF funct;
326: char prompt[80];
327: char *pep;
328: int c, s;
1.1 deraadt 329:
330: #ifndef NO_MACRO
1.4 millert 331: if (macrodef) {
332: /*
333: * Keystrokes aren't collected. Not hard, but pretty useless.
334: * Would not work for function keys in any case.
335: */
336: ewprintf("Can't rebind key in macro");
337: return FALSE;
1.1 deraadt 338: }
339: #ifndef NO_STARTUP
1.4 millert 340: if (inmacro) {
341: for (s = 0; s < maclcur->l_used - 1; s++) {
1.8 art 342: if (doscan(curmap, c = CHARMASK(maclcur->l_text[s]), &curmap)
1.7 art 343: != NULL) {
1.13 art 344: if (remap(curmap, c, NULL, NULL)
1.4 millert 345: != TRUE)
346: return FALSE;
347: }
1.1 deraadt 348: }
1.12 art 349: (void)doscan(curmap, c = maclcur->l_text[s], NULL);
1.4 millert 350: maclcur = maclcur->l_fp;
1.1 deraadt 351: } else {
1.5 millert 352: #endif /* !NO_STARTUP */
353: #endif /* !NO_MACRO */
1.14 mickey 354: pep = prompt + strlcpy(prompt, p, sizeof(prompt));
1.4 millert 355: for (;;) {
356: ewprintf("%s", prompt);
357: pep[-1] = ' ';
1.14 mickey 358: pep = keyname(pep, sizeof(prompt) - (pep - prompt),
359: c = getkey(FALSE));
1.8 art 360: if (doscan(curmap, c, &curmap) != NULL)
1.4 millert 361: break;
362: *pep++ = '-';
363: *pep = '\0';
364: }
1.1 deraadt 365: #ifndef NO_STARTUP
366: }
1.5 millert 367: #endif /* !NO_STARTUP */
1.4 millert 368: if (unbind)
369: funct = rescan;
1.1 deraadt 370: else {
1.4 millert 371: if ((s = eread("%s to command: ", prompt, 80, EFFUNC | EFNEW,
372: prompt)) != TRUE)
373: return s;
1.7 art 374: if (((funct = name_function(prompt)) == NULL) ?
1.4 millert 375: (pref_map = name_map(prompt)) == NULL : funct == NULL) {
376: ewprintf("[No match]");
377: return FALSE;
378: }
1.1 deraadt 379: }
380: return remap(curmap, c, funct, pref_map);
381: }
382:
383: /*
1.15 ! mickey 384: * bindkey: bind key sequence to a function in the specified map. Used by
! 385: * excline so it can bind function keys. To close to release to change
! 386: * calling sequence, should just pass KEYMAP *curmap rather than
1.5 millert 387: * KEYMAP **mapp.
388: */
1.1 deraadt 389: #ifdef BINDKEY
1.5 millert 390: static int
1.1 deraadt 391: bindkey(mapp, fname, keys, kcount)
1.15 ! mickey 392: KEYMAP **mapp;
! 393: char *fname;
! 394: KCHAR *keys;
! 395: int kcount;
1.5 millert 396: {
397: KEYMAP *curmap = *mapp;
398: KEYMAP *pref_map = NULL;
399: PF funct;
400: int c;
1.1 deraadt 401:
1.4 millert 402: if (fname == NULL)
403: funct = rescan;
1.7 art 404: else if (((funct = name_function(fname)) == NULL) ?
1.5 millert 405: (pref_map = name_map(fname)) == NULL : funct == NULL) {
1.4 millert 406: ewprintf("[No match: %s]", fname);
407: return FALSE;
408: }
409: while (--kcount) {
1.8 art 410: if (doscan(curmap, c = *keys++, &curmap) != NULL) {
1.13 art 411: if (remap(curmap, c, NULL, NULL) != TRUE)
1.4 millert 412: return FALSE;
1.9 art 413: /*
414: * XXX - Bizzarreness. remap creates an empty KEYMAP
415: * that the last key is supposed to point to.
416: */
417: curmap = ele->k_prefmap;
1.4 millert 418: }
1.1 deraadt 419: }
1.12 art 420: (void)doscan(curmap, c = *keys, NULL);
1.1 deraadt 421: return remap(curmap, c, funct, pref_map);
422: }
1.3 millert 423:
424: #ifdef FKEYS
425: /*
426: * Wrapper for bindkey() that converts escapes.
427: */
428: int
429: dobindkey(map, func, str)
430: KEYMAP *map;
1.4 millert 431: char *func;
432: char *str;
1.3 millert 433: {
1.5 millert 434: int i;
1.3 millert 435:
436: for (i = 0; *str && i < MAXKEY; i++) {
437: /* XXX - convert numbers w/ strol()? */
438: if (*str != '\\')
439: key.k_chars[i] = *str;
440: else {
1.4 millert 441: switch (*++str) {
442: case 't':
443: case 'T':
1.3 millert 444: key.k_chars[i] = '\t';
445: break;
1.4 millert 446: case 'n':
447: case 'N':
1.3 millert 448: key.k_chars[i] = '\n';
449: break;
1.4 millert 450: case 'r':
451: case 'R':
1.3 millert 452: key.k_chars[i] = '\r';
453: break;
1.4 millert 454: case 'e':
455: case 'E':
1.3 millert 456: key.k_chars[i] = CCHR('[');
457: break;
458: }
459: }
460: str++;
461: }
462: key.k_count = i;
1.4 millert 463: return (bindkey(&map, func, key.k_chars, key.k_count));
1.3 millert 464: }
1.5 millert 465: #endif /* FKEYS */
466: #endif /* BINDKEY */
1.1 deraadt 467:
468: /*
469: * This function modifies the fundamental keyboard map.
470: */
1.4 millert 471: /* ARGSUSED */
472: int
1.1 deraadt 473: bindtokey(f, n)
1.4 millert 474: int f, n;
1.1 deraadt 475: {
1.11 art 476: return dobind(fundamental_map, "Global set key: ", FALSE);
1.1 deraadt 477: }
478:
479: /*
480: * This function modifies the current mode's keyboard map.
481: */
1.4 millert 482: /* ARGSUSED */
483: int
1.1 deraadt 484: localbind(f, n)
1.4 millert 485: int f, n;
1.1 deraadt 486: {
1.15 ! mickey 487: return dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
1.5 millert 488: "Local set key: ", FALSE);
1.1 deraadt 489: }
490:
491: /*
492: * This function redefines a key in any keymap.
493: */
1.4 millert 494: /* ARGSUSED */
495: int
1.1 deraadt 496: define_key(f, n)
1.4 millert 497: int f, n;
1.1 deraadt 498: {
1.5 millert 499: static char buf[48] = "Define key map: ";
1.10 art 500: KEYMAP *mp;
1.4 millert 501:
502: buf[16] = '\0';
503: if (eread(buf, &buf[16], 48 - 16, EFNEW) != TRUE)
504: return FALSE;
1.10 art 505: if ((mp = name_map(&buf[16])) == NULL) {
1.4 millert 506: ewprintf("Unknown map %s", &buf[16]);
507: return FALSE;
508: }
1.12 art 509: (void)strncat(&buf[16], " key: ", 48 - 16 - 1);
1.10 art 510: return dobind(mp, buf, FALSE);
1.1 deraadt 511: }
512:
1.4 millert 513: int
1.1 deraadt 514: unbindtokey(f, n)
1.4 millert 515: int f, n;
1.1 deraadt 516: {
1.11 art 517: return dobind(fundamental_map, "Global unset key: ", TRUE);
1.1 deraadt 518: }
519:
1.4 millert 520: int
1.1 deraadt 521: localunbind(f, n)
1.4 millert 522: int f, n;
1.1 deraadt 523: {
1.4 millert 524: return dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
525: "Local unset key: ", TRUE);
1.1 deraadt 526: }
527:
528: /*
1.15 ! mickey 529: * Extended command. Call the message line routine to read in the command
! 530: * name and apply autocompletion to it. When it comes back, look the name
! 531: * up in the symbol table and run the command if it is found. Print an
1.5 millert 532: * error if there is anything wrong.
1.1 deraadt 533: */
1.4 millert 534: int
1.1 deraadt 535: extend(f, n)
1.5 millert 536: int f, n;
1.1 deraadt 537: {
1.5 millert 538: PF funct;
539: int s;
540: char xname[NXNAME];
1.4 millert 541:
542: if (!(f & FFARG))
543: s = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
544: else
545: s = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
546: if (s != TRUE)
547: return s;
548: if ((funct = name_function(xname)) != NULL) {
1.1 deraadt 549: #ifndef NO_MACRO
1.4 millert 550: if (macrodef) {
1.5 millert 551: LINE *lp = maclcur;
1.4 millert 552: macro[macrocount - 1].m_funct = funct;
553: maclcur = lp->l_bp;
554: maclcur->l_fp = lp->l_fp;
1.5 millert 555: free((char *)lp);
1.4 millert 556: }
1.5 millert 557: #endif /* !NO_MACRO */
558: return (*funct)(f, n);
1.1 deraadt 559: }
560: ewprintf("[No match]");
561: return FALSE;
562: }
563:
564: #ifndef NO_STARTUP
565: /*
566: * Define the commands needed to do startup-file processing.
567: * This code is mostly a kludge just so we can get startup-file processing.
568: *
569: * If you're serious about having this code, you should rewrite it.
570: * To wit:
571: * It has lots of funny things in it to make the startup-file look
572: * like a GNU startup file; mostly dealing with parens and semicolons.
573: * This should all vanish.
574: *
575: * We define eval-expression because it's easy. It can make
576: * *-set-key or define-key set an arbitrary key sequence, so it isn't
577: * useless.
578: */
579:
580: /*
581: * evalexpr - get one line from the user, and run it.
582: */
1.4 millert 583: /* ARGSUSED */
584: int
1.1 deraadt 585: evalexpr(f, n)
1.5 millert 586: int f, n;
1.1 deraadt 587: {
1.5 millert 588: int s;
589: char exbuf[128];
1.1 deraadt 590:
591: if ((s = ereply("Eval: ", exbuf, 128)) != TRUE)
592: return s;
593: return excline(exbuf);
594: }
1.4 millert 595:
1.1 deraadt 596: /*
1.15 ! mickey 597: * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5 millert 598: * testing startup files.
1.1 deraadt 599: */
1.4 millert 600: /* ARGSUSED */
601: int
1.1 deraadt 602: evalbuffer(f, n)
1.5 millert 603: int f, n;
1.1 deraadt 604: {
1.5 millert 605: LINE *lp;
606: BUFFER *bp = curbp;
607: int s;
608: static char excbuf[128];
1.1 deraadt 609:
610: for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
1.4 millert 611: if (llength(lp) >= 128)
612: return FALSE;
1.12 art 613: (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5 millert 614:
615: /* make sure it's terminated */
616: excbuf[llength(lp)] = '\0';
1.4 millert 617: if ((s = excline(excbuf)) != TRUE)
618: return s;
1.1 deraadt 619: }
620: return TRUE;
621: }
1.4 millert 622:
1.1 deraadt 623: /*
624: * evalfile - go get a file and evaluate it as line commands. You can
625: * go get your own startup file if need be.
626: */
1.4 millert 627: /* ARGSUSED */
628: int
1.1 deraadt 629: evalfile(f, n)
1.5 millert 630: int f, n;
1.1 deraadt 631: {
1.5 millert 632: int s;
633: char fname[NFILEN];
1.1 deraadt 634:
635: if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
636: return s;
637: return load(fname);
638: }
639:
640: /*
641: * load - go load the file name we got passed.
642: */
1.4 millert 643: int
644: load(fname)
1.5 millert 645: char *fname;
1.4 millert 646: {
1.5 millert 647: int s = TRUE;
648: int nbytes;
649: char excbuf[128];
1.1 deraadt 650:
651: if ((fname = adjustname(fname)) == NULL)
1.5 millert 652: /* just to be careful */
653: return FALSE;
1.1 deraadt 654:
1.13 art 655: if (ffropen(fname, NULL) != FIOSUC)
1.4 millert 656: return FALSE;
1.5 millert 657:
1.4 millert 658: while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.1 deraadt 659: excbuf[nbytes] = '\0';
660: if (excline(excbuf) != TRUE) {
661: s = FIOERR;
662: ewprintf("Error loading file %s", fname);
663: break;
664: }
665: }
1.13 art 666: (void)ffclose(NULL);
1.1 deraadt 667: excbuf[nbytes] = '\0';
1.4 millert 668: if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.1 deraadt 669: return FALSE;
670: return TRUE;
671: }
672:
673: /*
1.15 ! mickey 674: * excline - run a line from a load file or eval-expression. if FKEYS is
! 675: * defined, duplicate functionallity of dobind so function key values don't
1.5 millert 676: * have to fit in type char.
1.1 deraadt 677: */
1.4 millert 678: int
1.1 deraadt 679: excline(line)
1.5 millert 680: char *line;
1.1 deraadt 681: {
1.5 millert 682: PF fp;
683: LINE *lp, *np;
684: int status, c, f, n;
685: char *funcp;
686: char *argp = NULL;
687: #ifdef FKEYS
688: int bind;
689: KEYMAP *curmap;
690: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
691: #define BINDNO 1 /* not binding or non-quoted BINDARG */
692: #define BINDNEXT 2 /* next arg " (define-key) */
693: #define BINDDO 3 /* already found key to bind */
694: #define BINDEXT 1 /* space for trailing \0 */
695: #else /* FKEYS */
696: #define BINDEXT 0
697: #endif /* FKEYS */
698:
699: lp = NULL;
1.1 deraadt 700:
1.4 millert 701: if (macrodef || inmacro) {
1.1 deraadt 702: ewprintf("Not now!");
703: return FALSE;
704: }
705: f = 0;
706: n = 1;
707: funcp = skipwhite(line);
1.4 millert 708: if (*funcp == '\0')
709: return TRUE; /* No error on blank lines */
1.1 deraadt 710: line = parsetoken(funcp);
711: if (*line != '\0') {
712: *line++ = '\0';
713: line = skipwhite(line);
714: if ((*line >= '0' && *line <= '9') || *line == '-') {
715: argp = line;
716: line = parsetoken(line);
717: }
718: }
719: if (argp != NULL) {
720: f = FFARG;
721: n = atoi(argp);
722: }
1.4 millert 723: if ((fp = name_function(funcp)) == NULL) {
724: ewprintf("Unknown function: %s", funcp);
725: return FALSE;
1.1 deraadt 726: }
727: #ifdef FKEYS
1.4 millert 728: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 729: bind = BINDARG;
1.11 art 730: curmap = fundamental_map;
1.4 millert 731: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 732: bind = BINDARG;
733: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.4 millert 734: } else if (fp == define_key)
735: bind = BINDNEXT;
736: else
737: bind = BINDNO;
1.5 millert 738: #endif /* FKEYS */
739: /* Pack away all the args now... */
1.4 millert 740: if ((np = lalloc(0)) == FALSE)
741: return FALSE;
1.1 deraadt 742: np->l_fp = np->l_bp = maclcur = np;
743: while (*line != '\0') {
744: argp = skipwhite(line);
1.4 millert 745: if (*argp == '\0')
746: break;
1.1 deraadt 747: line = parsetoken(argp);
748: if (*argp != '"') {
1.4 millert 749: if (*argp == '\'')
750: ++argp;
751: if (!(lp = lalloc((int) (line - argp) + BINDEXT))) {
752: status = FALSE;
753: goto cleanup;
754: }
1.5 millert 755: bcopy(argp, ltext(lp), (int)(line - argp));
1.1 deraadt 756: #ifdef FKEYS
1.5 millert 757: /* don't count BINDEXT */
758: lp->l_used--;
1.4 millert 759: if (bind == BINDARG)
760: bind = BINDNO;
1.5 millert 761: #endif /* FKEYS */
762: } else {
763: /* quoted strings are special */
1.4 millert 764: ++argp;
1.1 deraadt 765: #ifdef FKEYS
1.4 millert 766: if (bind != BINDARG) {
1.5 millert 767: #endif /* FKEYS */
768: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 769: if (lp == NULL) {
770: status = FALSE;
771: goto cleanup;
772: }
773: lp->l_used = 0;
1.1 deraadt 774: #ifdef FKEYS
1.4 millert 775: } else {
776: key.k_count = 0;
1.1 deraadt 777: }
1.5 millert 778: #endif /* FKEYS */
1.4 millert 779: while (*argp != '"' && *argp != '\0') {
780: if (*argp != '\\')
781: c = *argp++;
782: else {
783: switch (*++argp) {
784: case 't':
785: case 'T':
786: c = CCHR('I');
787: break;
788: case 'n':
789: case 'N':
790: c = CCHR('J');
791: break;
792: case 'r':
793: case 'R':
794: c = CCHR('M');
795: break;
796: case 'e':
797: case 'E':
798: c = CCHR('[');
799: break;
800: case '^':
801: /*
802: * split into two statements
803: * due to bug in OSK cpp
804: */
805: c = CHARMASK(*++argp);
806: c = ISLOWER(c) ?
807: CCHR(TOUPPER(c)) : CCHR(c);
808: break;
809: case '0':
810: case '1':
811: case '2':
812: case '3':
813: case '4':
814: case '5':
815: case '6':
816: case '7':
817: c = *argp - '0';
1.15 ! mickey 818: if (argp[1] <= '7' &&
1.5 millert 819: argp[1] >= '0') {
1.4 millert 820: c <<= 3;
821: c += *++argp - '0';
822: if (argp[1] <= '7' &&
823: argp[1] >= '0') {
824: c <<= 3;
825: c += *++argp
826: - '0';
827: }
828: }
829: break;
830: #ifdef FKEYS
831: case 'f':
832: case 'F':
833: c = *++argp - '0';
834: if (ISDIGIT(argp[1])) {
835: c *= 10;
836: c += *++argp - '0';
837: }
838: c += KFIRST;
839: break;
1.5 millert 840: #endif /* FKEYS */
1.4 millert 841: default:
842: c = CHARMASK(*argp);
843: break;
844: }
845: argp++;
846: }
1.1 deraadt 847: #ifdef FKEYS
1.4 millert 848: if (bind == BINDARG)
849: key.k_chars[key.k_count++] = c;
850: else
1.5 millert 851: #endif /* FKEYS */
1.4 millert 852: lp->l_text[lp->l_used++] = c;
853: }
854: if (*line)
855: line++;
1.1 deraadt 856: }
857: #ifdef FKEYS
1.4 millert 858: switch (bind) {
859: case BINDARG:
1.1 deraadt 860: bind = BINDDO;
861: break;
1.4 millert 862: case BINDNEXT:
1.1 deraadt 863: lp->l_text[lp->l_used] = '\0';
1.10 art 864: if ((curmap = name_map(lp->l_text)) == NULL) {
1.4 millert 865: ewprintf("No such mode: %s", lp->l_text);
866: status = FALSE;
1.5 millert 867: free((char *)lp);
1.4 millert 868: goto cleanup;
1.1 deraadt 869: }
1.5 millert 870: free((char *)lp);
1.1 deraadt 871: bind = BINDARG;
872: break;
1.4 millert 873: default:
1.5 millert 874: #endif /* FKEYS */
1.1 deraadt 875: lp->l_fp = np->l_fp;
876: lp->l_bp = np;
877: np->l_fp = lp;
878: np = lp;
879: #ifdef FKEYS
880: }
1.5 millert 881: #endif /* FKEYS */
1.1 deraadt 882: }
883: #ifdef FKEYS
1.4 millert 884: switch (bind) {
885: default:
1.1 deraadt 886: ewprintf("Bad args to set key");
887: status = FALSE;
888: break;
1.4 millert 889: case BINDDO:
890: if (fp != unbindtokey && fp != localunbind) {
891: lp->l_text[lp->l_used] = '\0';
892: status = bindkey(&curmap, lp->l_text, key.k_chars,
893: key.k_count);
1.13 art 894: } else {
895: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 896: key.k_count);
1.13 art 897: }
1.1 deraadt 898: break;
1.4 millert 899: case BINDNO:
1.5 millert 900: #endif /* FKEYS */
1.1 deraadt 901: inmacro = TRUE;
902: maclcur = maclcur->l_fp;
1.5 millert 903: status = (*fp)(f, n);
1.1 deraadt 904: inmacro = FALSE;
905: #ifdef FKEYS
906: }
1.5 millert 907: #endif /* FKEYS */
1.1 deraadt 908: cleanup:
909: lp = maclcur->l_fp;
1.4 millert 910: while (lp != maclcur) {
911: np = lp->l_fp;
1.5 millert 912: free((char *)lp);
1.4 millert 913: lp = np;
1.1 deraadt 914: }
1.5 millert 915: free((char *)lp);
1.1 deraadt 916: return status;
917: }
918:
919: /*
920: * a pair of utility functions for the above
921: */
922: static char *
923: skipwhite(s)
1.5 millert 924: char *s;
1.1 deraadt 925: {
1.4 millert 926: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
927: s++;
928: if (*s == ';')
929: *s = '\0';
1.1 deraadt 930: return s;
931: }
932:
933: static char *
934: parsetoken(s)
1.4 millert 935: char *s;
1.1 deraadt 936: {
937: if (*s != '"') {
1.4 millert 938: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
939: s++;
940: if (*s == ';')
941: *s = '\0';
1.1 deraadt 942: } else
1.5 millert 943: do {
1.15 ! mickey 944: /*
! 945: * Strings get special treatment.
! 946: * Beware: You can \ out the end of the string!
1.5 millert 947: */
1.4 millert 948: if (*s == '\\')
949: ++s;
950: } while (*++s != '"' && *s != '\0');
1.1 deraadt 951: return s;
952: }
1.5 millert 953: #endif /* !NO_STARTUP */