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