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