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