Annotation of src/usr.bin/mg/extend.c, Revision 1.18
1.18 ! matthieu 1: /* $OpenBSD: extend.c,v 1.17 2001/05/24 10:43:17 art 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.1 deraadt 498: define_key(f, n)
1.4 millert 499: int f, n;
1.1 deraadt 500: {
1.5 millert 501: static char buf[48] = "Define key map: ";
1.10 art 502: KEYMAP *mp;
1.4 millert 503:
504: buf[16] = '\0';
505: if (eread(buf, &buf[16], 48 - 16, EFNEW) != TRUE)
506: return FALSE;
1.10 art 507: if ((mp = name_map(&buf[16])) == NULL) {
1.4 millert 508: ewprintf("Unknown map %s", &buf[16]);
509: return FALSE;
510: }
1.12 art 511: (void)strncat(&buf[16], " key: ", 48 - 16 - 1);
1.10 art 512: return dobind(mp, buf, FALSE);
1.1 deraadt 513: }
514:
1.4 millert 515: int
1.1 deraadt 516: unbindtokey(f, n)
1.4 millert 517: int f, n;
1.1 deraadt 518: {
1.11 art 519: return dobind(fundamental_map, "Global unset key: ", TRUE);
1.1 deraadt 520: }
521:
1.4 millert 522: int
1.1 deraadt 523: localunbind(f, n)
1.4 millert 524: int f, n;
1.1 deraadt 525: {
1.4 millert 526: return dobind(curbp->b_modes[curbp->b_nmodes]->p_map,
527: "Local unset key: ", TRUE);
1.1 deraadt 528: }
529:
530: /*
1.15 mickey 531: * Extended command. Call the message line routine to read in the command
532: * name and apply autocompletion to it. When it comes back, look the name
533: * up in the symbol table and run the command if it is found. Print an
1.5 millert 534: * error if there is anything wrong.
1.1 deraadt 535: */
1.4 millert 536: int
1.1 deraadt 537: extend(f, n)
1.5 millert 538: int f, n;
1.1 deraadt 539: {
1.5 millert 540: PF funct;
541: int s;
542: char xname[NXNAME];
1.4 millert 543:
544: if (!(f & FFARG))
545: s = eread("M-x ", xname, NXNAME, EFNEW | EFFUNC);
546: else
547: s = eread("%d M-x ", xname, NXNAME, EFNEW | EFFUNC, n);
548: if (s != TRUE)
549: return s;
550: if ((funct = name_function(xname)) != NULL) {
1.1 deraadt 551: #ifndef NO_MACRO
1.4 millert 552: if (macrodef) {
1.5 millert 553: LINE *lp = maclcur;
1.4 millert 554: macro[macrocount - 1].m_funct = funct;
555: maclcur = lp->l_bp;
556: maclcur->l_fp = lp->l_fp;
1.5 millert 557: free((char *)lp);
1.4 millert 558: }
1.5 millert 559: #endif /* !NO_MACRO */
560: return (*funct)(f, n);
1.1 deraadt 561: }
562: ewprintf("[No match]");
563: return FALSE;
564: }
565:
566: #ifndef NO_STARTUP
567: /*
568: * Define the commands needed to do startup-file processing.
569: * This code is mostly a kludge just so we can get startup-file processing.
570: *
571: * If you're serious about having this code, you should rewrite it.
572: * To wit:
573: * It has lots of funny things in it to make the startup-file look
574: * like a GNU startup file; mostly dealing with parens and semicolons.
575: * This should all vanish.
576: *
577: * We define eval-expression because it's easy. It can make
578: * *-set-key or define-key set an arbitrary key sequence, so it isn't
579: * useless.
580: */
581:
582: /*
583: * evalexpr - get one line from the user, and run it.
584: */
1.4 millert 585: /* ARGSUSED */
586: int
1.1 deraadt 587: evalexpr(f, n)
1.5 millert 588: int f, n;
1.1 deraadt 589: {
1.5 millert 590: int s;
591: char exbuf[128];
1.1 deraadt 592:
593: if ((s = ereply("Eval: ", exbuf, 128)) != TRUE)
594: return s;
595: return excline(exbuf);
596: }
1.4 millert 597:
1.1 deraadt 598: /*
1.15 mickey 599: * evalbuffer - evaluate the current buffer as line commands. Useful for
1.5 millert 600: * testing startup files.
1.1 deraadt 601: */
1.4 millert 602: /* ARGSUSED */
603: int
1.1 deraadt 604: evalbuffer(f, n)
1.5 millert 605: int f, n;
1.1 deraadt 606: {
1.5 millert 607: LINE *lp;
608: BUFFER *bp = curbp;
609: int s;
610: static char excbuf[128];
1.1 deraadt 611:
612: for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
1.4 millert 613: if (llength(lp) >= 128)
614: return FALSE;
1.12 art 615: (void)strncpy(excbuf, ltext(lp), llength(lp));
1.5 millert 616:
617: /* make sure it's terminated */
618: excbuf[llength(lp)] = '\0';
1.4 millert 619: if ((s = excline(excbuf)) != TRUE)
620: return s;
1.1 deraadt 621: }
622: return TRUE;
623: }
1.4 millert 624:
1.1 deraadt 625: /*
626: * evalfile - go get a file and evaluate it as line commands. You can
627: * go get your own startup file if need be.
628: */
1.4 millert 629: /* ARGSUSED */
630: int
1.1 deraadt 631: evalfile(f, n)
1.5 millert 632: int f, n;
1.1 deraadt 633: {
1.5 millert 634: int s;
635: char fname[NFILEN];
1.1 deraadt 636:
637: if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
638: return s;
639: return load(fname);
640: }
641:
642: /*
643: * load - go load the file name we got passed.
644: */
1.4 millert 645: int
646: load(fname)
1.5 millert 647: char *fname;
1.4 millert 648: {
1.5 millert 649: int s = TRUE;
1.18 ! matthieu 650: int nbytes = 0;
1.5 millert 651: char excbuf[128];
1.1 deraadt 652:
653: if ((fname = adjustname(fname)) == NULL)
1.5 millert 654: /* just to be careful */
655: return FALSE;
1.1 deraadt 656:
1.13 art 657: if (ffropen(fname, NULL) != FIOSUC)
1.4 millert 658: return FALSE;
1.5 millert 659:
1.4 millert 660: while ((s = ffgetline(excbuf, sizeof(excbuf) - 1, &nbytes)) == FIOSUC) {
1.1 deraadt 661: excbuf[nbytes] = '\0';
662: if (excline(excbuf) != TRUE) {
663: s = FIOERR;
664: ewprintf("Error loading file %s", fname);
665: break;
666: }
667: }
1.13 art 668: (void)ffclose(NULL);
1.1 deraadt 669: excbuf[nbytes] = '\0';
1.4 millert 670: if (s != FIOEOF || (nbytes && excline(excbuf) != TRUE))
1.1 deraadt 671: return FALSE;
672: return TRUE;
673: }
674:
675: /*
1.15 mickey 676: * excline - run a line from a load file or eval-expression. if FKEYS is
677: * defined, duplicate functionallity of dobind so function key values don't
1.5 millert 678: * have to fit in type char.
1.1 deraadt 679: */
1.4 millert 680: int
1.1 deraadt 681: excline(line)
1.5 millert 682: char *line;
1.1 deraadt 683: {
1.5 millert 684: PF fp;
685: LINE *lp, *np;
686: int status, c, f, n;
687: char *funcp;
688: char *argp = NULL;
689: #ifdef FKEYS
690: int bind;
691: KEYMAP *curmap;
692: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
693: #define BINDNO 1 /* not binding or non-quoted BINDARG */
694: #define BINDNEXT 2 /* next arg " (define-key) */
695: #define BINDDO 3 /* already found key to bind */
696: #define BINDEXT 1 /* space for trailing \0 */
697: #else /* FKEYS */
698: #define BINDEXT 0
699: #endif /* FKEYS */
700:
701: lp = NULL;
1.1 deraadt 702:
1.4 millert 703: if (macrodef || inmacro) {
1.1 deraadt 704: ewprintf("Not now!");
705: return FALSE;
706: }
707: f = 0;
708: n = 1;
709: funcp = skipwhite(line);
1.4 millert 710: if (*funcp == '\0')
711: return TRUE; /* No error on blank lines */
1.1 deraadt 712: line = parsetoken(funcp);
713: if (*line != '\0') {
714: *line++ = '\0';
715: line = skipwhite(line);
716: if ((*line >= '0' && *line <= '9') || *line == '-') {
717: argp = line;
718: line = parsetoken(line);
719: }
720: }
721: if (argp != NULL) {
722: f = FFARG;
723: n = atoi(argp);
724: }
1.4 millert 725: if ((fp = name_function(funcp)) == NULL) {
726: ewprintf("Unknown function: %s", funcp);
727: return FALSE;
1.1 deraadt 728: }
729: #ifdef FKEYS
1.4 millert 730: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 731: bind = BINDARG;
1.11 art 732: curmap = fundamental_map;
1.4 millert 733: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 734: bind = BINDARG;
735: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.4 millert 736: } else if (fp == define_key)
737: bind = BINDNEXT;
738: else
739: bind = BINDNO;
1.5 millert 740: #endif /* FKEYS */
741: /* Pack away all the args now... */
1.4 millert 742: if ((np = lalloc(0)) == FALSE)
743: return FALSE;
1.1 deraadt 744: np->l_fp = np->l_bp = maclcur = np;
745: while (*line != '\0') {
746: argp = skipwhite(line);
1.4 millert 747: if (*argp == '\0')
748: break;
1.1 deraadt 749: line = parsetoken(argp);
750: if (*argp != '"') {
1.4 millert 751: if (*argp == '\'')
752: ++argp;
753: if (!(lp = lalloc((int) (line - argp) + BINDEXT))) {
754: status = FALSE;
755: goto cleanup;
756: }
1.5 millert 757: bcopy(argp, ltext(lp), (int)(line - argp));
1.1 deraadt 758: #ifdef FKEYS
1.5 millert 759: /* don't count BINDEXT */
760: lp->l_used--;
1.4 millert 761: if (bind == BINDARG)
762: bind = BINDNO;
1.5 millert 763: #endif /* FKEYS */
764: } else {
765: /* quoted strings are special */
1.4 millert 766: ++argp;
1.1 deraadt 767: #ifdef FKEYS
1.4 millert 768: if (bind != BINDARG) {
1.5 millert 769: #endif /* FKEYS */
770: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 771: if (lp == NULL) {
772: status = FALSE;
773: goto cleanup;
774: }
775: lp->l_used = 0;
1.1 deraadt 776: #ifdef FKEYS
1.4 millert 777: } else {
778: key.k_count = 0;
1.1 deraadt 779: }
1.5 millert 780: #endif /* FKEYS */
1.4 millert 781: while (*argp != '"' && *argp != '\0') {
782: if (*argp != '\\')
783: c = *argp++;
784: else {
785: switch (*++argp) {
786: case 't':
787: case 'T':
788: c = CCHR('I');
789: break;
790: case 'n':
791: case 'N':
792: c = CCHR('J');
793: break;
794: case 'r':
795: case 'R':
796: c = CCHR('M');
797: break;
798: case 'e':
799: case 'E':
800: c = CCHR('[');
801: break;
802: case '^':
803: /*
804: * split into two statements
805: * due to bug in OSK cpp
806: */
807: c = CHARMASK(*++argp);
808: c = ISLOWER(c) ?
809: CCHR(TOUPPER(c)) : CCHR(c);
810: break;
811: case '0':
812: case '1':
813: case '2':
814: case '3':
815: case '4':
816: case '5':
817: case '6':
818: case '7':
819: c = *argp - '0';
1.15 mickey 820: if (argp[1] <= '7' &&
1.5 millert 821: argp[1] >= '0') {
1.4 millert 822: c <<= 3;
823: c += *++argp - '0';
824: if (argp[1] <= '7' &&
825: argp[1] >= '0') {
826: c <<= 3;
827: c += *++argp
828: - '0';
829: }
830: }
831: break;
832: #ifdef FKEYS
833: case 'f':
834: case 'F':
835: c = *++argp - '0';
836: if (ISDIGIT(argp[1])) {
837: c *= 10;
838: c += *++argp - '0';
839: }
840: c += KFIRST;
841: break;
1.5 millert 842: #endif /* FKEYS */
1.4 millert 843: default:
844: c = CHARMASK(*argp);
845: break;
846: }
847: argp++;
848: }
1.1 deraadt 849: #ifdef FKEYS
1.4 millert 850: if (bind == BINDARG)
851: key.k_chars[key.k_count++] = c;
852: else
1.5 millert 853: #endif /* FKEYS */
1.4 millert 854: lp->l_text[lp->l_used++] = c;
855: }
856: if (*line)
857: line++;
1.1 deraadt 858: }
859: #ifdef FKEYS
1.4 millert 860: switch (bind) {
861: case BINDARG:
1.1 deraadt 862: bind = BINDDO;
863: break;
1.4 millert 864: case BINDNEXT:
1.1 deraadt 865: lp->l_text[lp->l_used] = '\0';
1.10 art 866: if ((curmap = name_map(lp->l_text)) == NULL) {
1.4 millert 867: ewprintf("No such mode: %s", lp->l_text);
868: status = FALSE;
1.5 millert 869: free((char *)lp);
1.4 millert 870: goto cleanup;
1.1 deraadt 871: }
1.5 millert 872: free((char *)lp);
1.1 deraadt 873: bind = BINDARG;
874: break;
1.4 millert 875: default:
1.5 millert 876: #endif /* FKEYS */
1.1 deraadt 877: lp->l_fp = np->l_fp;
878: lp->l_bp = np;
879: np->l_fp = lp;
880: np = lp;
881: #ifdef FKEYS
882: }
1.5 millert 883: #endif /* FKEYS */
1.1 deraadt 884: }
885: #ifdef FKEYS
1.4 millert 886: switch (bind) {
887: default:
1.1 deraadt 888: ewprintf("Bad args to set key");
889: status = FALSE;
890: break;
1.4 millert 891: case BINDDO:
892: if (fp != unbindtokey && fp != localunbind) {
893: lp->l_text[lp->l_used] = '\0';
894: status = bindkey(&curmap, lp->l_text, key.k_chars,
895: key.k_count);
1.13 art 896: } else {
897: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 898: key.k_count);
1.13 art 899: }
1.1 deraadt 900: break;
1.4 millert 901: case BINDNO:
1.5 millert 902: #endif /* FKEYS */
1.1 deraadt 903: inmacro = TRUE;
904: maclcur = maclcur->l_fp;
1.5 millert 905: status = (*fp)(f, n);
1.1 deraadt 906: inmacro = FALSE;
907: #ifdef FKEYS
908: }
1.5 millert 909: #endif /* FKEYS */
1.1 deraadt 910: cleanup:
911: lp = maclcur->l_fp;
1.4 millert 912: while (lp != maclcur) {
913: np = lp->l_fp;
1.5 millert 914: free((char *)lp);
1.4 millert 915: lp = np;
1.1 deraadt 916: }
1.5 millert 917: free((char *)lp);
1.1 deraadt 918: return status;
919: }
920:
921: /*
922: * a pair of utility functions for the above
923: */
924: static char *
925: skipwhite(s)
1.5 millert 926: char *s;
1.1 deraadt 927: {
1.4 millert 928: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
929: s++;
930: if (*s == ';')
931: *s = '\0';
1.1 deraadt 932: return s;
933: }
934:
935: static char *
936: parsetoken(s)
1.4 millert 937: char *s;
1.1 deraadt 938: {
939: if (*s != '"') {
1.4 millert 940: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
941: s++;
942: if (*s == ';')
943: *s = '\0';
1.1 deraadt 944: } else
1.5 millert 945: do {
1.15 mickey 946: /*
947: * Strings get special treatment.
948: * Beware: You can \ out the end of the string!
1.5 millert 949: */
1.4 millert 950: if (*s == '\\')
951: ++s;
952: } while (*++s != '"' && *s != '\0');
1.1 deraadt 953: return s;
954: }
1.5 millert 955: #endif /* !NO_STARTUP */