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