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