[BACK]Return to interpreter.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

Annotation of src/usr.bin/mg/interpreter.c, Revision 1.24

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