From fcfff489169c028ac61c8e62a03666fd8056e964 Mon Sep 17 00:00:00 2001 From: Mark Lumsden Date: Sun, 21 Mar 2021 12:56:17 +0000 Subject: Add quoted strings capability in list values, no special chars detection in between them though. Add limitation to characters allowed in symbol names, equivalent to mg function names (A-Za-z-), quite restrictive but can grow of course. If value is not quoted and is not a variable, give an error. --- usr.bin/mg/def.h | 4 +- usr.bin/mg/extend.c | 6 +-- usr.bin/mg/interpreter.c | 131 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 95 insertions(+), 46 deletions(-) (limited to 'usr.bin/mg') diff --git a/usr.bin/mg/def.h b/usr.bin/mg/def.h index 7b7d90088ec..0c436ef5bc2 100644 --- a/usr.bin/mg/def.h +++ b/usr.bin/mg/def.h @@ -1,4 +1,4 @@ -/* $OpenBSD: def.h,v 1.169 2021/03/20 09:00:49 lum Exp $ */ +/* $OpenBSD: def.h,v 1.170 2021/03/21 12:56:16 lum Exp $ */ /* This file is in the public domain. */ @@ -721,7 +721,7 @@ void dobeep(void); /* interpreter.c */ int foundparen(char *); -int clearvars(void); +void cleanup(void); /* * Externals. diff --git a/usr.bin/mg/extend.c b/usr.bin/mg/extend.c index 4cb08fea1c0..31c7f378074 100644 --- a/usr.bin/mg/extend.c +++ b/usr.bin/mg/extend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: extend.c,v 1.72 2021/03/01 10:51:14 lum Exp $ */ +/* $OpenBSD: extend.c,v 1.73 2021/03/21 12:56:16 lum Exp $ */ /* This file is in the public domain. */ /* @@ -606,11 +606,11 @@ evalbuffer(int f, int n) /* make sure it's terminated */ excbuf[llength(lp)] = '\0'; if ((s = excline(excbuf)) != TRUE) { - (void) clearvars(); + cleanup(); return (s); } } - (void) clearvars(); + cleanup(); return (TRUE); } diff --git a/usr.bin/mg/interpreter.c b/usr.bin/mg/interpreter.c index 3fb64508bea..4a156e0d9a7 100644 --- a/usr.bin/mg/interpreter.c +++ b/usr.bin/mg/interpreter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: interpreter.c,v 1.10 2021/03/20 19:39:30 lum Exp $ */ +/* $OpenBSD: interpreter.c,v 1.11 2021/03/21 12:56:16 lum Exp $ */ /* * This file is in the public domain. * @@ -20,13 +20,13 @@ * like: * * 1. Give multiple arguments to a function that usually would accept only one: - * (find-file a.txt b.txt. c.txt) + * (find-file "a.txt" "b.txt" "c.txt") * * 2. Define a single value variable: - * (define myfile d.txt) + * (define myfile "d.txt") * * 3. Define a list: - * (define myfiles(list e.txt f.txt)) + * (define myfiles(list "e.txt" "f.txt")) * * 4. Use the previously defined variable or list: * (find-file myfiles) @@ -35,10 +35,12 @@ * 1. multiline parsing - currently only single lines supported. * 2. parsing for '(' and ')' throughout whole string and evaluate correctly. * 3. conditional execution. - * 4. deal with quotes around a string: "x x" - * 5. oh so many things.... + * 4. deal with special characters in a string: "x\" x" etc + * 5. do symbol names need more complex regex patterns? A-Za-z- at the moment. + * 6. oh so many things.... * [...] * n. implement user definable functions. + * */ #include #include @@ -95,8 +97,9 @@ foundparen(char *funstr) char *p, *valp, *endp = NULL, *regs; char expbuf[BUFSIZE], tmpbuf[BUFSIZE]; int ret, pctr, fndstart, expctr, blkid, fndchr, fndend; + int inquote; - pctr = fndstart = expctr = fndchr = fndend = 0; + pctr = fndstart = expctr = fndchr = fndend = inquote = 0; blkid = 1; /* * Check for blocks of code with opening and closing (). @@ -116,7 +119,8 @@ foundparen(char *funstr) return(dobeep_msg("Empty lists not supported at moment")); regs = "[(]+[\t ]*[(]+"; if (doregex(regs, funstr)) - return(dobeep_msg("Multiple left parantheses found")); + return(dobeep_msg("Multiple consecutive left parantheses "\ + "found.")); /* * load expressions into a list called 'expentry', to be processd * when all are obtained. @@ -131,11 +135,16 @@ foundparen(char *funstr) else *endp = '\0'; e1->par2 = 1; - if ((e1->exp = strndup(valp, BUFSIZE)) == NULL) + if ((e1->exp = strndup(valp, BUFSIZE)) == + NULL) { + cleanup(); return(dobeep_msg("strndup error")); + } } - if ((e1 = malloc(sizeof(struct expentry))) == NULL) + if ((e1 = malloc(sizeof(struct expentry))) == NULL) { + cleanup(); return (dobeep_msg("malloc Error")); + } SLIST_INSERT_HEAD(&exphead, e1, eentry); e1->exp = NULL; e1->expctr = ++expctr; @@ -147,12 +156,19 @@ foundparen(char *funstr) endp = NULL; pctr++; } else if (*p == ')') { + if (inquote == 1) { + cleanup(); + return(dobeep_msg("Opening and closing quote "\ + "char error")); + } if (endp == NULL) *p = '\0'; else *endp = '\0'; - if ((e1->exp = strndup(valp, BUFSIZE)) == NULL) + if ((e1->exp = strndup(valp, BUFSIZE)) == NULL) { + cleanup(); return(dobeep_msg("strndup error")); + } fndstart = 0; pctr--; } else if (*p != ' ' && *p != '\t') { @@ -160,6 +176,12 @@ foundparen(char *funstr) valp = p; fndchr = 1; } + if (*p == '"') { + if (inquote == 0) + inquote = 1; + else + inquote = 0; + } fndend = 0; endp = NULL; } else if (fndend == 0 && (*p == ' ' || *p == '\t')) { @@ -167,18 +189,23 @@ foundparen(char *funstr) fndend = 1; endp = p; } else if (*p == '\t') /* need to check not between "" */ - *p = ' '; + if (inquote == 0) + *p = ' '; if (pctr == 0) blkid++; p++; } - expbuf[0] = tmpbuf[0] = '\0'; + if (pctr != 0) { + cleanup(); + return(dobeep_msg("Opening and closing parentheses error")); + } /* * Join expressions together for the moment, to progess. * This needs to be totally redone and * iterate in-to-out, evaluating as we go. Eventually. */ + expbuf[0] = tmpbuf[0] = '\0'; SLIST_FOREACH(e1, &exphead, eentry) { if (strlcpy(tmpbuf, expbuf, sizeof(tmpbuf)) >= sizeof(tmpbuf)) return (dobeep_msg("strlcpy error")); @@ -195,19 +222,20 @@ foundparen(char *funstr) mglog_misc("exp|%s|\n", e1->exp); #endif } - if (pctr != 0) { - clearexp(); - return(dobeep_msg("Opening and closing parentheses error")); - } ret = parseexp(expbuf); - clearexp(); + if (ret == FALSE) + cleanup(); + else + clearexp(); /* leave lists but remove expressions */ return (ret); } /* - * At the moment, only paring list defines. Much more to do. + * At the moment, only parsing list defines. Much more to do. + * Also only use basic chars for symbol names like ones found in + * mg functions. */ static int parseexp(char *funstr) @@ -216,19 +244,19 @@ parseexp(char *funstr) /* Does the line have a list 'define' like: */ /* (define alist(list 1 2 3 4)) */ - regs = "^define[ ]+.*[ ]+list[ ]+.*[ ]*"; + regs = "^define[ ]+[A-Za-z-]+[ ]+list[ ]+.*[ ]*"; if (doregex(regs, funstr)) return(foundvar(funstr)); /* Does the line have a incorrect variable 'define' like: */ /* (define i y z) */ - regs = "^define[ ]+.*[ ]+.*[ ]+.*$"; + regs = "^define[ ]+[A-Za-z-]+[ ]+.*[ ]+.*$"; if (doregex(regs, funstr)) return(dobeep_msg("Invalid use of define.")); /* Does the line have a single variable 'define' like: */ /* (define i 0) */ - regs = "^define[ ]+.*[ ]+.*$"; + regs = "^define[ ]+[A-Za-z-]+[ ]+.*$"; if (doregex(regs, funstr)) return(foundvar(funstr)); @@ -250,9 +278,11 @@ multiarg(char *funstr) char excbuf[BUFSIZE], argbuf[BUFSIZE]; char contbuf[BUFSIZE], varbuf[BUFSIZE]; char *cmdp = NULL, *argp, *fendp = NULL, *endp, *p, *v, *s = " "; + char *regs; int spc, numparams, numspc; - int inlist, sizof, fin; - + int inlist, sizof, fin, inquote; + + /* mg function name regex */ if (doregex("^[A-Za-z-]+$", funstr)) return(excline(funstr)); @@ -277,23 +307,29 @@ multiarg(char *funstr) return (dobeep_msg("strlcpy error")); argp = argbuf; numspc = spc = 1; /* initially fake a space so we find first argument */ - inlist = fin = 0; + inlist = fin = inquote = 0; for (p = argbuf; *p != '\0'; p++) { if (*(p + 1) == '\0') fin = 1; if (*p != ' ') { + if (*p == '"') { + if (inquote == 1) + inquote = 0; + else + inquote = 1; + } if (spc == 1) argp = p; spc = 0; } - if (*p == ' ' || fin) { + if ((*p == ' ' && inquote == 0) || fin) { if (spc == 1) continue; if (*p == ' ') { - *p = '\0'; /* terminate arg string */ + *p = '\0'; /* terminate arg string */ } endp = p + 1; excbuf[0] = '\0'; @@ -301,7 +337,10 @@ multiarg(char *funstr) contbuf[0] = '\0'; sizof = sizeof(varbuf); v = varbuf; - if (isvar(&argp, &v, sizof)) { + regs = "[\"]+.*[\"]+"; + if (doregex(regs, argp)) + ; /* found quotes */ + else if (isvar(&argp, &v, sizof)) { (void)(strlcat(varbuf, " ", sizof) >= sizof); @@ -312,20 +351,19 @@ multiarg(char *funstr) (void)(strlcat(varbuf, contbuf, sizof) >= sizof); - - (void)(strlcpy(argbuf, varbuf, + + argbuf[0] = ' '; + argbuf[1] = '\0'; + (void)(strlcat(argbuf, varbuf, sizof) >= sizof); p = argp = argbuf; - while (*p != ' ') { - if (*p == '\0') - break; - p++; - } - *p = '\0'; spc = 1; fin = 0; - } + continue; + } else + return (dobeep_msgs("Var not found:", argp)); + if (strlcpy(excbuf, cmdp, sizeof(excbuf)) >= sizeof(excbuf)) return (dobeep_msg("strlcpy error")); @@ -348,7 +386,6 @@ multiarg(char *funstr) return (TRUE); } - /* * Is an item a value or a variable? */ @@ -371,7 +408,6 @@ isvar(char **argp, char **varbuf, int sizof) return (FALSE); } - /* * The define string _must_ adhere to the regex in parsexp(). * This is not the correct way to do parsing but it does highlight @@ -385,8 +421,11 @@ foundvar(char *defstr) char *p, *vnamep, *vendp = NULL, *valp; int spc; + /* vars names can't start with these. */ + /* char *spchrs = "+-.#"; */ + p = strstr(defstr, " "); /* move to first ' ' char. */ - vnamep = skipwhite(p); /* find first char of var name. */ + vnamep = skipwhite(p); /* find first char of var name. */ vendp = vnamep; /* now find the end of the list name */ @@ -455,7 +494,7 @@ foundvar(char *defstr) * Finished with buffer evaluation, so clean up any vars. * Perhaps keeps them in mg even after use,... */ -int +static int clearvars(void) { struct varentry *v1 = NULL; @@ -487,6 +526,16 @@ clearexp(void) return; } +/* + * Cleanup before leaving. + */ +void +cleanup(void) +{ + clearexp(); + clearvars(); +} + /* * Test a string against a regular expression. */ -- cgit v1.2.3