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

Diff for /src/usr.bin/mg/interpreter.c between version 1.20 and 1.21

version 1.20, 2021/03/26 12:31:37 version 1.21, 2021/04/20 14:26:19
Line 66 
Line 66 
 #include "log.h"  #include "log.h"
 #endif  #endif
   
 static int       multiarg(char *);  static int       multiarg(char *, char *, int);
 static int       isvar(char **, char **, int);  static int       isvar(char **, char **, int);
 static int       foundvar(char *);  /*static int     dofunc(char **, char **, int);*/
   static int       founddef(char *, int, int, int);
   static int       foundlst(char *, int, int);
   static int       expandvals(char *, char *, char *);
   static int       foundfun(char *, int);
 static int       doregex(char *, char *);  static int       doregex(char *, char *);
 static int       parseexp_tmp(char *);  
 static void      clearexp(void);  static void      clearexp(void);
 static int       addexp(char *, int, int, int, int);  static int       parse(char *, const char *, const char *, int, int);
 static int       exitinterpreter(void);  static int       parsdef(char *, const char *, const char *, int, int);
   static int       parsval(char *, const char *, const char *, int, int);
   static int       parsexp(char *, const char *, const char *, int, int);
   
   static int       exitinterpreter(char *, char *, int);
   
 TAILQ_HEAD(exphead, expentry) ehead;  TAILQ_HEAD(exphead, expentry) ehead;
 struct expentry {  struct expentry {
         TAILQ_ENTRY(expentry) eentry;          TAILQ_ENTRY(expentry) eentry;
         char    *exp;           /* The string found between paraenthesis. */          char    *fun;           /* The 1st string found between parens.   */
         int      par1;          /* Parenthesis at start of string (=1     */          char     funbuf[BUFSIZE];
         int      par2;          /* Parenthesis at end of string   )=2     */          const char      *par1;  /* Parenthesis at start of string         */
           const char      *par2;  /* Parenthesis at end of string           */
         int      expctr;        /* An incremental counter:+1 for each exp */          int      expctr;        /* An incremental counter:+1 for each exp */
         int      blkid;         /* Which block are we in?                 */          int      blkid;         /* Which block are we in?                 */
 };  };
Line 90 
Line 98 
  */   */
 struct varentry {  struct varentry {
         SLIST_ENTRY(varentry) entry;          SLIST_ENTRY(varentry) entry;
           char     valbuf[BUFSIZE];
         char    *name;          char    *name;
         char    *vals;          char    *vals;
         int      count;          int      count;
           int      expctr;
           int      blkid;
 };  };
 SLIST_HEAD(vlisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);  SLIST_HEAD(vlisthead, varentry) varhead = SLIST_HEAD_INITIALIZER(varhead);
   
Line 110 
Line 121 
                 "lambda"                  "lambda"
         };          };
   
   const char lp = '(';
   const char rp = ')';
   char *defnam = NULL;
   
 /*  /*
  * Line has a '(' as the first non-white char.   * Line has a '(' as the first non-white char.
Line 119 
Line 133 
 int  int
 foundparen(char *funstr, int llen)  foundparen(char *funstr, int llen)
 {  {
         struct expentry *e1 = NULL, *e2 = NULL;          const char      *lrp = NULL;
         char            *p, *begp = NULL, *endp = NULL, *regs;          char            *p, *begp = NULL, *endp = NULL, *regs;
         char             expbuf[BUFSIZE], tmpbuf[BUFSIZE];  
         int              i, ret, pctr, expctr, blkid, inquote;          int              i, ret, pctr, expctr, blkid, inquote;
   
         pctr = expctr = inquote = 0;          pctr = expctr = inquote = 0;
Line 157 
Line 170 
   
         for (i = 0; i < llen; ++i, p++) {          for (i = 0; i < llen; ++i, p++) {
                 if (*p == '(') {                  if (*p == '(') {
                           if (inquote == 1) {
                                   cleanup();
                                   return(dobeep_msg("Opening and closing quote "\
                                       "char error"));
                           }
                         if (begp != NULL) {                          if (begp != NULL) {
                                 if (endp == NULL)                                  if (endp == NULL)
                                         *p = '\0';                                          *p = '\0';
                                 else                                  else
                                         *endp = '\0';                                          *endp = '\0';
   
                                 ret = addexp(begp, 1, 1, blkid, ++expctr);                                  ret = parse(begp, lrp, &lp, blkid, ++expctr);
                                 if (!ret) {                                  if (!ret) {
                                         cleanup();                                          cleanup();
                                         return(ret);                                          return(ret);
                                 }                                  }
                         }                          }
                           lrp = &lp;
                         begp = endp = NULL;                          begp = endp = NULL;
                         pctr++;                          pctr++;
                 } else if (*p == ')') {                  } else if (*p == ')') {
Line 183 
Line 202 
                                 else                                  else
                                         *endp = '\0';                                          *endp = '\0';
   
                                 ret = addexp(begp, 1, 2, blkid, ++expctr);                                  ret = parse(begp, lrp, &rp, blkid, ++expctr);
                                 if (!ret) {                                  if (!ret) {
                                         cleanup();                                          cleanup();
                                         return(ret);                                          return(ret);
                                 }                                  }
                         }                          }
                           lrp = &rp;
                         begp = endp = NULL;                          begp = endp = NULL;
                         pctr--;                          pctr--;
                 } else if (*p != ' ' && *p != '\t') {                  } else if (*p != ' ' && *p != '\t') {
Line 208 
Line 228 
                         if (inquote == 0)                          if (inquote == 0)
                                 *p = ' ';                                  *p = ' ';
   
                 if (pctr == 0)                  if (pctr == 0) {
                         blkid++;                          blkid++;
                           expctr = 0;
                           defnam = NULL;
                   }
         }          }
   
         if (pctr != 0) {          if (pctr != 0) {
                 cleanup();                  cleanup();
                 return(dobeep_msg("Opening and closing parentheses error"));                  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';  
         TAILQ_FOREACH_SAFE(e1, &ehead, eentry, e2) {  
                 if (strlcpy(tmpbuf, expbuf, sizeof(tmpbuf)) >= sizeof(tmpbuf))  
                         return (dobeep_msg("strlcpy error"));  
                 expbuf[0] = '\0';  
                 if (strlcpy(expbuf, e1->exp, sizeof(expbuf)) >= sizeof(expbuf))  
                         return (dobeep_msg("strlcat error"));  
                 if (*tmpbuf != '\0')  
                         if (strlcat(expbuf, " ", sizeof(expbuf)) >=  
                             sizeof(expbuf))  
                                 return (dobeep_msg("strlcat error"));  
                 if (strlcat(expbuf, tmpbuf, sizeof(expbuf)) >= sizeof(expbuf))  
                         return (dobeep_msg("strlcat error"));  
 #ifdef MGLOG  
                 mglog_misc("exp|%s|\n", e1->exp);  
 #endif  
         }  
   
         ret = parseexp_tmp(expbuf);  
         if (ret == FALSE)          if (ret == FALSE)
                 cleanup();                  cleanup();
         else          else
Line 250 
Line 249 
   
   
 static int  static int
 addexp(char *begp, int par1, int par2, int blkid, int expctr)  parse(char *begp, const char *par1, const char *par2, int blkid, int expctr)
 {  {
         struct expentry *e1 = NULL;          char    *regs;
           int      ret = FALSE;
   
         if ((e1 = malloc(sizeof(struct expentry))) == NULL) {          if (strncmp(begp, "define", 6) == 0) {
                 cleanup();                  ret = parsdef(begp, par1, par2, blkid, expctr);
                 return (dobeep_msg("malloc Error"));                  if (ret == TRUE || ret == FALSE)
         }                          return (ret);
         TAILQ_INSERT_HEAD(&ehead, e1, eentry);          } else if (strncmp(begp, "list", 4) == 0)
         if ((e1->exp = strndup(begp, BUFSIZE)) == NULL) {                  return(parsval(begp, par1, par2, blkid, expctr));
                 cleanup();  
                 return(dobeep_msg("strndup error"));  
         }  
         e1->expctr = expctr;  
         e1->blkid = blkid;  
         /* need to think about these two */  
         e1->par1 = par1;  
         e1->par2 = par2;  
   
         return (TRUE);          regs = "^exit$";
           if (doregex(regs, begp))
                   return(exitinterpreter(NULL, NULL, FALSE));
   
           /* mg function name regex */
           regs = "^[A-Za-z-]+$";
           if (doregex(regs, begp))
                   return(excline(begp, 0));
   
           /* Corner case 1 */
           if (strncmp(begp, "global-set-key ", 15) == 0)
                   /* function name as 2nd param screws up multiarg. */
                   return(excline(begp, 0));
   
           /* Corner case 2 */
           if (strncmp(begp, "define-key ", 11) == 0)
                   /* function name as 3rd param screws up multiarg. */
                   return(excline(begp, 0));
   
           return (parsexp(begp, par1, par2, blkid, expctr));
 }  }
   
 /*  
  * At the moment, use parseexp_tmp in lieu of proper block parsing.  
  * Move away from this eventually.  
  */  
 static int  static int
 parseexp_tmp(char *funstr)  parsdef(char *begp, const char *par1, const char *par2, int blkid, int expctr)
 {  {
         char    *regs;          char    *regs;
   
         /* Does the line have a list 'define' like: */          if ((defnam == NULL) && (expctr != 1))
         /* (define alist(list 1 2 3 4)) */                  return(dobeep_msg("'define' incorrectly used"));
         regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+list[ ]+.*[ ]*";  
         if (doregex(regs, funstr))  
                 return(foundvar(funstr));  
   
         /* Does the line have a variable 'define' like: */  
         /* (define i (function-name j)) */  
         regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+[A-Za-z-]+[ ]+.*$";  
         if (doregex(regs, funstr))  
                 return(foundvar(funstr));  
   
         /* Does the line have a incorrect variable 'define' like: */          /* Does the line have a incorrect variable 'define' like: */
         /* (define i y z) */          /* (define i y z) */
         regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.*[ ]+.*$";          regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.+[ ]+.+$";
         if (doregex(regs, funstr))          if (doregex(regs, begp))
                 return(dobeep_msg("Invalid use of define."));                  return(dobeep_msg("Invalid use of define"));
   
         /* Does the line have a single variable 'define' like: */          /* Does the line have a single variable 'define' like: */
         /* (define i 0) */          /* (define i 0) */
         regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.*$";          regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]+.*$";
         if (doregex(regs, funstr))          if (doregex(regs, begp)) {
                 return(foundvar(funstr));                  if (par1 == &lp && par2 == &rp && expctr == 1)
                           return(founddef(begp, blkid, expctr, 1));
                   return(dobeep_msg("Invalid use of define."));
           }
           /* Does the line have  '(define i(' */
           regs = "^define[ ]+[A-Za-z][.0-9_A-Z+a-z-]*[ ]*$";
           if (doregex(regs, begp)) {
                   if (par1 == &lp && par2 == &lp && expctr == 1)
                           return(founddef(begp, blkid, expctr, 0));
                   return(dobeep_msg("Invalid use of 'define'"));
           }
           /* Does the line have  '(define (' */
           regs = "^define$";
           if (doregex(regs, begp)) {
                   if (par1 == &lp && par2 == &lp && expctr == 1)
                           return(foundfun(begp, expctr));
                   return(dobeep_msg("Invalid use of 'define'."));
           }
   
         /* Does the line have an unrecognised 'define' */          return (ABORT);
         regs = "^define[\t ]+";  }
         if (doregex(regs, funstr))  
                 return(dobeep_msg("Invalid use of define"));  
   
         /* Exit? */  static int
         regs = "^exit$";  parsval(char *begp, const char *par1, const char *par2, int blkid, int expctr)
         if (doregex(regs, funstr))  {
                 return(exitinterpreter());          char    *regs;
   
         return(multiarg(funstr));          /* Does the line have 'list' */
           regs = "^list$";
           if (doregex(regs, begp))
                   return(dobeep_msg("Invalid use of list"));
   
           /* Does the line have a 'list' like: */
           /* (list "a" "b") */
           regs = "^list[ ]+.*$";
           if (doregex(regs, begp)) {
                   if (expctr == 1)
                           return(dobeep_msg("list with no-where to go."));
   
                   if (par1 == &lp && expctr > 1)
                           return(foundlst(begp, blkid, expctr));
   
                   return(dobeep_msg("Invalid use of list."));
           }
           return (FALSE);
 }  }
   
 /*  
  * Pass a list of arguments to a function.  
  */  
 static int  static int
 multiarg(char *funstr)  parsexp(char *begp, const char *par1, const char *par2, int blkid, int expctr)
 {  {
         PF       funcp;          struct expentry *e1 = NULL;
         char     excbuf[BUFSIZE], argbuf[BUFSIZE];          PF               funcp;
         char     contbuf[BUFSIZE], varbuf[BUFSIZE];          char            *cmdp, *fendp, *valp, *fname, *funb = NULL;;
         char    *cmdp = NULL, *argp, *fendp = NULL, *endp, *p, *v, *s = " ";          int              numparams, ret;
         char    *regs;  
         int      spc, numparams, numspc;  
         int      inlist, sizof, fin, inquote;  
   
         /* mg function name regex */          cmdp = begp;
         if (doregex("^[A-Za-z-]+$", funstr))  
                 return(excline(funstr, 0));  
   
         cmdp = funstr;  
         fendp = strchr(cmdp, ' ');          fendp = strchr(cmdp, ' ');
         *fendp = '\0';          *fendp = '\0';
   
         /*          /*
          * If no extant mg command found, just return.           * If no extant mg command found, just return.
          */           */
Line 347 
Line 368 
   
         numparams = numparams_function(funcp);          numparams = numparams_function(funcp);
         if (numparams == 0)          if (numparams == 0)
                 return (dobeep_msgs("Command takes no arguments: ", cmdp));                  return (dobeep_msgs("Command takes no arguments:", cmdp));
   
         /* now find the first argument */          if ((e1 = malloc(sizeof(struct expentry))) == NULL) {
         p = fendp + 1;                  cleanup();
         p = skipwhite(p);                  return (dobeep_msg("malloc Error"));
           }
           TAILQ_INSERT_HEAD(&ehead, e1, eentry);
           if ((e1->fun = strndup(cmdp, BUFSIZE)) == NULL) {
                   cleanup();
                   return(dobeep_msg("strndup error"));
           }
           cmdp = e1->fun;
           fname = e1->fun;
           e1->funbuf[0] = '\0';
           funb = e1->funbuf;
           e1->expctr = expctr;
           e1->blkid = blkid;
           /* need to think about these two */
           e1->par1 = par1;
           e1->par2 = par2;
   
         if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))          *fendp = ' ';
                 return (dobeep_msg("strlcpy error"));          valp = fendp + 1;
   
           ret = expandvals(cmdp, valp, funb);
           if (!ret)
                   return (ret);
   
           return (multiarg(fname, funb, numparams));
   }
   
   /*
    * Pass a list of arguments to a function.
    */
   static int
   multiarg(char *cmdp, char *argbuf, int numparams)
   {
           char     excbuf[BUFSIZE];
           char    *argp, *p, *s = " ";
           char    *regs;
           int      spc, numspc;
           int      fin, inquote;
   
         argp = argbuf;          argp = argbuf;
         numspc = spc = 1; /* initially fake a space so we find first argument */          spc = 1; /* initially fake a space so we find first argument */
         inlist = fin = inquote = 0;          numspc = fin = inquote = 0;
   
         for (p = argbuf; *p != '\0'; p++) {          for (p = argbuf; *p != '\0'; p++) {
                 if (*(p + 1) == '\0')                  if (*(p + 1) == '\0')
Line 371 
Line 427 
                                         inquote = 1;                                          inquote = 1;
                         }                          }
                         if (spc == 1)                          if (spc == 1)
                                 argp = p;                                  if ((numspc % numparams) == 0) {
                                           argp = p;
                                   }
                         spc = 0;                          spc = 0;
                 }                  }
                 if ((*p == ' ' && inquote == 0) || fin) {                  if ((*p == ' ' && inquote == 0) || fin) {
                         if (spc == 1)                          if (spc == 1)/* || (numspc % numparams == 0))*/
                                 continue;                                  continue;
                           if ((numspc % numparams) != (numparams - 1)) {
                                   numspc++;
                                   continue;
                           }
                         if (*p == ' ') {                          if (*p == ' ') {
                                 *p = '\0';              /* terminate arg string */                                  *p = '\0';              /* terminate arg string */
                         }                          }
                         endp = p + 1;  
                         excbuf[0] = '\0';                          excbuf[0] = '\0';
                         varbuf[0] = '\0';  
                         contbuf[0] = '\0';  
                         sizof = sizeof(varbuf);  
                         v = varbuf;  
                         regs = "[\"]+.*[\"]+";                          regs = "[\"]+.*[\"]+";
                         if (doregex(regs, argp))  
                                 ;                       /* found quotes */  
                         else if (isvar(&argp, &v, sizof)) {  
                                 (void)(strlcat(varbuf, " ",  
                                     sizof) >= sizof);  
   
                                 *p = ' ';                          if (!doregex(regs, argp)) {
   
                                 (void)(strlcpy(contbuf, endp,  
                                     sizeof(contbuf)) >= sizeof(contbuf));  
   
                                 (void)(strlcat(varbuf, contbuf,  
                                     sizof) >= sizof);  
   
                                 argbuf[0] = ' ';  
                                 argbuf[1] = '\0';  
                                 (void)(strlcat(argbuf, varbuf,  
                                     sizof) >= sizof);  
   
                                 p = argp = argbuf;  
                                 spc = 1;  
                                 fin = 0;  
                                 continue;  
                         } else {  
                                 const char *errstr;                                  const char *errstr;
                                 int iters;                                  int iters;
   
Line 437 
Line 471 
                                 break;                                  break;
   
                         *p = ' ';               /* unterminate arg string */                          *p = ' ';               /* unterminate arg string */
                           numspc++;
                         spc = 1;                          spc = 1;
                 }                  }
         }          }
Line 458 
Line 493 
 #endif  #endif
         SLIST_FOREACH(v1, &varhead, entry) {          SLIST_FOREACH(v1, &varhead, entry) {
                 if (strcmp(*argp, v1->name) == 0) {                  if (strcmp(*argp, v1->name) == 0) {
                         (void)(strlcpy(*varbuf, v1->vals, sizof) >= sizof);                          (void)(strlcpy(*varbuf, v1->valbuf, sizof) >= sizof);
                         return (TRUE);                          return (TRUE);
                 }                  }
         }          }
         return (FALSE);          return (FALSE);
 }  }
   
   
   static int
   foundfun(char *defstr, int expctr)
   {
           return (TRUE);
   }
   
   static int
   foundlst(char *defstr, int blkid, int expctr)
   {
           char            *p;
   
           p = strstr(defstr, " ");
           p = skipwhite(p);
           expandvals(NULL, p, defnam);
   
           return (TRUE);
   }
   
 /*  /*
  * The define string _must_ adhere to the regex in parsexp().   * 'define' strings follow the regex in parsdef().
  * This is not the correct way to do parsing but it does highlight  
  * the issues. Also, vars should find their way into one list only.  
  * Currently they go into two.  
  */   */
 static int  static int
 foundvar(char *defstr)  founddef(char *defstr, int blkid, int expctr, int hasval)
 {  {
         struct varentry *vt, *v1 = NULL;          struct varentry *vt, *v1 = NULL;
         char            *p, *vnamep, *vendp = NULL, *valp;          char            *p, *vnamep, *vendp = NULL, *valp;
         char             tmpbuf[BUFSIZE];  
         int              spc;  
   
         /* vars names can't start with these. */  
         /* char *spchrs = "+-.#";       */  
   
         p = strstr(defstr, " ");        /* move to first ' ' char.    */          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;          vendp = vnamep;
   
         /* now find the end of the list name */          /* now find the end of the define/list name */
         while (1) {          while (1) {
                 ++vendp;                  ++vendp;
                 if (*vendp == ' ')                  if (*vendp == ' ')
Line 495 
Line 541 
         *vendp = '\0';          *vendp = '\0';
   
         /*          /*
          * Check list name is not an existing function.           * Check list name is not an existing mg function.
          */           */
         if (name_function(vnamep) != NULL)          if (name_function(vnamep) != NULL)
                 return(dobeep_msgs("Variable/function name clash:", vnamep));                  return(dobeep_msgs("Variable/function name clash:", vnamep));
   
         p = ++vendp;  
         p = skipwhite(p);  
   
         /*  
          * Now what have we found? A keyword (e.g list)? A value?  
          * We only deal with values and a couple of keywords at moment.  
          */  
         if (strncmp(p, "list ", 5) == 0) {  
                 p = strstr(p, " ");     /* find ' ' after 'list'.  */  
                 valp = skipwhite(p);    /* find first value     */  
         } else if (strncmp(p, "get-environment-variable ", 25) == 0) {  
                 const char      *t;  
                 char            *tmp;  
                 const char      *q = "\"";  
   
                 p = strstr(p, " ");     /* find ' ' after keyword.  */  
                 t = skipwhite(p);    /* find first value     */  
   
                 if (t[0] == *q || t[strlen(t) - 1] == *q)  
                         return (dobeep_msgs("Please remove '\"' around:",  
                             t));  
                 if ((tmp = getenv(t)) == NULL || *tmp == '\0')  
                         return(dobeep_msgs("Envar not found:", t));  
                 /* envar is returned without "" around the string */  
                 tmpbuf[0] = '\0';  
                 if (strlcat(tmpbuf, q, sizeof(tmpbuf)) >= sizeof(tmpbuf))  
                         return (dobeep_msg("strlcat error"));  
                 if (strlcat(tmpbuf, tmp, sizeof(tmpbuf)) >= sizeof(tmpbuf))  
                         return (dobeep_msg("strlcat error"));  
                 if (strlcat(tmpbuf, q, sizeof(tmpbuf)) >= sizeof(tmpbuf))  
                         return (dobeep_msg("strlcat error"));  
   
                 valp = tmpbuf;  
         } else  
                 valp = p;  
         /*  
          * 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)) {          if (!SLIST_EMPTY(&varhead)) {
                 SLIST_FOREACH_SAFE(v1, &varhead, entry, vt) {                  SLIST_FOREACH_SAFE(v1, &varhead, entry, vt) {
                         if (strcmp(vnamep, v1->name) == 0)                          if (strcmp(vnamep, v1->name) == 0)
Line 551 
Line 557 
         SLIST_INSERT_HEAD(&varhead, v1, entry);          SLIST_INSERT_HEAD(&varhead, v1, entry);
         if ((v1->name = strndup(vnamep, BUFSIZE)) == NULL)          if ((v1->name = strndup(vnamep, BUFSIZE)) == NULL)
                 return(dobeep_msg("strndup error"));                  return(dobeep_msg("strndup error"));
           vnamep = v1->name;
         v1->count = 0;          v1->count = 0;
         vendp = NULL;          v1->expctr = expctr;
           v1->blkid = blkid;
         /* initially fake a space so we find first value */          v1->vals = NULL;
         spc = 1;          v1->valbuf[0] = '\0';
         /* now loop through values in list value string while counting them */  
         for (p = valp; *p != '\0'; p++) {          defnam = v1->valbuf;
                 if (*p != ' ' && *p != '\t') {  
           if (hasval) {
                   valp = skipwhite(vendp + 1);
   
                   expandvals(NULL, valp, defnam);
                   defnam = NULL;
           }
           *vendp = ' ';
           return (TRUE);
   }
   
   
   static int
   expandvals(char *cmdp, char *valp, char *bp)
   {
           char     excbuf[BUFSIZE], argbuf[BUFSIZE];
           char     contbuf[BUFSIZE], varbuf[BUFSIZE];
           char    *argp, *endp, *p, *v, *s = " ";
           char    *regs;
           int      spc, cnt;
           int      inlist, sizof, fin, inquote;
   
           /* now find the first argument */
           p = skipwhite(valp);
   
           if (strlcpy(argbuf, p, sizeof(argbuf)) >= sizeof(argbuf))
                   return (dobeep_msg("strlcpy error"));
           argp = argbuf;
           spc = 1; /* initially fake a space so we find first argument */
           inlist = fin = inquote = cnt = spc = 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)                          if (spc == 1)
                                 v1->count++;                                  argp = p;
                         spc = 0;                          spc = 0;
                 }                  }
         }                  if ((*p == ' ' && inquote == 0) || fin) {
         if ((v1->vals = strndup(valp, BUFSIZE)) == NULL)                          if (spc == 1)
                 return(dobeep_msg("strndup error"));                                  continue;
                           /* terminate arg string */
                           if (*p == ' ') {
                                   *p = '\0';
                           }
                           endp = p + 1;
                           excbuf[0] = '\0';
                           varbuf[0] = '\0';
                           contbuf[0] = '\0';
                           sizof = sizeof(varbuf);
                           v = varbuf;
                           regs = "[\"]+.*[\"]+";
                           if (doregex(regs, argp))
                                   ;                       /* found quotes */
                           else if (isvar(&argp, &v, sizof)) {
   
                                   (void)(strlcat(varbuf, " ",
                                       sizof) >= sizof);
   
                                   *p = ' ';
                                   (void)(strlcpy(contbuf, endp,
                                       sizeof(contbuf)) >= sizeof(contbuf));
   
                                   (void)(strlcat(varbuf, contbuf,
                                       sizof) >= sizof);
   
                                   argbuf[0] = ' ';
                                   argbuf[1] = '\0';
                                   (void)(strlcat(argbuf, varbuf,
                                       sizof) >= sizof);
   
                                   p = argp = argbuf;
                                   spc = 1;
                                   fin = 0;
                                   continue;
                           } else {
                                   const char *errstr;
                                   int iters;
   
                                   iters = strtonum(argp, 0, INT_MAX, &errstr);
                                   if (errstr != NULL)
                                           return (dobeep_msgs("Var not found:",
                                               argp));
                           }
 #ifdef  MGLOG  #ifdef  MGLOG
         mglog_misc("var:%s\t#items:%d\tvals:|%s|\n", vnamep, v1->count, v1->vals);          mglog_misc("x|%s|%p|%d|\n", bp, defnam, BUFSIZE);
 #endif  #endif
                           if (*bp != '\0') {
                                   if (strlcat(bp, s, BUFSIZE) >= BUFSIZE)
                                           return (dobeep_msg("strlcat error"));
                           }
                           if (strlcat(bp, argp, BUFSIZE) >= BUFSIZE) {
                                   return (dobeep_msg("strlcat error"));
                           }
   /*                      v1->count++;*/
   
                           if (fin)
                                   break;
   
                           *p = ' ';               /* unterminate arg string */
                           spc = 1;
                   }
           }
         return (TRUE);          return (TRUE);
 }  }
   
Line 586 
Line 691 
         while (!SLIST_EMPTY(&varhead)) {          while (!SLIST_EMPTY(&varhead)) {
                 v1 = SLIST_FIRST(&varhead);                  v1 = SLIST_FIRST(&varhead);
                 SLIST_REMOVE_HEAD(&varhead, entry);                  SLIST_REMOVE_HEAD(&varhead, entry);
                 free(v1->vals);  /*              free(v1->vals);*/
                 free(v1->name);                  free(v1->name);
                 free(v1);                  free(v1);
         }          }
Line 604 
Line 709 
         while (!TAILQ_EMPTY(&ehead)) {          while (!TAILQ_EMPTY(&ehead)) {
                 e1 = TAILQ_FIRST(&ehead);                  e1 = TAILQ_FIRST(&ehead);
                 TAILQ_REMOVE(&ehead, e1, eentry);                  TAILQ_REMOVE(&ehead, e1, eentry);
                 free(e1->exp);                  free(e1->fun);
                 free(e1);                  free(e1);
         }          }
         return;          return;
Line 616 
Line 721 
 void  void
 cleanup(void)  cleanup(void)
 {  {
           defnam = NULL;
   
         clearexp();          clearexp();
         clearvars();          clearvars();
 }  }
Line 645 
Line 752 
  * execution.   * execution.
  */   */
 static int  static int
 exitinterpreter()  exitinterpreter(char *ptr, char *dobuf, int dosiz)
 {  {
         cleanup();          cleanup();
         if (batch == 0)          if (batch == 0)
                 return(dobeep_msg("Interpreter exited via exit command."));                  return(dobeep_msg("Interpreter exited via exit command."));
         return(FALSE);          return(FALSE);
 }  }
   
   /*
    * All code below commented out (until end of file).
    *
    * Need to think about how interpreter functions are done.
    * Probably don't have a choice with string-append().
   
   static int       getenvironmentvariable(char *, char *, int);
   static int       stringappend(char *, char *, int);
   
   typedef int      (*PFI)(char *, char *, int);
   
   
   struct ifunmap {
           PFI              fn_funct;
           const char      *fn_name;
           struct ifunmap  *fn_next;
   };
   static struct ifunmap *ifuns;
   
   static struct ifunmap ifunctnames[] = {
           {exitinterpreter, "exit"},
           {getenvironmentvariable, "get-environment-variable"},
           {stringappend, "string-append"},
           {NULL, NULL}
   };
   
   void
   ifunmap_init(void)
   {
           struct ifunmap *fn;
   
           for (fn = ifunctnames; fn->fn_name != NULL; fn++) {
                   fn->fn_next = ifuns;
                   ifuns = fn;
           }
   }
   
   PFI
   name_ifun(const char *ifname)
   {
           struct ifunmap  *fn;
   
           for (fn = ifuns; fn != NULL; fn = fn->fn_next) {
                   if (strcmp(fn->fn_name, ifname) == 0)
                           return (fn->fn_funct);
           }
   
           return (NULL);
   }
   
   
   int
   dofunc(char **ifname, char **tmpbuf, int sizof)
   {
           PFI      fnc;
           char    *p, *tmp;
   
           p = strstr(*ifname, " ");
           *p = '\0';
   
           fnc = name_ifun(*ifname);
           if (fnc == NULL)
                   return (FALSE);
   
           *p = ' ';
   
           tmp = *tmpbuf;
   
           fnc(p, tmp, sizof);
   
           return (TRUE);
   }
   
   static int
   getenvironmentvariable(char *ptr, char *dobuf, int dosiz)
   {
           char            *t;
           char            *tmp;
           const char      *q = "\"";
   
           t = skipwhite(ptr);
   
           if (t[0] == *q || t[strlen(t) - 1] == *q)
                   return (dobeep_msgs("Please remove '\"' around:", t));
           if ((tmp = getenv(t)) == NULL || *tmp == '\0')
                   return(dobeep_msgs("Envar not found:", t));
   
           dobuf[0] = '\0';
           if (strlcat(dobuf, q, dosiz) >= dosiz)
                   return (dobeep_msg("strlcat error"));
           if (strlcat(dobuf, tmp, dosiz) >= dosiz)
                   return (dobeep_msg("strlcat error"));
           if (strlcat(dobuf, q, dosiz) >= dosiz)
                   return (dobeep_msg("strlcat error"));
   
           return (TRUE);
   }
   
   static int
   stringappend(char *ptr, char *dobuf, int dosiz)
   {
           char             varbuf[BUFSIZE], funbuf[BUFSIZE];
           char            *p, *f, *v, *vendp;
           int              sizof, fin = 0;
   
           varbuf[0] = funbuf[0] = '\0';
           f = funbuf;
           v = varbuf;
           sizof = sizeof(varbuf);
           *dobuf = '\0';
   
           p = skipwhite(ptr);
   
           while (*p != '\0') {
                   vendp = p;
                   while (1) {
                           if (*vendp == ' ') {
                                   break;
                           } else if (*vendp == '\0') {
                                   fin = 1;
                                   break;
                           }
                           ++vendp;
                   }
                   *vendp = '\0';
   
                   if (isvar(&p, &v, sizof)) {
                           if (v[0] == '"' && v[strlen(v) - 1] == '"' ) {
                                   v[strlen(v) - 1] = '\0';
                                   v = v + 1;
                           }
                           if (strlcat(f, v, sizof) >= sizof)
                                   return (dobeep_msg("strlcat error"));
                   } else {
                           if (p[0] == '"' && p[strlen(p) - 1] == '"' ) {
                                   p[strlen(p) - 1] = '\0';
                                   p = p + 1;
                           }
                           if (strlcat(f, p, sizof) >= sizof)
                                   return (dobeep_msg("strlcat error"));
                   }
                   if (fin)
                           break;
                   vendp++;
                   if (*vendp == '\0')
                           break;
                   p = skipwhite(vendp);
           }
   
           (void)snprintf(dobuf, dosiz, "\"%s\"", f);
   
           return (TRUE);
   }
   
   Index: main.c
   ===================================================================
   RCS file: /cvs/src/usr.bin/mg/main.c,v
   retrieving revision 1.89
   diff -u -p -u -p -r1.89 main.c
   --- main.c      20 Mar 2021 09:00:49 -0000      1.89
   +++ main.c      12 Apr 2021 17:58:52 -0000
   @@ -133,10 +133,12 @@ main(int argc, char **argv)
                   extern void grep_init(void);
                   extern void cmode_init(void);
                   extern void dired_init(void);
   +               extern void ifunmap_init(void);
   
                   dired_init();
                   grep_init();
                   cmode_init();
   +               ifunmap_init();
           }
   
   
   */

Legend:
Removed from v.1.20  
changed lines
  Added in v.1.21