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