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

Diff for /src/usr.bin/rdist/expand.c between version 1.1 and 1.2

version 1.1, 1995/10/18 08:45:59 version 1.2, 1996/02/03 12:12:23
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 1983, 1993   * Copyright (c) 1983 Regents of the University of California.
  *      The Regents of the University of California.  All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 32 
Line 32 
  */   */
   
 #ifndef lint  #ifndef lint
 /* from: static char sccsid[] = "@(#)expand.c   8.1 (Berkeley) 6/9/93"; */  static char RCSid[] =
 static char *rcsid = "$Id$";  "$Id$";
   
   static char sccsid[] = "@(#)expand.c    5.2 (Berkeley) 3/28/86";
   
   char copyright[] =
   "@(#) Copyright (c) 1983 Regents of the University of California.\n\
    All rights reserved.\n";
 #endif /* not lint */  #endif /* not lint */
   
 #include "defs.h"  #include "defs.h"
   
 #define GAVSIZ  NCARGS / 6  #define MAXEARGS        2048
 #define LC '{'  #define LC              '{'
 #define RC '}'  #define RC              '}'
   
 static char     shchars[] = "${[*?";  static char     shchars[] = "${[*?";
   
 int     which;          /* bit mask of types to expand */  int             which;          /* bit mask of types to expand */
 int     eargc;          /* expanded arg count */  int             eargc;          /* expanded arg count */
 char    **eargv;        /* expanded arg vectors */  char          **eargv;          /* expanded arg vectors */
 char    *path;  char           *path;
 char    *pathp;  char           *pathp;
 char    *lastpathp;  char           *lastpathp;
 char    *tilde;         /* "~user" if not expanding tilde, else "" */  char           *tilde;          /* "~user" if not expanding tilde, else "" */
 char    *tpathp;  char           *tpathp;
 int     nleft;  
   
 int     expany;         /* any expansions done? */  int             expany;         /* any expansions done? */
 char    *entp;  char           *entp;
 char    **sortbase;  char          **sortbase;
   char           *argvbuf[MAXEARGS];
   
   static int      argcmp();
   void            expstr();
   void            expsh();
   void            matchdir();
   
 #define sort()  qsort((char *)sortbase, &eargv[eargc] - sortbase, \  #define sort()  qsort((char *)sortbase, &eargv[eargc] - sortbase, \
                       sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]                        sizeof(*sortbase), argcmp), sortbase = &eargv[eargc]
   
 static void     Cat __P((char *, char *));  static void Cat(s1, s2)                         /* quote in s1 and s2 */
 static void     addpath __P((int));          register u_char *s1, *s2;
 static int      amatch __P((char *, char *));  {
 static int      argcmp __P((const void *, const void *));          register char *cp;
 static int      execbrc __P((char *, char *));          int len = strlen((char *)s1) + strlen((char *)s2) + 2;
 static void     expsh __P((char *));  
 static void     expstr __P((char *));  
 static int      match __P((char *, char *));  
 static void     matchdir __P((char *));  
 static int      smatch __P((char *, char *));  
   
           if ((eargc + 1) >= MAXEARGS) {
                   yyerror("Too many names");
                   return;
           }
   
           eargv[++eargc] = (char *) NULL;
           eargv[eargc - 1] = cp = xmalloc(len);
   
           do {
                   if (*s1 == QUOTECHAR)
                           s1++;
           } while (*cp++ = *s1++);
           cp--;
           do {
                   if (*s2 == QUOTECHAR)
                           s2++;
           } while (*cp++ = *s2++);
   }
   
   static void addpath(c)
           char c;
   {
           if (pathp >= lastpathp) {
                   yyerror("Pathname too long");
                   return;
           } else {
                   *pathp++ = c;
                   *pathp = CNULL;
           }
   }
   
 /*  /*
  * Take a list of names and expand any macros, etc.   * Take a list of names and expand any macros, etc.
  * wh = E_VARS if expanding variables.   * wh = E_VARS if expanding variables.
Line 82 
Line 119 
  * Major portions of this were snarfed from csh/sh.glob.c.   * Major portions of this were snarfed from csh/sh.glob.c.
  */   */
 struct namelist *  struct namelist *
 expand(list, wh)  expand(list, wh)                                /* quote in list->n_name */
         struct namelist *list;          struct namelist *list;
         int wh;          int wh;
 {  {
         register struct namelist *nl, *prev;          register struct namelist *nl, *prev;
         register int n;          register int n;
         char pathbuf[BUFSIZ];          char pathbuf[BUFSIZ];
         char *argvbuf[GAVSIZ];  
   
         if (debug) {          if (debug)
                 printf("expand(%x, %d)\nlist = ", list, wh);                  debugmsg(DM_CALL, "expand(%x, %d) start, list = %s",
                 prnames(list);                           list, wh, getnlstr(list));
         }  
   
         if (wh == 0) {          if (wh == 0)
                 register char *cp;                  fatalerr("expand() contains invalid 'wh' argument.");
   
                 for (nl = list; nl != NULL; nl = nl->n_next)  
                         for (cp = nl->n_name; *cp; cp++)  
                                 *cp = *cp & TRIM;  
                 return(list);  
         }  
   
         which = wh;          which = wh;
         path = tpathp = pathp = pathbuf;          path = tpathp = pathp = pathbuf;
         *pathp = '\0';          *pathp = CNULL;
         lastpathp = &path[sizeof pathbuf - 2];          lastpathp = &path[sizeof pathbuf - 2];
         tilde = "";          tilde = "";
         eargc = 0;          eargc = 0;
         eargv = sortbase = argvbuf;          eargv = sortbase = argvbuf;
         *eargv = 0;          *eargv = (char *) NULL;
         nleft = NCARGS - 4;  
         /*          /*
          * Walk the name list and expand names into eargv[];           * Walk the name list and expand names into eargv[];
          */           */
         for (nl = list; nl != NULL; nl = nl->n_next)          for (nl = list; nl != NULL; nl = nl->n_next)
                 expstr(nl->n_name);                  expstr((u_char *)nl->n_name);
         /*          /*
          * Take expanded list of names from eargv[] and build a new list.           * Take expanded list of names from eargv[] and build a new list.
          */           */
         list = prev = NULL;          list = prev = NULL;
         for (n = 0; n < eargc; n++) {          for (n = 0; n < eargc; n++) {
                 nl = makenl(NULL);                  nl = makenl((char *)NULL);
                 nl->n_name = eargv[n];                  nl->n_name = eargv[n];
                 if (prev == NULL)                  if (prev == NULL)
                         list = prev = nl;                          list = prev = nl;
Line 133 
Line 162 
                         prev = nl;                          prev = nl;
                 }                  }
         }          }
         if (debug) {  
                 printf("expanded list = ");  
                 prnames(list);  
         }  
         return(list);          return(list);
 }  }
   
 static void  /*
 expstr(s)   * xstrchr() is a version of strchr() that
         char *s;   * handles u_char buffers.
    */
   u_char *xstrchr(str, ch)
           u_char *str;
           int ch;
 {  {
         register char *cp, *cp1;          register u_char *cp;
   
           for (cp = str; cp && *cp != CNULL; ++cp)
                   if (ch == *cp)
                           return(cp);
   
           return((u_char *)NULL);
   }
   
   void expstr(s)
           u_char *s;
   {
           register u_char *cp, *cp1;
         register struct namelist *tp;          register struct namelist *tp;
         char *tail;          u_char *tail;
         char buf[BUFSIZ];          u_char ebuf[BUFSIZ];
           u_char varbuff[BUFSIZ];
         int savec, oeargc;          int savec, oeargc;
         extern char homedir[];          extern char *homedir;
   
         if (s == NULL || *s == '\0')          if (s == NULL || *s == CNULL)
                 return;                  return;
   
         if ((which & E_VARS) && (cp = index(s, '$')) != NULL) {          /*
                 *cp++ = '\0';           * Remove quoted characters
                 if (*cp == '\0') {           */
           if (IS_ON(which, E_VARS)) {
                   if ((int)strlen((char *)s) > sizeof(varbuff)) {
                           yyerror("Variable is too large.");
                           return;
                   }
                   for (cp = s, cp1 = varbuff; cp && *cp; ++cp) {
                           /*
                            * remove quoted character if the next
                            * character is not $
                            */
                           if (*cp == QUOTECHAR && *(cp+1) != '$')
                                   ++cp;
                           else
                                   *cp1++ = *cp;
                   }
                   *cp1 = CNULL;
                   s = varbuff;
           }
   
           /*
            * Consider string 's' a variable that should be expanded if
            * there is a '$' in 's' that is not quoted.
            */
           if (IS_ON(which, E_VARS) &&
               ((cp = xstrchr(s, '$')) && !(cp > s && *(cp-1) == QUOTECHAR))) {
                   *cp++ = CNULL;
                   if (*cp == CNULL) {
                         yyerror("no variable name after '$'");                          yyerror("no variable name after '$'");
                         return;                          return;
                 }                  }
                 if (*cp == LC) {                  if (*cp == LC) {
                         cp++;                          cp++;
                         if ((tail = index(cp, RC)) == NULL) {                          for (cp1 = cp; ; cp1 = tail + 1) {
                                 yyerror("unmatched '{'");                                  if ((tail = xstrchr(cp1, RC)) == NULL) {
                                 return;                                          yyerror("unmatched '{'");
                                           return;
                                   }
                                   if (tail[-1] != QUOTECHAR) break;
                         }                          }
                         *tail++ = savec = '\0';                          *tail++ = savec = CNULL;
                         if (*cp == '\0') {                          if (*cp == CNULL) {
                                 yyerror("no variable name after '$'");                                  yyerror("no variable name after '$'");
                                 return;                                  return;
                         }                          }
                 } else {                  } else {
                         tail = cp + 1;                          tail = cp + 1;
                         savec = *tail;                          savec = *tail;
                         *tail = '\0';                          *tail = CNULL;
                 }                  }
                 tp = lookup(cp, NULL, 0);                  tp = lookup((char *)cp, LOOKUP, (struct namelist *)NULL);
                 if (savec != '\0')                  if (savec != CNULL)
                         *tail = savec;                          *tail = savec;
                 if (tp != NULL) {                  if (tp != NULL) {
                         for (; tp != NULL; tp = tp->n_next) {                          for (; tp != NULL; tp = tp->n_next) {
                                 sprintf(buf, "%s%s%s", s, tp->n_name, tail);                                  (void) sprintf((char *)ebuf,
                                 expstr(buf);                                                 "%s%s%s", s, tp->n_name, tail);
                                   expstr(ebuf);
                         }                          }
                         return;                          return;
                 }                  }
                 sprintf(buf, "%s%s", s, tail);                  (void) sprintf((char *)ebuf, "%s%s", s, tail);
                 expstr(buf);                  expstr(ebuf);
                 return;                  return;
         }          }
         if ((which & ~E_VARS) == 0 || !strcmp(s, "{") || !strcmp(s, "{}")) {          if ((which & ~E_VARS) == 0 || !strcmp((char *)s, "{") ||
                 Cat(s, "");              !strcmp((char *)s, "{}")) {
                   Cat(s, (u_char *)"");
                 sort();                  sort();
                 return;                  return;
         }          }
         if (*s == '~') {          if (*s == '~') {
                 cp = ++s;                  cp = ++s;
                 if (*cp == '\0' || *cp == '/') {                  if (*cp == CNULL || *cp == '/') {
                         tilde = "~";                          tilde = "~";
                         cp1 = homedir;                          cp1 = (u_char *)homedir;
                 } else {                  } else {
                         tilde = cp1 = buf;                          tilde = (char *)(cp1 = ebuf);
                         *cp1++ = '~';                          *cp1++ = '~';
                         do                          do
                                 *cp1++ = *cp++;                                  *cp1++ = *cp++;
                         while (*cp && *cp != '/');                          while (*cp && *cp != '/');
                         *cp1 = '\0';                          *cp1 = CNULL;
                         if (pw == NULL || strcmp(pw->pw_name, buf+1) != 0) {                          if (pw == NULL || strcmp(pw->pw_name,
                                 if ((pw = getpwnam(buf+1)) == NULL) {                                                   (char *)ebuf+1) != 0) {
                                         strcat(buf, ": unknown user name");                                  if ((pw = getpwnam((char *)ebuf+1)) == NULL) {
                                         yyerror(buf+1);                                          strcat((char *)ebuf,
                                                  ": unknown user name");
                                           yyerror((char *)ebuf+1);
                                         return;                                          return;
                                 }                                  }
                         }                          }
                         cp1 = pw->pw_dir;                          cp1 = (u_char *)pw->pw_dir;
                         s = cp;                          s = cp;
                 }                  }
                 for (cp = path; *cp++ = *cp1++; )                  for (cp = (u_char *)path; *cp++ = *cp1++; )
                         ;                          ;
                 tpathp = pathp = cp - 1;                  tpathp = pathp = (char *)cp - 1;
         } else {          } else {
                 tpathp = pathp = path;                  tpathp = pathp = path;
                 tilde = "";                  tilde = "";
         }          }
         *pathp = '\0';          *pathp = CNULL;
         if (!(which & E_SHELL)) {          if (!(which & E_SHELL)) {
                 if (which & E_TILDE)                  if (which & E_TILDE)
                         Cat(path, s);                          Cat((u_char *)path, s);
                 else                  else
                         Cat(tilde, s);                          Cat((u_char *)tilde, s);
                 sort();                  sort();
                 return;                  return;
         }          }
Line 237 
Line 314 
         expany = 0;          expany = 0;
         expsh(s);          expsh(s);
         if (eargc == oeargc)          if (eargc == oeargc)
                 Cat(s, "");             /* "nonomatch" is set */                  Cat(s, (u_char *)"");           /* "nonomatch" is set */
         sort();          sort();
 }  }
   
 static int  static
 argcmp(a1, a2)  argcmp(a1, a2)
         const void *a1, *a2;          char **a1, **a2;
 {  {
   
         return (strcmp(*(char **)a1, *(char **)a2));          return (strcmp(*a1, *a2));
 }  }
   
 /*  /*
  * If there are any Shell meta characters in the name,   * If there are any Shell meta characters in the name,
  * expand into a list, after searching directory   * expand into a list, after searching directory
  */   */
 static void  void expsh(s)                           /* quote in s */
 expsh(s)          u_char *s;
         char *s;  
 {  {
         register char *cp;          register u_char *cp, *oldcp;
         register char *spathp, *oldcp;          register char *spathp;
         struct stat stb;          struct stat stb;
   
         spathp = pathp;          spathp = pathp;
         cp = s;          cp = s;
         while (!any(*cp, shchars)) {          while (!any(*cp, shchars)) {
                 if (*cp == '\0') {                  if (*cp == CNULL) {
                         if (!expany || stat(path, &stb) >= 0) {                          if (!expany || stat(path, &stb) >= 0) {
                                 if (which & E_TILDE)                                  if (which & E_TILDE)
                                         Cat(path, "");                                          Cat((u_char *)path, (u_char *)"");
                                 else                                  else
                                         Cat(tilde, tpathp);                                          Cat((u_char *)tilde, (u_char *)tpathp);
                         }                          }
                         goto endit;                          goto endit;
                 }                  }
                   if (*cp == QUOTECHAR) cp++;
                 addpath(*cp++);                  addpath(*cp++);
         }          }
         oldcp = cp;          oldcp = cp;
Line 280 
Line 357 
                 cp--, pathp--;                  cp--, pathp--;
         if (*cp == '/')          if (*cp == '/')
                 cp++, pathp++;                  cp++, pathp++;
         *pathp = '\0';          *pathp = CNULL;
         if (*oldcp == '{') {          if (*oldcp == '{') {
                 execbrc(cp, NULL);                  (void) execbrc(cp, (u_char *)NULL);
                 return;                  return;
         }          }
         matchdir(cp);          matchdir((char *)cp);
 endit:  endit:
         pathp = spathp;          pathp = spathp;
         *pathp = '\0';          *pathp = CNULL;
 }  }
   
 static void  void matchdir(pattern)                          /* quote in pattern */
 matchdir(pattern)  
         char *pattern;          char *pattern;
 {  {
         struct stat stb;          struct stat stb;
         register struct direct *dp;          register DIRENTRY *dp;
         DIR *dirp;          DIR *dirp;
   
         dirp = opendir(path);          dirp = opendir(path);
Line 307 
Line 383 
         }          }
         if (fstat(dirp->dd_fd, &stb) < 0)          if (fstat(dirp->dd_fd, &stb) < 0)
                 goto patherr1;                  goto patherr1;
         if (!ISDIR(stb.st_mode)) {          if (!S_ISDIR(stb.st_mode)) {
                 errno = ENOTDIR;                  errno = ENOTDIR;
                 goto patherr1;                  goto patherr1;
         }          }
         while ((dp = readdir(dirp)) != NULL)          while ((dp = readdir(dirp)) != NULL)
                 if (match(dp->d_name, pattern)) {                  if (match(dp->d_name, pattern)) {
                         if (which & E_TILDE)                          if (which & E_TILDE)
                                 Cat(path, dp->d_name);                                  Cat((u_char *)path, (u_char *)dp->d_name);
                         else {                          else {
                                 strcpy(pathp, dp->d_name);                                  (void) strcpy(pathp, dp->d_name);
                                 Cat(tilde, tpathp);                                  Cat((u_char *)tilde, (u_char *)tpathp);
                                 *pathp = '\0';                                  *pathp = CNULL;
                         }                          }
                 }                  }
         closedir(dirp);          closedir(dirp);
Line 327 
Line 403 
 patherr1:  patherr1:
         closedir(dirp);          closedir(dirp);
 patherr2:  patherr2:
         strcat(path, ": ");          (void) strcat(path, ": ");
         strcat(path, strerror(errno));          (void) strcat(path, SYSERR);
         yyerror(path);          yyerror(path);
 }  }
   
 static int  execbrc(p, s)                           /* quote in p */
 execbrc(p, s)          u_char *p, *s;
         char *p, *s;  
 {  {
         char restbuf[BUFSIZ + 2];          u_char restbuf[BUFSIZ + 2];
         register char *pe, *pm, *pl;          register u_char *pe, *pm, *pl;
         int brclev = 0;          int brclev = 0;
         char *lm, savec, *spathp;          u_char *lm, savec;
           char *spathp;
   
         for (lm = restbuf; *p != '{'; *lm++ = *p++)          for (lm = restbuf; *p != '{'; *lm++ = *p++)
                 continue;                  if (*p == QUOTECHAR) *lm++ = *p++;
   
         for (pe = ++p; *pe; pe++)          for (pe = ++p; *pe; pe++)
                 switch (*pe) {                  switch (*pe) {
   
Line 358 
Line 435 
   
                 case '[':                  case '[':
                         for (pe++; *pe && *pe != ']'; pe++)                          for (pe++; *pe && *pe != ']'; pe++)
                                 continue;                                  if (*p == QUOTECHAR) pe++;
                         if (!*pe)                          if (!*pe)
                                 yyerror("Missing ']'");                                  yyerror("Missing ']'");
                         continue;                          continue;
   
                   case QUOTECHAR:         /* skip this character */
                           pe++;
                           continue;
                 }                  }
 pend:  pend:
         if (brclev || !*pe) {          if (brclev || !*pe) {
Line 369 
Line 450 
                 return (0);                  return (0);
         }          }
         for (pl = pm = p; pm <= pe; pm++)          for (pl = pm = p; pm <= pe; pm++)
                 switch (*pm & (QUOTE|TRIM)) {                  /* the strip code was a noop */
                   switch (*pm) {
   
                 case '{':                  case '{':
                         brclev++;                          brclev++;
Line 388 
Line 470 
 doit:  doit:
                         savec = *pm;                          savec = *pm;
                         *pm = 0;                          *pm = 0;
                         strcpy(lm, pl);                          (void) strcpy((char *)lm, (char *)pl);
                         strcat(restbuf, pe + 1);                          (void) strcat((char *)restbuf, (char *)pe + 1);
                         *pm = savec;                          *pm = savec;
                         if (s == 0) {                          if (s == 0) {
                                 spathp = pathp;                                  spathp = pathp;
                                 expsh(restbuf);                                  expsh(restbuf);
                                 pathp = spathp;                                  pathp = spathp;
                                 *pathp = 0;                                  *pathp = 0;
                         } else if (amatch(s, restbuf))                          } else if (amatch((char *)s, restbuf))
                                 return (1);                                  return (1);
                         sort();                          sort();
                         pl = pm + 1;                          pl = pm + 1;
Line 404 
Line 486 
   
                 case '[':                  case '[':
                         for (pm++; *pm && *pm != ']'; pm++)                          for (pm++; *pm && *pm != ']'; pm++)
                                 continue;                                  if (*pm == QUOTECHAR) pm++;
                         if (!*pm)                          if (!*pm)
                                 yyerror("Missing ']'");                                  yyerror("Missing ']'");
                         continue;                          continue;
   
                   case QUOTECHAR:                 /* skip one character */
                           pm++;
                           continue;
                 }                  }
         return (0);          return (0);
 }  }
   
 static int  match(s, p)                                     /* quote in p */
 match(s, p)  
         char *s, *p;          char *s, *p;
 {  {
         register int c;          register int c;
Line 430 
Line 515 
         return (c);          return (c);
 }  }
   
 static int  amatch(s, p)                                    /* quote in p */
 amatch(s, p)          register char *s;
         register char *s, *p;          register u_char *p;
 {  {
         register int scc;          register int scc;
         int ok, lc;          int ok, lc;
Line 442 
Line 527 
   
         expany = 1;          expany = 1;
         for (;;) {          for (;;) {
                 scc = *s++ & TRIM;                  scc = *s++;
                 switch (c = *p++) {                  switch (c = *p++) {
   
                 case '{':                  case '{':
                         return (execbrc(p - 1, s - 1));                          return (execbrc((u_char *)p - 1, (u_char *)s - 1));
   
                 case '[':                  case '[':
                         ok = 0;                          ok = 0;
Line 457 
Line 542 
                                                 break;                                                  break;
                                         return (0);                                          return (0);
                                 }                                  }
                                   if (cc == QUOTECHAR) cc = *p++;
                                 if (cc == '-') {                                  if (cc == '-') {
                                         if (lc <= scc && scc <= *p++)                                          if (lc <= scc && scc <= (int)*p++)
                                                 ok++;                                                  ok++;
                                 } else                                  } else
                                         if (scc == (lc = cc))                                          if (scc == (lc = cc))
Line 482 
Line 568 
                                         return (1);                                          return (1);
                         return (0);                          return (0);
   
                 case '\0':                  case CNULL:
                         return (scc == '\0');                          return (scc == CNULL);
   
                 default:                  default:
                         if ((c & TRIM) != scc)                          if (c != scc)
                                 return (0);                                  return (0);
                         continue;                          continue;
   
                 case '?':                  case '?':
                         if (scc == '\0')                          if (scc == CNULL)
                                 return (0);                                  return (0);
                         continue;                          continue;
   
Line 504 
Line 590 
                         while (*s)                          while (*s)
                                 addpath(*s++);                                  addpath(*s++);
                         addpath('/');                          addpath('/');
                         if (stat(path, &stb) == 0 && ISDIR(stb.st_mode))                          if (stat(path, &stb) == 0 && S_ISDIR(stb.st_mode))
                                 if (*p == '\0') {                                  if (*p == CNULL) {
                                         if (which & E_TILDE)                                          if (which & E_TILDE)
                                                 Cat(path, "");                                                  Cat((u_char *)path,
                                                       (u_char *)"");
                                         else                                          else
                                                 Cat(tilde, tpathp);                                                  Cat((u_char *)tilde,
                                                       (u_char *)tpathp);
                                 } else                                  } else
                                         expsh(p);                                          expsh(p);
                         pathp = spathp;                          pathp = spathp;
                         *pathp = '\0';                          *pathp = CNULL;
                         return (0);                          return (0);
                 }                  }
         }          }
 }  
   
 static int  
 smatch(s, p)  
         register char *s, *p;  
 {  
         register int scc;  
         int ok, lc;  
         int c, cc;  
   
         for (;;) {  
                 scc = *s++ & TRIM;  
                 switch (c = *p++) {  
   
                 case '[':  
                         ok = 0;  
                         lc = 077777;  
                         while (cc = *p++) {  
                                 if (cc == ']') {  
                                         if (ok)  
                                                 break;  
                                         return (0);  
                                 }  
                                 if (cc == '-') {  
                                         if (lc <= scc && scc <= *p++)  
                                                 ok++;  
                                 } else  
                                         if (scc == (lc = cc))  
                                                 ok++;  
                         }  
                         if (cc == 0) {  
                                 yyerror("Missing ']'");  
                                 return (0);  
                         }  
                         continue;  
   
                 case '*':  
                         if (!*p)  
                                 return (1);  
                         for (s--; *s; s++)  
                                 if (smatch(s, p))  
                                         return (1);  
                         return (0);  
   
                 case '\0':  
                         return (scc == '\0');  
   
                 default:  
                         if ((c & TRIM) != scc)  
                                 return (0);  
                         continue;  
   
                 case '?':  
                         if (scc == 0)  
                                 return (0);  
                         continue;  
   
                 }  
         }  
 }  
   
 static void  
 Cat(s1, s2)  
         register char *s1, *s2;  
 {  
         int len = strlen(s1) + strlen(s2) + 1;  
         register char *s;  
   
         nleft -= len;  
         if (nleft <= 0 || ++eargc >= GAVSIZ)  
                 yyerror("Arguments too long");  
         eargv[eargc] = 0;  
         eargv[eargc - 1] = s = malloc(len);  
         if (s == NULL)  
                 fatal("ran out of memory\n");  
         while (*s++ = *s1++ & TRIM)  
                 ;  
         s--;  
         while (*s++ = *s2++ & TRIM)  
                 ;  
 }  
   
 static void  
 addpath(c)  
         int c;  
 {  
   
         if (pathp >= lastpathp)  
                 yyerror("Pathname too long");  
         else {  
                 *pathp++ = c & TRIM;  
                 *pathp = '\0';  
         }  
 }  
   
 /*  
  * Expand file names beginning with `~' into the  
  * user's home directory path name. Return a pointer in buf to the  
  * part corresponding to `file'.  
  */  
 char *  
 exptilde(buf, file)  
         char buf[];  
         register char *file;  
 {  
         register char *s1, *s2, *s3;  
         extern char homedir[];  
   
         if (*file != '~') {  
                 strcpy(buf, file);  
                 return(buf);  
         }  
         if (*++file == '\0') {  
                 s2 = homedir;  
                 s3 = NULL;  
         } else if (*file == '/') {  
                 s2 = homedir;  
                 s3 = file;  
         } else {  
                 s3 = file;  
                 while (*s3 && *s3 != '/')  
                         s3++;  
                 if (*s3 == '/')  
                         *s3 = '\0';  
                 else  
                         s3 = NULL;  
                 if (pw == NULL || strcmp(pw->pw_name, file) != 0) {  
                         if ((pw = getpwnam(file)) == NULL) {  
                                 error("%s: unknown user name\n", file);  
                                 if (s3 != NULL)  
                                         *s3 = '/';  
                                 return(NULL);  
                         }  
                 }  
                 if (s3 != NULL)  
                         *s3 = '/';  
                 s2 = pw->pw_dir;  
         }  
         for (s1 = buf; *s1++ = *s2++; )  
                 ;  
         s2 = --s1;  
         if (s3 != NULL) {  
                 s2++;  
                 while (*s1++ = *s3++)  
                         ;  
         }  
         return(s2);  
 }  }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2