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