Annotation of src/usr.bin/mg/extend.c, Revision 1.22
1.22 ! ho 1: /* $OpenBSD: extend.c,v 1.21 2002/02/16 21:27:49 millert 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 *);
27: static int dobind(KEYMAP *, char *, int);
28: static char *skipwhite(char *);
29: static char *parsetoken(char *);
30: static int bindkey(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;
1.22 ! ho 689: char *funcp, *tmp;
1.5 millert 690: char *argp = NULL;
1.22 ! ho 691: long nl;
1.5 millert 692: #ifdef FKEYS
693: int bind;
694: KEYMAP *curmap;
695: #define BINDARG 0 /* this arg is key to bind (local/global set key) */
696: #define BINDNO 1 /* not binding or non-quoted BINDARG */
697: #define BINDNEXT 2 /* next arg " (define-key) */
698: #define BINDDO 3 /* already found key to bind */
699: #define BINDEXT 1 /* space for trailing \0 */
700: #else /* FKEYS */
701: #define BINDEXT 0
702: #endif /* FKEYS */
703:
704: lp = NULL;
1.1 deraadt 705:
1.4 millert 706: if (macrodef || inmacro) {
1.1 deraadt 707: ewprintf("Not now!");
708: return FALSE;
709: }
710: f = 0;
711: n = 1;
712: funcp = skipwhite(line);
1.4 millert 713: if (*funcp == '\0')
714: return TRUE; /* No error on blank lines */
1.1 deraadt 715: line = parsetoken(funcp);
716: if (*line != '\0') {
717: *line++ = '\0';
718: line = skipwhite(line);
1.20 vincent 719: if (ISDIGIT(*line) || *line == '-') {
1.1 deraadt 720: argp = line;
721: line = parsetoken(line);
722: }
723: }
724: if (argp != NULL) {
725: f = FFARG;
1.20 vincent 726: errno = 0;
1.22 ! ho 727: nl = strtol(argp, &tmp, 10);
1.20 vincent 728: if (*tmp != '\0')
729: return FALSE;
1.22 ! ho 730: if (nl >= INT_MAX || nl <= INT_MIN)
1.20 vincent 731: return FALSE;
1.22 ! ho 732: n = (int)nl;
1.1 deraadt 733: }
1.4 millert 734: if ((fp = name_function(funcp)) == NULL) {
735: ewprintf("Unknown function: %s", funcp);
736: return FALSE;
1.1 deraadt 737: }
738: #ifdef FKEYS
1.4 millert 739: if (fp == bindtokey || fp == unbindtokey) {
1.1 deraadt 740: bind = BINDARG;
1.11 art 741: curmap = fundamental_map;
1.4 millert 742: } else if (fp == localbind || fp == localunbind) {
1.1 deraadt 743: bind = BINDARG;
744: curmap = curbp->b_modes[curbp->b_nmodes]->p_map;
1.4 millert 745: } else if (fp == define_key)
746: bind = BINDNEXT;
747: else
748: bind = BINDNO;
1.5 millert 749: #endif /* FKEYS */
750: /* Pack away all the args now... */
1.4 millert 751: if ((np = lalloc(0)) == FALSE)
752: return FALSE;
1.1 deraadt 753: np->l_fp = np->l_bp = maclcur = np;
754: while (*line != '\0') {
755: argp = skipwhite(line);
1.4 millert 756: if (*argp == '\0')
757: break;
1.1 deraadt 758: line = parsetoken(argp);
759: if (*argp != '"') {
1.4 millert 760: if (*argp == '\'')
761: ++argp;
1.20 vincent 762: if ((lp = lalloc((int) (line - argp) + BINDEXT)) ==
763: NULL) {
1.4 millert 764: status = FALSE;
765: goto cleanup;
766: }
1.5 millert 767: bcopy(argp, ltext(lp), (int)(line - argp));
1.1 deraadt 768: #ifdef FKEYS
1.5 millert 769: /* don't count BINDEXT */
770: lp->l_used--;
1.4 millert 771: if (bind == BINDARG)
772: bind = BINDNO;
1.5 millert 773: #endif /* FKEYS */
774: } else {
775: /* quoted strings are special */
1.4 millert 776: ++argp;
1.1 deraadt 777: #ifdef FKEYS
1.4 millert 778: if (bind != BINDARG) {
1.5 millert 779: #endif /* FKEYS */
780: lp = lalloc((int)(line - argp) + BINDEXT);
1.4 millert 781: if (lp == NULL) {
782: status = FALSE;
783: goto cleanup;
784: }
785: lp->l_used = 0;
1.1 deraadt 786: #ifdef FKEYS
1.4 millert 787: } else {
788: key.k_count = 0;
1.1 deraadt 789: }
1.5 millert 790: #endif /* FKEYS */
1.4 millert 791: while (*argp != '"' && *argp != '\0') {
792: if (*argp != '\\')
793: c = *argp++;
794: else {
795: switch (*++argp) {
796: case 't':
797: case 'T':
798: c = CCHR('I');
799: break;
800: case 'n':
801: case 'N':
802: c = CCHR('J');
803: break;
804: case 'r':
805: case 'R':
806: c = CCHR('M');
807: break;
808: case 'e':
809: case 'E':
810: c = CCHR('[');
811: break;
812: case '^':
813: /*
814: * split into two statements
815: * due to bug in OSK cpp
816: */
817: c = CHARMASK(*++argp);
818: c = ISLOWER(c) ?
819: CCHR(TOUPPER(c)) : CCHR(c);
820: break;
821: case '0':
822: case '1':
823: case '2':
824: case '3':
825: case '4':
826: case '5':
827: case '6':
828: case '7':
829: c = *argp - '0';
1.15 mickey 830: if (argp[1] <= '7' &&
1.5 millert 831: argp[1] >= '0') {
1.4 millert 832: c <<= 3;
833: c += *++argp - '0';
834: if (argp[1] <= '7' &&
835: argp[1] >= '0') {
836: c <<= 3;
837: c += *++argp
838: - '0';
839: }
840: }
841: break;
842: #ifdef FKEYS
843: case 'f':
844: case 'F':
845: c = *++argp - '0';
846: if (ISDIGIT(argp[1])) {
847: c *= 10;
848: c += *++argp - '0';
849: }
850: c += KFIRST;
851: break;
1.5 millert 852: #endif /* FKEYS */
1.4 millert 853: default:
854: c = CHARMASK(*argp);
855: break;
856: }
857: argp++;
858: }
1.1 deraadt 859: #ifdef FKEYS
1.4 millert 860: if (bind == BINDARG)
861: key.k_chars[key.k_count++] = c;
862: else
1.5 millert 863: #endif /* FKEYS */
1.4 millert 864: lp->l_text[lp->l_used++] = c;
865: }
866: if (*line)
867: line++;
1.1 deraadt 868: }
869: #ifdef FKEYS
1.4 millert 870: switch (bind) {
871: case BINDARG:
1.1 deraadt 872: bind = BINDDO;
873: break;
1.4 millert 874: case BINDNEXT:
1.1 deraadt 875: lp->l_text[lp->l_used] = '\0';
1.10 art 876: if ((curmap = name_map(lp->l_text)) == NULL) {
1.4 millert 877: ewprintf("No such mode: %s", lp->l_text);
878: status = FALSE;
1.5 millert 879: free((char *)lp);
1.4 millert 880: goto cleanup;
1.1 deraadt 881: }
1.5 millert 882: free((char *)lp);
1.1 deraadt 883: bind = BINDARG;
884: break;
1.4 millert 885: default:
1.5 millert 886: #endif /* FKEYS */
1.1 deraadt 887: lp->l_fp = np->l_fp;
888: lp->l_bp = np;
889: np->l_fp = lp;
890: np = lp;
891: #ifdef FKEYS
892: }
1.5 millert 893: #endif /* FKEYS */
1.1 deraadt 894: }
895: #ifdef FKEYS
1.4 millert 896: switch (bind) {
897: default:
1.1 deraadt 898: ewprintf("Bad args to set key");
899: status = FALSE;
900: break;
1.4 millert 901: case BINDDO:
902: if (fp != unbindtokey && fp != localunbind) {
903: lp->l_text[lp->l_used] = '\0';
904: status = bindkey(&curmap, lp->l_text, key.k_chars,
905: key.k_count);
1.13 art 906: } else {
907: status = bindkey(&curmap, NULL, key.k_chars,
1.4 millert 908: key.k_count);
1.13 art 909: }
1.1 deraadt 910: break;
1.4 millert 911: case BINDNO:
1.5 millert 912: #endif /* FKEYS */
1.1 deraadt 913: inmacro = TRUE;
914: maclcur = maclcur->l_fp;
1.5 millert 915: status = (*fp)(f, n);
1.1 deraadt 916: inmacro = FALSE;
917: #ifdef FKEYS
918: }
1.5 millert 919: #endif /* FKEYS */
1.1 deraadt 920: cleanup:
921: lp = maclcur->l_fp;
1.4 millert 922: while (lp != maclcur) {
923: np = lp->l_fp;
1.5 millert 924: free((char *)lp);
1.4 millert 925: lp = np;
1.1 deraadt 926: }
1.5 millert 927: free((char *)lp);
1.1 deraadt 928: return status;
929: }
930:
931: /*
932: * a pair of utility functions for the above
933: */
934: static char *
935: skipwhite(s)
1.5 millert 936: char *s;
1.1 deraadt 937: {
1.4 millert 938: while (*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
939: s++;
940: if (*s == ';')
941: *s = '\0';
1.1 deraadt 942: return s;
943: }
944:
945: static char *
946: parsetoken(s)
1.4 millert 947: char *s;
1.1 deraadt 948: {
949: if (*s != '"') {
1.4 millert 950: while (*s && *s != ' ' && *s != '\t' && *s != ')' && *s != '(')
951: s++;
952: if (*s == ';')
953: *s = '\0';
1.1 deraadt 954: } else
1.5 millert 955: do {
1.15 mickey 956: /*
957: * Strings get special treatment.
958: * Beware: You can \ out the end of the string!
1.5 millert 959: */
1.4 millert 960: if (*s == '\\')
961: ++s;
962: } while (*++s != '"' && *s != '\0');
1.1 deraadt 963: return s;
964: }
1.5 millert 965: #endif /* !NO_STARTUP */