This diff introduces lists to the startup file of mg. With this diff applied you could have something similar to:

(define y(list b.txt c.txt))
(define z(list d.txt e.txt))
(find-file a.txt y f.txt z)

in your .mg file, and when you opened mg, there would be 7 buffers opened (a.txt, b.txt, c.txt, d.txt, e.txt, and f.txt, including the *scratch* buffer)

When I got about 3/4 of the way through this diff I realised I was probably not doing it the best way. I should have a list of 'key' words and multi-line parsing and lists within lists etc... I think I need to go back and take those ideas and apply them bit by bit to this diff. However, as a way forward does anyone object to this diff going in? My plan is to hopefully have some kind of user definable functions in mg, but functions (usually) need conditionals and variables, so I am trying to add in the basics beforehand. I'm using this for regress tests within mg, but arguably there could be other uses, depending on how much was developed.

Like with the previous multi arg diff, if your .mg file has no '(' characters on the first line, you won't (or shouldn't) see any functional difference in mg. Any comments/objections?

Mark

Index: bell.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/bell.c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 bell.c
--- bell.c      3 Jan 2016 19:37:08 -0000       1.4
+++ bell.c      15 Jul 2019 20:12:00 -0000
@@ -26,6 +26,23 @@ bellinit(void)
        dovisiblebell = 0;
 }

+
+int
+dobeep_msgs(const char *msg, const char *s)
+{
+       ewprintf("%s %s", msg, s);
+       dobeep();
+       return (FALSE);
+}
+
+int
+dobeep_msg(const char *msg)
+{
+       ewprintf("%s", msg);
+       dobeep();
+       return (FALSE);
+}
+
 void
 dobeep(void)
 {
Index: def.h
===================================================================
RCS file: /cvs/src/usr.bin/mg/def.h,v
retrieving revision 1.162
diff -u -p -u -p -r1.162 def.h
--- def.h       3 Jul 2019 18:11:07 -0000       1.162
+++ def.h       15 Jul 2019 20:12:00 -0000
@@ -711,6 +711,8 @@ int          compile(int, int);
 void            bellinit(void);
 int             toggleaudiblebell(int, int);
 int             togglevisiblebell(int, int);
+int             dobeep_msgs(const char *, const char *);
+int             dobeep_msg(const char *);
 void            dobeep(void);

 /*
Index: extend.c
===================================================================
RCS file: /cvs/src/usr.bin/mg/extend.c,v
retrieving revision 1.67
diff -u -p -u -p -r1.67 extend.c
--- extend.c    11 Jul 2019 18:20:18 -0000      1.67
+++ extend.c    15 Jul 2019 20:12:00 -0000
@@ -29,6 +29,17 @@ static int    dobind(KEYMAP *, const char
 static char    *skipwhite(char *);
 static char    *parsetoken(char *);
 static int      bindkey(KEYMAP **, const char *, KCHAR *, int);
+static int      clearvars(void);
+
+struct varentry {
+       SLIST_ENTRY(varentry) entry;
+       char    *name;
+       char    *vals;
+       int      count;
+};
+SLIST_HEAD(slisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);
+
+#define                BUFSIZE 128     /* Size of line contents - could be 
larger? */

 /*
  * Insert a string, mainly for use from macros (created by selfinsert).
@@ -37,7 +48,7 @@ static int     bindkey(KEYMAP **, const cha
 int
 insert(int f, int n)
 {
-       char     buf[128], *bufp, *cp;
+       char     buf[BUFSIZE], *bufp, *cp;
        int      count, c;

        if (inmacro) {
@@ -595,7 +606,7 @@ extend(int f, int n)
 int
 evalexpr(int f, int n)
 {
-       char     exbuf[128], *bufp;
+       char     exbuf[BUFSIZE], *bufp;

        if ((bufp = eread("Eval: ", exbuf, sizeof(exbuf),
            EFNEW | EFCR)) == NULL)
@@ -616,18 +627,21 @@ evalbuffer(int f, int n)
        struct line             *lp;
        struct buffer           *bp = curbp;
        int              s;
-       static char      excbuf[128];
+       static char      excbuf[BUFSIZE];

        for (lp = bfirstlp(bp); lp != bp->b_headp; lp = lforw(lp)) {
-               if (llength(lp) >= 128)
+               if (llength(lp) >= BUFSIZE)
                        return (FALSE);
                (void)strncpy(excbuf, ltext(lp), llength(lp));

                /* make sure it's terminated */
                excbuf[llength(lp)] = '\0';
-               if ((s = excline(excbuf)) != TRUE)
+               if ((s = excline(excbuf)) != TRUE) {
+                       (void) clearvars();
                        return (s);
+               }
        }
+       (void) clearvars();
        return (TRUE);
 }

@@ -657,7 +671,7 @@ load(const char *fname)
 {
        int      s = TRUE, line, ret;
        int      nbytes = 0;
-       char     excbuf[128], fncpy[NFILEN];
+       char     excbuf[BUFSIZE], fncpy[NFILEN];
        FILE    *ffp;

        if ((fname = adjustname(fname, TRUE)) == NULL)
@@ -693,17 +707,39 @@ load(const char *fname)
 }

 /*
- * Line has a '(' as the first non-white char.
+ * Is an item a value or a variable?
+ */
+static int
+isvar(char **argp, char **tmpbuf, int sizof)
+{
+       struct varentry *v1 = NULL;
+
+       if (SLIST_EMPTY(&varhead))
+               return (FALSE);
+
+       SLIST_FOREACH(v1, &varhead, entry) {
+               if (strcmp(*argp, v1->name) == 0) {
+                       (void)(strlcpy(*tmpbuf, v1->vals, sizof) >= sizof);
+                       return (TRUE);
+               }
+       }
+       return (FALSE);
+}
+
+/*
+ * Pass a list of arguments to a function.
  */
 static int
 multiarg(char *funstr)
 {
        regex_t  regex_buff;
        PF       funcp;
-       char     excbuf[128];
-       char    *cmdp, *argp, *fendp, *endp, *p, *s = " ";
+       char     excbuf[BUFSIZE], argbuf[BUFSIZE], *contbuf, tmpbuf[BUFSIZE];
+       char    *cmdp, *argp, *fendp, *endp, *p, *t, *s = " ";
        int      singlecmd = 0, spc, numparams, numspc;
+       int      inlist, foundlst = 0, last, sizof;

+       contbuf = NULL;
        endp = strrchr(funstr, ')');
        if (endp == NULL) {
                ewprintf("No closing parenthesis found");
@@ -714,24 +750,18 @@ multiarg(char *funstr)
                *p = '\0';
        /* we now know that string starts with '(' and ends with ')' */
        if (regcomp(&regex_buff, "^[(][\t ]*[)]$", REG_EXTENDED)) {
-               dobeep();
-               ewprintf("Could not compile regex");
                regfree(&regex_buff);
-               return(FALSE);
+               return (dobeep_msg("Could not compile regex"));
        }
        if (!regexec(&regex_buff, funstr, 0, NULL, 0)) {
-               dobeep();
-               ewprintf("No command found");
                regfree(&regex_buff);
-               return(FALSE);
+               return (dobeep_msg("No command found"));
        }
        /* currently there are no mg commands that don't have a letter */
        if (regcomp(&regex_buff, "^[(][\t ]*[A-Za-z-]+[\t ]*[)]$",
            REG_EXTENDED)) {
-               dobeep();
-               ewprintf("Could not compile regex");
                regfree(&regex_buff);
-               return(FALSE);
+               return (dobeep_msg("Could not compile regex"));
        }
        if (!regexec(&regex_buff, funstr, 0, NULL, 0))
                singlecmd = 1;
@@ -754,53 +784,82 @@ multiarg(char *funstr)

        *fendp = '\0';
        /*
-        * If no extant mg command found, line could be a (define of some kind.
-        * Since no defines exist at the moment, just return.
+        * If no extant mg command found, just return.
         */
-       if ((funcp = name_function(cmdp)) == NULL) {
-               dobeep();
-               ewprintf("Unknown command: %s", cmdp);
-               return (FALSE);
-       }
+       if ((funcp = name_function(cmdp)) == NULL)
+               return (dobeep_msgs("Unknown command: ", cmdp));
+
        numparams = numparams_function(funcp);
-       if (numparams == 0) {
-               dobeep();
-               ewprintf("Command takes no arguments: %s", cmdp);
-               return (FALSE);
-       }
+       if (numparams == 0)
+               return (dobeep_msgs("Command takes no arguments: ", cmdp));

        /* now find the first argument */
- p = fendp + 1; - argp = skipwhite(p);
+       p = fendp + 1;
+       p = skipwhite(p);
+       if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
+               return (dobeep_msg("strlcpy error"));
+       argp = argbuf;
        numspc = spc = 1; /* initially fake a space so we find first argument */
+       inlist = last = 0;

        for (p = argp; *p != '\0'; p++) {
+               if (foundlst) {
+                       foundlst = 0;
+                       p--;    /* otherwise 1st arg is missed from list. */
+               }
                if (*p == ' ' || *p == '\t' || *p == ')') {
                        if (spc == 1)
                                continue;
                        if (spc == 0 && (numspc % numparams == 0)) {
+                               if (*p == ')')
+                                       last = 1;
+                               else
+                                       last = 0;
                                *p = '\0';      /* terminate arg string */
+                               endp = p + 1;
                                excbuf[0] = '\0';
+                               /* Is arg a var? */
+                               if (!inlist) {
+                                       if ((contbuf = strndup(endp, BUFSIZE))
+                                           == NULL)
+                                               return(FALSE);
+                                       sizof = sizeof(tmpbuf);
+                                       t = tmpbuf;
+                                       if (isvar(&argp, &t, sizof)) {
+                                               *p = ' ';
+                                               (void)(strlcpy(argbuf, tmpbuf,
+                                                   sizof) >= sizof);
+                                               p = argp = argbuf;
+                                               spc = 1;
+                                               foundlst = inlist = 1;
+                                               continue;
+                                       }
+                               }
                                if (strlcpy(excbuf, cmdp, sizeof(excbuf))
-                                    >= sizeof(excbuf)) {
-                                       dobeep();
-                                       ewprintf("strlcpy error");
-                                       return (FALSE);
-                               }
+                                    >= sizeof(excbuf))
+                                       return (dobeep_msg("strlcpy error"));
                                if (strlcat(excbuf, s, sizeof(excbuf))
-                                   >= sizeof(excbuf)) {
-                                       dobeep();
-                                       ewprintf("strlcpy error");
-                                       return (FALSE);
-                               }
+                                   >= sizeof(excbuf))
+                                       return (dobeep_msg("strlcat error"));
                                if (strlcat(excbuf, argp, sizeof(excbuf))
-                                   >= sizeof(excbuf)) {
-                                       dobeep();
-                                       ewprintf("strlcpy error");
-                                       return (FALSE);
-                               }
+                                   >= sizeof(excbuf))
+                                       return (dobeep_msg("strlcat error"));
+
                                excline(excbuf);
-                               *p = ' ';       /* so 'for' loop can continue */
+                               *p = ' ';       /* so 'for' loop can continue */
+                               if (last) {
+                                       if (contbuf != NULL) {
+                                               (void)strlcpy(argbuf, contbuf,
+                                                   sizeof(argbuf));
+                                               contbuf = NULL;
+                                               p = argp = argbuf;
+                                               foundlst = 1;
+                                               inlist = 0;
+                                               continue;
+                                       }
+                                       spc = 1;
+                                       inlist = 0;
+                               }
                        }
                        numspc++;
                        spc = 1;
@@ -815,6 +874,165 @@ multiarg(char *funstr)
        return (TRUE);
 }

+
+/*
+ * The (define string _must_ adhere to the regex in foundparen.
+ * This is not the correct way to do parsing but it does highlight
+ * the issues.
+ */
+static int
+foundlist(char *defstr)
+{
+       struct varentry *vt, *v1 = NULL;
+       const char       e[1] = "e", t[1] = "t";
+       char            *p, *vnamep, *vendp = NULL, *valp;
+       int              spc;
+
+
+       p = defstr + 1;         /* move past first '(' char.    */
+       p = skipwhite(p);       /* find first char of 'define'. */
+       p = strstr(p, e);       /* find first 'e' in 'define'.  */
+       p = strstr(++p, e);     /* find second 'e' in 'define'. */
+       p++;                    /* move past second 'e'.        */
+       vnamep = skipwhite(p);  /* find first char of var name. */
+       vendp = vnamep;
+
+       /* now find the end of the list name */
+       while (1) {
+               ++vendp;
+               if (*vendp == '(' || *vendp == ' ' || *vendp == '\t')
+                       break;
+       }
+       *vendp = '\0';
+       /*
+        * Check list name is not an existing function.
+        * Although could this be allowed? Shouldn't context dictate?
+        */
+       if (name_function(vnamep) != NULL)
+               return(dobeep_msgs("Variable/function name clash:", vnamep));
+
+       p = ++vendp;
+       p = strstr(p, t);       /* find 't' in 'list'.  */
+       valp = skipwhite(++p);  /* find first value     */
+       /*
+        * Now we have the name of the list starting at 'vnamep',
+        * and the first value is at 'valp', record the details
+        * in a linked list. But first remove variable, if existing already.
+        */
+       if (!SLIST_EMPTY(&varhead)) {
+               SLIST_FOREACH_SAFE(v1, &varhead, entry, vt) {
+                       if (strcmp(vnamep, v1->name) == 0)
+                               SLIST_REMOVE(&varhead, v1, varentry, entry);
+               }
+       }
+       if ((v1 = malloc(sizeof(struct varentry))) == NULL)
+               return (ABORT);
+       SLIST_INSERT_HEAD(&varhead, v1, entry);
+       if ((v1->name = strndup(vnamep, BUFSIZE)) == NULL)
+               return(dobeep_msg("strndup error"));
+       v1->count = 0;
+       vendp = NULL;
+
+       /* initially fake a space so we find first value */
+       spc = 1;
+       /* now loop through values in list value string while counting them */
+       for (p = valp; *p != '\0'; p++) {
+               if (*p == ' ' || *p == '\t') {
+                       if (spc == 0)
+                               vendp = p;
+                       spc = 1;
+               } else if (*p == ')') {
+                       vendp = ++p; /* currently need ')' */
+                       break;
+               } else {
+                       if (spc == 1)
+                               v1->count++;
+                       spc = 0;
+               }
+       }
+       *vendp = '\0';
+       if ((v1->vals = strndup(valp, BUFSIZE)) == NULL)
+               return(dobeep_msg("strndup error"));
+
+       return (TRUE);
+}
+
+/*
+ * to do
+ */
+static int
+foundvar(char *funstr)
+{
+       ewprintf("to do");
+       return (TRUE);
+}
+
+/*
+ * Finished with evaluation, so clean up any vars.
+ */
+static int
+clearvars(void)
+{
+       struct varentry *v1 = NULL;
+
+       while (!SLIST_EMPTY(&varhead)) {
+               v1 = SLIST_FIRST(&varhead);
+               SLIST_REMOVE_HEAD(&varhead, entry);
+               free(v1->vals);
+               free(v1->name);
+               free(v1);
+       }
+       return (FALSE);
+}
+
+/*
+ * Line has a '(' as the first non-white char.
+ * Do some very basic parsing of line with '(' as the first character.
+ * Multi-line not supported at the moment, To do.
+ */
+static int
+foundparen(char *funstr)
+{
+       regex_t  regex_buff;
+       char    *regs;
+
+       /* Does the line have a list 'define' like: */
+       /* (define alist(list 1 2 3 4)) */
+       regs = "^[(][\t ]*define[\t ]+[^\t (]+[\t ]*[(][\t ]*list[\t ]+"\
+               "[^\t ]+.*[)][\t ]*[)]";
+       if (regcomp(&regex_buff, regs, REG_EXTENDED)) {
+               regfree(&regex_buff);
+               return(dobeep_msg("Could not compile regex"));
+       }
+       if (!regexec(&regex_buff, funstr, 0, NULL, 0)) {
+               regfree(&regex_buff);
+               return(foundlist(funstr));
+       }
+       /* Does the line have a single variable 'define' like: */
+       /* (define i 0) */
+       regs = "^[(][\t ]*define[\t ]+[^\t (]+[\t ]*[^\t (]+[\t ]*[)]";
+       if (regcomp(&regex_buff, regs, REG_EXTENDED)) {
+               regfree(&regex_buff);
+               return(dobeep_msg("Could not compile regex"));
+       }
+       if (!regexec(&regex_buff, funstr, 0, NULL, 0)) {
+               regfree(&regex_buff);
+               return(foundvar(funstr));
+       }
+       /* Does the line have an unrecognised 'define' */
+       regs = "^[(][\t ]*define[\t ]+";
+       if (regcomp(&regex_buff, regs, REG_EXTENDED)) {
+               regfree(&regex_buff);
+               return(dobeep_msg("Could not compile regex"));
+       }
+       if (!regexec(&regex_buff, funstr, 0, NULL, 0)) {
+               regfree(&regex_buff);
+               return(dobeep_msg("Invalid use of define"));
+       }
+       regfree(&regex_buff);
+       return(multiarg(funstr));
+}
+
 /*
  * excline - run a line from a load file or eval-expression.
  */
@@ -837,18 +1055,16 @@ excline(char *line)

        lp = NULL;

-       if (macrodef || inmacro) {
-               dobeep();
-               ewprintf("Not now!");
-               return (FALSE);
-       }
+       if (macrodef || inmacro)
+               return(dobeep_msg("Not now!"));
+
        f = 0;
        n = 1;
        funcp = skipwhite(line);
        if (*funcp == '\0')
                return (TRUE);  /* No error on blank lines */
        if (*funcp == '(')
-               return (multiarg(funcp));
+               return (foundparen(funcp));
        line = parsetoken(funcp);
        if (*line != '\0') {
                *line++ = '\0';
@@ -867,11 +1083,9 @@ excline(char *line)
                        return (FALSE);
                n = (int)nl;
        }
-       if ((fp = name_function(funcp)) == NULL) {
-               dobeep();
-               ewprintf("Unknown function: %s", funcp);
-               return (FALSE);
-       }
+       if ((fp = name_function(funcp)) == NULL)
+               return (dobeep_msgs("Unknown function: ", funcp));
+
        if (fp == bindtokey || fp == unbindtokey) {
                bind = BINDARG;
                curmap = fundamental_map;

Reply via email to