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