[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.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(&regex_buff, r, REG_EXTENDED)) {
1.1       lum       779:                regfree(&regex_buff);
1.27      lum       780:                return(dobeep_num("Regex compilation error line:", lnm));
1.1       lum       781:        }
1.8       lum       782:        if (!regexec(&regex_buff, e, 0, NULL, 0)) {
                    783:                regfree(&regex_buff);
                    784:                return(TRUE);
1.1       lum       785:        }
1.9       lum       786:        regfree(&regex_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: */