Annotation of src/usr.bin/mg/interpreter.c, Revision 1.22
1.22 ! lum 1: /* $OpenBSD: interpreter.c,v 1.21 2021/04/20 14:26:19 lum Exp $ */
1.1 lum 2: /*
3: * This file is in the public domain.
4: *
5: * Author: Mark Lumsden <mark@showcomplex.com>
6: */
7:
8: /*
9: * This file attempts to add some 'scripting' functionality into mg.
10: *
11: * The initial goal is to give mg the ability to use it's existing functions
12: * and structures in a linked-up way. Hopefully resulting in user definable
13: * functions. The syntax is 'scheme' like but currently it is not a scheme
14: * interpreter.
15: *
16: * At the moment there is no manual page reference to this file. The code below
17: * is liable to change, so use at your own risk!
18: *
19: * If you do want to do some testing, you can add some lines to your .mg file
20: * like:
21: *
22: * 1. Give multiple arguments to a function that usually would accept only one:
1.11 lum 23: * (find-file "a.txt" "b.txt" "c.txt")
1.1 lum 24: *
1.7 lum 25: * 2. Define a single value variable:
1.11 lum 26: * (define myfile "d.txt")
1.1 lum 27: *
1.7 lum 28: * 3. Define a list:
1.11 lum 29: * (define myfiles(list "e.txt" "f.txt"))
1.7 lum 30: *
31: * 4. Use the previously defined variable or list:
1.1 lum 32: * (find-file myfiles)
33: *
34: * To do:
35: * 1. multiline parsing - currently only single lines supported.
36: * 2. parsing for '(' and ')' throughout whole string and evaluate correctly.
37: * 3. conditional execution.
1.11 lum 38: * 4. deal with special characters in a string: "x\" x" etc
1.19 lum 39: * 5. do symbol names need more complex regex patterns? [A-Za-z][.0-9_A-Z+a-z-]
40: * at the moment.
1.11 lum 41: * 6. oh so many things....
1.1 lum 42: * [...]
43: * n. implement user definable functions.
1.11 lum 44: *
1.14 lum 45: * Notes:
46: * - Currently calls to excline() from this file have the line length set to
47: * zero. That's because excline() uses '\0' as the end of line indicator
48: * and only the call to foundparen() within excline() uses excline's 2nd
49: * argument. Importantly, any lines sent to there from here will not be
50: * coming back here.
1.1 lum 51: */
52: #include <sys/queue.h>
1.13 lum 53:
54: #include <limits.h>
1.1 lum 55: #include <regex.h>
56: #include <signal.h>
57: #include <stdio.h>
58: #include <stdlib.h>
59: #include <string.h>
60:
61: #include "def.h"
62: #include "funmap.h"
63:
1.2 lum 64: #ifdef MGLOG
65: #include "kbd.h"
66: #include "log.h"
67: #endif
68:
1.21 lum 69: static int multiarg(char *, char *, int);
1.1 lum 70: static int isvar(char **, char **, int);
1.21 lum 71: /*static int dofunc(char **, char **, int);*/
72: static int founddef(char *, int, int, int);
73: static int foundlst(char *, int, int);
74: static int expandvals(char *, char *, char *);
75: static int foundfun(char *, int);
1.8 lum 76: static int doregex(char *, char *);
1.10 lum 77: static void clearexp(void);
1.21 lum 78: static int parse(char *, const char *, const char *, int, int);
79: static int parsdef(char *, const char *, const char *, int, int);
80: static int parsval(char *, const char *, const char *, int, int);
81: static int parsexp(char *, const char *, const char *, int, int);
82:
83: static int exitinterpreter(char *, char *, int);
1.10 lum 84:
1.12 lum 85: TAILQ_HEAD(exphead, expentry) ehead;
1.10 lum 86: struct expentry {
1.12 lum 87: TAILQ_ENTRY(expentry) eentry;
1.21 lum 88: char *fun; /* The 1st string found between parens. */
89: char funbuf[BUFSIZE];
90: const char *par1; /* Parenthesis at start of string */
91: const char *par2; /* Parenthesis at end of string */
1.10 lum 92: int expctr; /* An incremental counter:+1 for each exp */
93: int blkid; /* Which block are we in? */
94: };
1.1 lum 95:
96: /*
97: * Structure for variables during buffer evaluation.
98: */
99: struct varentry {
100: SLIST_ENTRY(varentry) entry;
1.21 lum 101: char valbuf[BUFSIZE];
1.1 lum 102: char *name;
103: char *vals;
104: int count;
1.21 lum 105: int expctr;
106: int blkid;
1.1 lum 107: };
108: SLIST_HEAD(vlisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);
109:
110: /*
1.12 lum 111: * Structure for scheme keywords.
112: */
113: #define NUMSCHKEYS 4
114: #define MAXLENSCHKEYS 17 /* 17 = longest keyword (16) + 1 */
115:
116: char scharkey[NUMSCHKEYS][MAXLENSCHKEYS] =
117: {
118: "define",
119: "list",
120: "if",
121: "lambda"
122: };
123:
1.21 lum 124: const char lp = '(';
125: const char rp = ')';
126: char *defnam = NULL;
1.12 lum 127:
128: /*
1.10 lum 129: * Line has a '(' as the first non-white char.
130: * Do some very basic parsing of line.
131: * Multi-line not supported at the moment, To do.
132: */
133: int
1.14 lum 134: foundparen(char *funstr, int llen)
1.10 lum 135: {
1.21 lum 136: const char *lrp = NULL;
1.15 lum 137: char *p, *begp = NULL, *endp = NULL, *regs;
1.18 lum 138: int i, ret, pctr, expctr, blkid, inquote;
1.10 lum 139:
1.18 lum 140: pctr = expctr = inquote = 0;
1.10 lum 141: blkid = 1;
142:
143: /*
144: * Currently can't do () or (( at the moment,
145: * just drop out - stops a segv. TODO.
146: */
147: regs = "[(]+[\t ]*[)]+";
148: if (doregex(regs, funstr))
149: return(dobeep_msg("Empty lists not supported at moment"));
150: regs = "[(]+[\t ]*[(]+";
151: if (doregex(regs, funstr))
1.11 lum 152: return(dobeep_msg("Multiple consecutive left parantheses "\
153: "found."));
1.10 lum 154: /*
155: * load expressions into a list called 'expentry', to be processd
156: * when all are obtained.
157: * Not really live code at the moment. Just part of the process of
158: * working out what needs to be done.
159: */
1.12 lum 160: TAILQ_INIT(&ehead);
161:
1.17 lum 162: /*
163: * Check for blocks of code with opening and closing ().
164: * One block = (cmd p a r a m)
165: * Two blocks = (cmd p a r a m s)(hola)
166: * Two blocks = (cmd p a r (list a m s))(hola)
167: * Only single line at moment, but more for multiline.
168: */
169: p = funstr;
170:
1.18 lum 171: for (i = 0; i < llen; ++i, p++) {
1.10 lum 172: if (*p == '(') {
1.21 lum 173: if (inquote == 1) {
174: cleanup();
175: return(dobeep_msg("Opening and closing quote "\
176: "char error"));
177: }
1.18 lum 178: if (begp != NULL) {
1.10 lum 179: if (endp == NULL)
180: *p = '\0';
181: else
182: *endp = '\0';
1.17 lum 183:
1.21 lum 184: ret = parse(begp, lrp, &lp, blkid, ++expctr);
1.17 lum 185: if (!ret) {
1.11 lum 186: cleanup();
1.17 lum 187: return(ret);
1.11 lum 188: }
1.10 lum 189: }
1.21 lum 190: lrp = &lp;
1.18 lum 191: begp = endp = NULL;
1.10 lum 192: pctr++;
193: } else if (*p == ')') {
1.11 lum 194: if (inquote == 1) {
195: cleanup();
196: return(dobeep_msg("Opening and closing quote "\
197: "char error"));
198: }
1.18 lum 199: if (begp != NULL) {
1.17 lum 200: if (endp == NULL)
201: *p = '\0';
202: else
203: *endp = '\0';
204:
1.21 lum 205: ret = parse(begp, lrp, &rp, blkid, ++expctr);
1.17 lum 206: if (!ret) {
207: cleanup();
208: return(ret);
209: }
1.11 lum 210: }
1.21 lum 211: lrp = &rp;
1.18 lum 212: begp = endp = NULL;
1.10 lum 213: pctr--;
214: } else if (*p != ' ' && *p != '\t') {
1.18 lum 215: if (begp == NULL)
216: begp = p;
1.11 lum 217: if (*p == '"') {
218: if (inquote == 0)
219: inquote = 1;
220: else
221: inquote = 0;
222: }
1.10 lum 223: endp = NULL;
1.18 lum 224: } else if (endp == NULL && (*p == ' ' || *p == '\t')) {
1.10 lum 225: *p = ' ';
226: endp = p;
1.12 lum 227: } else if (*p == '\t')
1.11 lum 228: if (inquote == 0)
229: *p = ' ';
1.15 lum 230:
1.21 lum 231: if (pctr == 0) {
1.10 lum 232: blkid++;
1.21 lum 233: expctr = 0;
234: defnam = NULL;
235: }
1.10 lum 236: }
237:
1.11 lum 238: if (pctr != 0) {
239: cleanup();
240: return(dobeep_msg("Opening and closing parentheses error"));
241: }
242: if (ret == FALSE)
243: cleanup();
244: else
245: clearexp(); /* leave lists but remove expressions */
1.10 lum 246:
247: return (ret);
1.17 lum 248: }
249:
250:
251: static int
1.21 lum 252: parse(char *begp, const char *par1, const char *par2, int blkid, int expctr)
1.17 lum 253: {
1.21 lum 254: char *regs;
255: int ret = FALSE;
256:
257: if (strncmp(begp, "define", 6) == 0) {
258: ret = parsdef(begp, par1, par2, blkid, expctr);
259: if (ret == TRUE || ret == FALSE)
260: return (ret);
261: } else if (strncmp(begp, "list", 4) == 0)
262: return(parsval(begp, par1, par2, blkid, expctr));
263:
264: regs = "^exit$";
265: if (doregex(regs, begp))
266: return(exitinterpreter(NULL, NULL, FALSE));
1.17 lum 267:
1.21 lum 268: /* mg function name regex */
269: regs = "^[A-Za-z-]+$";
270: if (doregex(regs, begp))
271: return(excline(begp, 0));
272:
273: /* Corner case 1 */
274: if (strncmp(begp, "global-set-key ", 15) == 0)
275: /* function name as 2nd param screws up multiarg. */
276: return(excline(begp, 0));
277:
278: /* Corner case 2 */
279: if (strncmp(begp, "define-key ", 11) == 0)
280: /* function name as 3rd param screws up multiarg. */
281: return(excline(begp, 0));
1.17 lum 282:
1.21 lum 283: return (parsexp(begp, par1, par2, blkid, expctr));
1.10 lum 284: }
285:
286: static int
1.21 lum 287: parsdef(char *begp, const char *par1, const char *par2, int blkid, int expctr)
1.10 lum 288: {
289: char *regs;
290:
1.21 lum 291: if ((defnam == NULL) && (expctr != 1))
292: return(dobeep_msg("'define' incorrectly used"));
1.12 lum 293:
1.10 lum 294: /* Does the line have a incorrect variable 'define' like: */
295: /* (define i y z) */
1.21 lum 296: regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.+[ ]+.+$";
297: if (doregex(regs, begp))
298: return(dobeep_msg("Invalid use of define"));
1.10 lum 299:
300: /* Does the line have a single variable 'define' like: */
301: /* (define i 0) */
1.19 lum 302: regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.*$";
1.21 lum 303: if (doregex(regs, begp)) {
304: if (par1 == &lp && par2 == &rp && expctr == 1)
305: return(founddef(begp, blkid, expctr, 1));
306: return(dobeep_msg("Invalid use of define."));
307: }
308: /* Does the line have '(define i(' */
309: regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]*$";
310: if (doregex(regs, begp)) {
311: if (par1 == &lp && par2 == &lp && expctr == 1)
312: return(founddef(begp, blkid, expctr, 0));
313: return(dobeep_msg("Invalid use of 'define'"));
314: }
315: /* Does the line have '(define (' */
316: regs = "^define$";
317: if (doregex(regs, begp)) {
318: if (par1 == &lp && par2 == &lp && expctr == 1)
319: return(foundfun(begp, expctr));
320: return(dobeep_msg("Invalid use of 'define'."));
321: }
322:
323: return (ABORT);
324: }
325:
326: static int
327: parsval(char *begp, const char *par1, const char *par2, int blkid, int expctr)
328: {
329: char *regs;
1.10 lum 330:
1.21 lum 331: /* Does the line have 'list' */
332: regs = "^list$";
333: if (doregex(regs, begp))
334: return(dobeep_msg("Invalid use of list"));
335:
336: /* Does the line have a 'list' like: */
337: /* (list "a" "b") */
338: regs = "^list[ ]+.*$";
339: if (doregex(regs, begp)) {
340: if (expctr == 1)
341: return(dobeep_msg("list with no-where to go."));
1.10 lum 342:
1.21 lum 343: if (par1 == &lp && expctr > 1)
344: return(foundlst(begp, blkid, expctr));
1.16 lum 345:
1.21 lum 346: return(dobeep_msg("Invalid use of list."));
347: }
348: return (FALSE);
1.10 lum 349: }
350:
1.1 lum 351: static int
1.21 lum 352: parsexp(char *begp, const char *par1, const char *par2, int blkid, int expctr)
1.1 lum 353: {
1.21 lum 354: struct expentry *e1 = NULL;
355: PF funcp;
356: char *cmdp, *fendp, *valp, *fname, *funb = NULL;;
357: int numparams, ret;
1.1 lum 358:
1.21 lum 359: cmdp = begp;
1.10 lum 360: fendp = strchr(cmdp, ' ');
1.1 lum 361: *fendp = '\0';
1.21 lum 362:
1.1 lum 363: /*
364: * If no extant mg command found, just return.
365: */
366: if ((funcp = name_function(cmdp)) == NULL)
367: return (dobeep_msgs("Unknown command: ", cmdp));
368:
369: numparams = numparams_function(funcp);
370: if (numparams == 0)
1.21 lum 371: return (dobeep_msgs("Command takes no arguments:", cmdp));
1.22 ! lum 372:
! 373: if (numparams == -1)
! 374: return (dobeep_msgs("Interactive command found:", cmdp));
1.21 lum 375:
376: if ((e1 = malloc(sizeof(struct expentry))) == NULL) {
377: cleanup();
378: return (dobeep_msg("malloc Error"));
379: }
380: TAILQ_INSERT_HEAD(&ehead, e1, eentry);
381: if ((e1->fun = strndup(cmdp, BUFSIZE)) == NULL) {
382: cleanup();
383: return(dobeep_msg("strndup error"));
384: }
385: cmdp = e1->fun;
386: fname = e1->fun;
387: e1->funbuf[0] = '\0';
388: funb = e1->funbuf;
389: e1->expctr = expctr;
390: e1->blkid = blkid;
391: /* need to think about these two */
392: e1->par1 = par1;
393: e1->par2 = par2;
394:
395: *fendp = ' ';
396: valp = fendp + 1;
397:
398: ret = expandvals(cmdp, valp, funb);
399: if (!ret)
400: return (ret);
401:
402: return (multiarg(fname, funb, numparams));
403: }
1.1 lum 404:
1.21 lum 405: /*
406: * Pass a list of arguments to a function.
407: */
408: static int
409: multiarg(char *cmdp, char *argbuf, int numparams)
410: {
411: char excbuf[BUFSIZE];
412: char *argp, *p, *s = " ";
413: char *regs;
414: int spc, numspc;
415: int fin, inquote;
1.10 lum 416:
1.1 lum 417: argp = argbuf;
1.21 lum 418: spc = 1; /* initially fake a space so we find first argument */
419: numspc = fin = inquote = 0;
1.10 lum 420:
421: for (p = argbuf; *p != '\0'; p++) {
422: if (*(p + 1) == '\0')
423: fin = 1;
1.1 lum 424:
1.10 lum 425: if (*p != ' ') {
1.11 lum 426: if (*p == '"') {
427: if (inquote == 1)
428: inquote = 0;
429: else
430: inquote = 1;
431: }
1.10 lum 432: if (spc == 1)
1.21 lum 433: if ((numspc % numparams) == 0) {
434: argp = p;
435: }
1.10 lum 436: spc = 0;
1.1 lum 437: }
1.11 lum 438: if ((*p == ' ' && inquote == 0) || fin) {
1.21 lum 439: if (spc == 1)/* || (numspc % numparams == 0))*/
440: continue;
441: if ((numspc % numparams) != (numparams - 1)) {
442: numspc++;
1.1 lum 443: continue;
1.21 lum 444: }
1.10 lum 445: if (*p == ' ') {
1.11 lum 446: *p = '\0'; /* terminate arg string */
1.10 lum 447: }
448: excbuf[0] = '\0';
1.11 lum 449: regs = "[\"]+.*[\"]+";
1.10 lum 450:
1.21 lum 451: if (!doregex(regs, argp)) {
1.13 lum 452: const char *errstr;
453: int iters;
454:
455: iters = strtonum(argp, 0, INT_MAX, &errstr);
456: if (errstr != NULL)
457: return (dobeep_msgs("Var not found:",
458: argp));
459: }
1.11 lum 460:
1.10 lum 461: if (strlcpy(excbuf, cmdp, sizeof(excbuf))
462: >= sizeof(excbuf))
463: return (dobeep_msg("strlcpy error"));
464: if (strlcat(excbuf, s, sizeof(excbuf))
465: >= sizeof(excbuf))
466: return (dobeep_msg("strlcat error"));
467: if (strlcat(excbuf, argp, sizeof(excbuf))
468: >= sizeof(excbuf))
469: return (dobeep_msg("strlcat error"));
470:
1.14 lum 471: excline(excbuf, 0);
1.10 lum 472:
473: if (fin)
474: break;
475:
476: *p = ' '; /* unterminate arg string */
1.21 lum 477: numspc++;
1.1 lum 478: spc = 1;
479: }
480: }
481: return (TRUE);
482: }
483:
484: /*
485: * Is an item a value or a variable?
486: */
487: static int
1.10 lum 488: isvar(char **argp, char **varbuf, int sizof)
1.1 lum 489: {
490: struct varentry *v1 = NULL;
491:
492: if (SLIST_EMPTY(&varhead))
493: return (FALSE);
1.2 lum 494: #ifdef MGLOG
1.10 lum 495: mglog_isvar(*varbuf, *argp, sizof);
1.2 lum 496: #endif
1.1 lum 497: SLIST_FOREACH(v1, &varhead, entry) {
498: if (strcmp(*argp, v1->name) == 0) {
1.21 lum 499: (void)(strlcpy(*varbuf, v1->valbuf, sizof) >= sizof);
1.1 lum 500: return (TRUE);
501: }
502: }
503: return (FALSE);
504: }
505:
1.21 lum 506:
507: static int
508: foundfun(char *defstr, int expctr)
509: {
510: return (TRUE);
511: }
512:
513: static int
514: foundlst(char *defstr, int blkid, int expctr)
515: {
516: char *p;
517:
518: p = strstr(defstr, " ");
519: p = skipwhite(p);
520: expandvals(NULL, p, defnam);
521:
522: return (TRUE);
523: }
524:
1.1 lum 525: /*
1.21 lum 526: * 'define' strings follow the regex in parsdef().
1.1 lum 527: */
528: static int
1.21 lum 529: founddef(char *defstr, int blkid, int expctr, int hasval)
1.1 lum 530: {
531: struct varentry *vt, *v1 = NULL;
1.10 lum 532: char *p, *vnamep, *vendp = NULL, *valp;
1.11 lum 533:
1.10 lum 534: p = strstr(defstr, " "); /* move to first ' ' char. */
1.11 lum 535: vnamep = skipwhite(p); /* find first char of var name. */
1.1 lum 536: vendp = vnamep;
537:
1.21 lum 538: /* now find the end of the define/list name */
1.1 lum 539: while (1) {
540: ++vendp;
1.10 lum 541: if (*vendp == ' ')
1.1 lum 542: break;
543: }
544: *vendp = '\0';
1.10 lum 545:
1.1 lum 546: /*
1.21 lum 547: * Check list name is not an existing mg function.
1.1 lum 548: */
549: if (name_function(vnamep) != NULL)
550: return(dobeep_msgs("Variable/function name clash:", vnamep));
551:
552: if (!SLIST_EMPTY(&varhead)) {
553: SLIST_FOREACH_SAFE(v1, &varhead, entry, vt) {
554: if (strcmp(vnamep, v1->name) == 0)
555: SLIST_REMOVE(&varhead, v1, varentry, entry);
556: }
557: }
558: if ((v1 = malloc(sizeof(struct varentry))) == NULL)
559: return (ABORT);
560: SLIST_INSERT_HEAD(&varhead, v1, entry);
561: if ((v1->name = strndup(vnamep, BUFSIZE)) == NULL)
562: return(dobeep_msg("strndup error"));
1.21 lum 563: vnamep = v1->name;
1.1 lum 564: v1->count = 0;
1.21 lum 565: v1->expctr = expctr;
566: v1->blkid = blkid;
567: v1->vals = NULL;
568: v1->valbuf[0] = '\0';
569:
570: defnam = v1->valbuf;
571:
572: if (hasval) {
573: valp = skipwhite(vendp + 1);
574:
575: expandvals(NULL, valp, defnam);
576: defnam = NULL;
577: }
578: *vendp = ' ';
579: return (TRUE);
580: }
581:
582:
583: static int
584: expandvals(char *cmdp, char *valp, char *bp)
585: {
586: char excbuf[BUFSIZE], argbuf[BUFSIZE];
587: char contbuf[BUFSIZE], varbuf[BUFSIZE];
588: char *argp, *endp, *p, *v, *s = " ";
589: char *regs;
590: int spc, cnt;
591: int inlist, sizof, fin, inquote;
592:
593: /* now find the first argument */
594: p = skipwhite(valp);
595:
596: if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
597: return (dobeep_msg("strlcpy error"));
598: argp = argbuf;
599: spc = 1; /* initially fake a space so we find first argument */
600: inlist = fin = inquote = cnt = spc = 0;
601:
602: for (p = argbuf; *p != '\0'; p++) {
603: if (*(p + 1) == '\0')
604: fin = 1;
605:
606: if (*p != ' ') {
607: if (*p == '"') {
608: if (inquote == 1)
609: inquote = 0;
610: else
611: inquote = 1;
612: }
1.1 lum 613: if (spc == 1)
1.21 lum 614: argp = p;
1.1 lum 615: spc = 0;
616: }
1.21 lum 617: if ((*p == ' ' && inquote == 0) || fin) {
618: if (spc == 1)
619: continue;
620: /* terminate arg string */
621: if (*p == ' ') {
622: *p = '\0';
623: }
624: endp = p + 1;
625: excbuf[0] = '\0';
626: varbuf[0] = '\0';
627: contbuf[0] = '\0';
628: sizof = sizeof(varbuf);
629: v = varbuf;
630: regs = "[\"]+.*[\"]+";
631: if (doregex(regs, argp))
632: ; /* found quotes */
633: else if (isvar(&argp, &v, sizof)) {
634:
635: (void)(strlcat(varbuf, " ",
636: sizof) >= sizof);
637:
638: *p = ' ';
639: (void)(strlcpy(contbuf, endp,
640: sizeof(contbuf)) >= sizeof(contbuf));
641:
642: (void)(strlcat(varbuf, contbuf,
643: sizof) >= sizof);
644:
645: argbuf[0] = ' ';
646: argbuf[1] = '\0';
647: (void)(strlcat(argbuf, varbuf,
648: sizof) >= sizof);
649:
650: p = argp = argbuf;
651: spc = 1;
652: fin = 0;
653: continue;
654: } else {
655: const char *errstr;
656: int iters;
1.1 lum 657:
1.21 lum 658: iters = strtonum(argp, 0, INT_MAX, &errstr);
659: if (errstr != NULL)
660: return (dobeep_msgs("Var not found:",
661: argp));
662: }
1.7 lum 663: #ifdef MGLOG
1.21 lum 664: mglog_misc("x|%s|%p|%d|\n", bp, defnam, BUFSIZE);
1.7 lum 665: #endif
1.21 lum 666: if (*bp != '\0') {
667: if (strlcat(bp, s, BUFSIZE) >= BUFSIZE)
668: return (dobeep_msg("strlcat error"));
669: }
670: if (strlcat(bp, argp, BUFSIZE) >= BUFSIZE) {
671: return (dobeep_msg("strlcat error"));
672: }
673: /* v1->count++;*/
674:
675: if (fin)
676: break;
1.1 lum 677:
1.21 lum 678: *p = ' '; /* unterminate arg string */
679: spc = 1;
680: }
681: }
1.1 lum 682: return (TRUE);
683: }
684:
685: /*
1.10 lum 686: * Finished with buffer evaluation, so clean up any vars.
687: * Perhaps keeps them in mg even after use,...
1.1 lum 688: */
1.11 lum 689: static int
1.1 lum 690: clearvars(void)
691: {
692: struct varentry *v1 = NULL;
693:
694: while (!SLIST_EMPTY(&varhead)) {
695: v1 = SLIST_FIRST(&varhead);
696: SLIST_REMOVE_HEAD(&varhead, entry);
1.21 lum 697: /* free(v1->vals);*/
1.1 lum 698: free(v1->name);
699: free(v1);
700: }
701: return (FALSE);
702: }
703:
704: /*
1.10 lum 705: * Finished with block evaluation, so clean up any expressions.
1.1 lum 706: */
1.10 lum 707: static void
708: clearexp(void)
1.1 lum 709: {
1.10 lum 710: struct expentry *e1 = NULL;
1.9 lum 711:
1.12 lum 712: while (!TAILQ_EMPTY(&ehead)) {
713: e1 = TAILQ_FIRST(&ehead);
714: TAILQ_REMOVE(&ehead, e1, eentry);
1.21 lum 715: free(e1->fun);
1.10 lum 716: free(e1);
1.9 lum 717: }
1.10 lum 718: return;
1.11 lum 719: }
720:
721: /*
722: * Cleanup before leaving.
723: */
724: void
725: cleanup(void)
726: {
1.21 lum 727: defnam = NULL;
728:
1.11 lum 729: clearexp();
730: clearvars();
1.8 lum 731: }
732:
733: /*
734: * Test a string against a regular expression.
735: */
1.10 lum 736: static int
1.8 lum 737: doregex(char *r, char *e)
738: {
739: regex_t regex_buff;
740:
741: if (regcomp(®ex_buff, r, REG_EXTENDED)) {
1.1 lum 742: regfree(®ex_buff);
1.8 lum 743: return(dobeep_msg("Regex compilation error"));
1.1 lum 744: }
1.8 lum 745: if (!regexec(®ex_buff, e, 0, NULL, 0)) {
746: regfree(®ex_buff);
747: return(TRUE);
1.1 lum 748: }
1.9 lum 749: regfree(®ex_buff);
1.16 lum 750: return(FALSE);
751: }
752:
753: /*
754: * Display a message so it is apparent that this is the method which stopped
755: * execution.
756: */
757: static int
1.21 lum 758: exitinterpreter(char *ptr, char *dobuf, int dosiz)
1.16 lum 759: {
760: cleanup();
761: if (batch == 0)
762: return(dobeep_msg("Interpreter exited via exit command."));
1.9 lum 763: return(FALSE);
1.1 lum 764: }
1.21 lum 765:
766: /*
767: * All code below commented out (until end of file).
768: *
769: * Need to think about how interpreter functions are done.
770: * Probably don't have a choice with string-append().
771:
772: static int getenvironmentvariable(char *, char *, int);
773: static int stringappend(char *, char *, int);
774:
775: typedef int (*PFI)(char *, char *, int);
776:
777:
778: struct ifunmap {
779: PFI fn_funct;
780: const char *fn_name;
781: struct ifunmap *fn_next;
782: };
783: static struct ifunmap *ifuns;
784:
785: static struct ifunmap ifunctnames[] = {
786: {exitinterpreter, "exit"},
787: {getenvironmentvariable, "get-environment-variable"},
788: {stringappend, "string-append"},
789: {NULL, NULL}
790: };
791:
792: void
793: ifunmap_init(void)
794: {
795: struct ifunmap *fn;
796:
797: for (fn = ifunctnames; fn->fn_name != NULL; fn++) {
798: fn->fn_next = ifuns;
799: ifuns = fn;
800: }
801: }
802:
803: PFI
804: name_ifun(const char *ifname)
805: {
806: struct ifunmap *fn;
807:
808: for (fn = ifuns; fn != NULL; fn = fn->fn_next) {
809: if (strcmp(fn->fn_name, ifname) == 0)
810: return (fn->fn_funct);
811: }
812:
813: return (NULL);
814: }
815:
816:
817: int
818: dofunc(char **ifname, char **tmpbuf, int sizof)
819: {
820: PFI fnc;
821: char *p, *tmp;
822:
823: p = strstr(*ifname, " ");
824: *p = '\0';
825:
826: fnc = name_ifun(*ifname);
827: if (fnc == NULL)
828: return (FALSE);
829:
830: *p = ' ';
831:
832: tmp = *tmpbuf;
833:
834: fnc(p, tmp, sizof);
835:
836: return (TRUE);
837: }
838:
839: static int
840: getenvironmentvariable(char *ptr, char *dobuf, int dosiz)
841: {
842: char *t;
843: char *tmp;
844: const char *q = "\"";
845:
846: t = skipwhite(ptr);
847:
848: if (t[0] == *q || t[strlen(t) - 1] == *q)
849: return (dobeep_msgs("Please remove '\"' around:", t));
850: if ((tmp = getenv(t)) == NULL || *tmp == '\0')
851: return(dobeep_msgs("Envar not found:", t));
852:
853: dobuf[0] = '\0';
854: if (strlcat(dobuf, q, dosiz) >= dosiz)
855: return (dobeep_msg("strlcat error"));
856: if (strlcat(dobuf, tmp, dosiz) >= dosiz)
857: return (dobeep_msg("strlcat error"));
858: if (strlcat(dobuf, q, dosiz) >= dosiz)
859: return (dobeep_msg("strlcat error"));
860:
861: return (TRUE);
862: }
863:
864: static int
865: stringappend(char *ptr, char *dobuf, int dosiz)
866: {
867: char varbuf[BUFSIZE], funbuf[BUFSIZE];
868: char *p, *f, *v, *vendp;
869: int sizof, fin = 0;
870:
871: varbuf[0] = funbuf[0] = '\0';
872: f = funbuf;
873: v = varbuf;
874: sizof = sizeof(varbuf);
875: *dobuf = '\0';
876:
877: p = skipwhite(ptr);
878:
879: while (*p != '\0') {
880: vendp = p;
881: while (1) {
882: if (*vendp == ' ') {
883: break;
884: } else if (*vendp == '\0') {
885: fin = 1;
886: break;
887: }
888: ++vendp;
889: }
890: *vendp = '\0';
891:
892: if (isvar(&p, &v, sizof)) {
893: if (v[0] == '"' && v[strlen(v) - 1] == '"' ) {
894: v[strlen(v) - 1] = '\0';
895: v = v + 1;
896: }
897: if (strlcat(f, v, sizof) >= sizof)
898: return (dobeep_msg("strlcat error"));
899: } else {
900: if (p[0] == '"' && p[strlen(p) - 1] == '"' ) {
901: p[strlen(p) - 1] = '\0';
902: p = p + 1;
903: }
904: if (strlcat(f, p, sizof) >= sizof)
905: return (dobeep_msg("strlcat error"));
906: }
907: if (fin)
908: break;
909: vendp++;
910: if (*vendp == '\0')
911: break;
912: p = skipwhite(vendp);
913: }
914:
915: (void)snprintf(dobuf, dosiz, "\"%s\"", f);
916:
917: return (TRUE);
918: }
919:
920: Index: main.c
921: ===================================================================
922: RCS file: /cvs/src/usr.bin/mg/main.c,v
923: retrieving revision 1.89
924: diff -u -p -u -p -r1.89 main.c
925: --- main.c 20 Mar 2021 09:00:49 -0000 1.89
926: +++ main.c 12 Apr 2021 17:58:52 -0000
927: @@ -133,10 +133,12 @@ main(int argc, char **argv)
928: extern void grep_init(void);
929: extern void cmode_init(void);
930: extern void dired_init(void);
931: + extern void ifunmap_init(void);
932:
933: dired_init();
934: grep_init();
935: cmode_init();
936: + ifunmap_init();
937: }
938:
939:
940: */