home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / glob.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  25KB  |  1,274 lines

  1. /*
  2.  *
  3.  * glob.c - filename generation
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made. 
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk. 
  18.  *
  19.  */
  20.  
  21. #include "zsh.h"
  22.  
  23. #ifdef __hpux
  24. #include <ndir.h>
  25. #else
  26. #ifdef SYSV
  27. #define direct dirent
  28. #else
  29. #include <sys/dir.h>
  30. #endif
  31. #endif
  32. #include <sys/errno.h>
  33.  
  34. #define exists(X) (access(X,0) == 0 || readlink(X,NULL,0) == 0)
  35.  
  36. static int mode;                /* != 0 if we are parsing glob patterns */
  37. static int pathpos;            /* position in pathbuf */
  38. static int matchsz;            /* size of matchbuf */
  39. static int matchct;            /* number of matches found */
  40. static char pathbuf[MAXPATHLEN];    /* pathname buffer */
  41. static char **matchbuf;        /* array of matches */
  42. static char **matchptr;        /* &matchbuf[matchct] */
  43. static Comp exclude;            /* pattern to exclude */
  44.  
  45. /* max # of qualifiers */
  46.  
  47. #define QUALCT 16
  48.  
  49. static int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long));
  50. static long qualdata[QUALCT];
  51. static int qualsense[QUALCT];
  52. static int qualct;
  53. static int gf_nullglob,gf_markdirs,gf_noglobdots;
  54.  
  55. /* pathname component in filename patterns */
  56.  
  57. struct complist {
  58.     Complist next;
  59.     Comp comp;
  60.     int closure;    /* 1 if this is a (foo/)# */
  61.     };
  62. struct comp {
  63.     Comp left,right,next;
  64.     char *str;
  65.     int closure,last;
  66.     };
  67.  
  68. void glob(list,np) /**/
  69. Lklist list;Lknode *np;
  70. {
  71. Lknode node = prevnode(*np);
  72. Lknode next = nextnode(*np);
  73. int sl;            /* length of the pattern */
  74. char *ostr;        /* the pattern before the parser chops it up */
  75. Complist q;        /* pattern after parsing */
  76. char *str = getdata(*np);    /* the pattern */
  77.  
  78.     sl = strlen(str);
  79.     ostr = strdup(str);
  80.     uremnode(list,*np);
  81.     qualct = 0;
  82.     gf_nullglob = isset(NULLGLOB);
  83.     gf_markdirs = isset(MARKDIRS);
  84.     gf_noglobdots = unset(GLOBDOTS);
  85.     if (str[sl-1] == Outpar)    /* check for qualifiers */
  86.         {
  87.         char *s;
  88.         int sense = 0;
  89.         long data;
  90.         int (*func) DCLPROTO((struct stat *,long));
  91.  
  92.         for (s = str+sl-2; s != str; s--)
  93.             if (*s == Bar || *s == Outpar || *s == Inpar)
  94.                 break;
  95.         if (*s == Inpar)
  96.             {
  97.             *s++ = '\0';
  98.             func = NULL;
  99.             while (*s != Outpar)
  100.                 {
  101.                 func = NULL;
  102.                 if (idigit(*s))
  103.                     {
  104.                     func = qualflags;
  105.                     data = 0;
  106.                     while (idigit(*s))
  107.                         data = data*010+(*s++-'0');
  108.                     }
  109.                 else switch ((int)(unsigned char)(*s++))
  110.                     {
  111.                     case (int)(unsigned char)Hat: case '^': sense = 1-sense; break;
  112. #ifdef S_IFLNK
  113.                     case '@': func = qualmode; data = S_IFLNK; break;
  114. #endif
  115. #ifdef S_IFSOCK
  116.                     case '=': func = qualmode; data = S_IFSOCK; break;
  117. #endif
  118. #ifdef S_IFIFO
  119.                     case 'p': func = qualmode; data = S_IFIFO; break;
  120. #endif
  121.                     case '/': func = qualmode; data = S_IFDIR; break;
  122.                     case '.': func = qualmode; data = S_IFREG; break;
  123.                     case '%': func = qualisdev; break;
  124.                     case (int)(unsigned char)Star:  func = qualiscom; break;
  125.                     case 'R': func = qualflags; data = 0004; break;
  126.                     case 'W': func = qualflags; data = 0002; break;
  127.                     case 'X': func = qualflags; data = 0001; break;
  128.                     case 'r': func = qualflags; data = 0400; break;
  129.                     case 'w': func = qualflags; data = 0200; break;
  130.                     case 'x': func = qualflags; data = 0100; break;
  131.                     case 's': func = qualflags; data = 04000; break;
  132.                     case 'S': func = qualflags; data = 02000; break;
  133.                     case 'd': func = qualdev; data = qgetnum(&s); break;
  134.                     case 'l': func = qualnlink; data = qgetnum(&s); break;
  135.                     case 'U': func = qualuid; data = geteuid(); break;
  136.                     case 'G': func = qualgid; data = getegid(); break;
  137.                     case 'u': func = qualuid; data = qgetnum(&s); break;
  138.                     case 'g': func = qualgid; data = qgetnum(&s); break;
  139.                     case 'M': gf_markdirs = !sense; break;
  140.                     case 'N': gf_nullglob = !sense; break;
  141.                     case 'D': gf_noglobdots = sense; break;
  142.                     default: zerr("unknown file attribute",NULL,0); return;
  143.                     }
  144.                 if (func)
  145.                     {
  146.                     if (qualct == QUALCT-1)
  147.                         {
  148.                         zerr("too many qualifiers",NULL,0);
  149.                         return;
  150.                         }
  151.                     qualfuncs[qualct] = func;
  152.                     qualsense[qualct] = sense;
  153.                     qualdata[qualct] = data;
  154.                     qualct++;
  155.                     }
  156.                 if (errflag)
  157.                     return;
  158.                 }
  159.             }
  160.         }
  161.     else if ((str[sl-1] == '/') && !((str[sl-2] == Star)&&
  162.                 (str[sl-3] == Star)&&(str[sl-4] == Star)&&
  163.                 (str[sl-5]==Star)))        /* foo/ == foo(/) */
  164.         {
  165.         str[sl-1] = '\0';
  166.         qualfuncs[0] = qualmode;
  167.         qualdata[0] = S_IFDIR;
  168.         qualsense[0] = 0;
  169.         qualct = 1;
  170.         }
  171.     qualfuncs[qualct] = NULL;
  172.     if (*str == '/')    /* pattern has absolute path */
  173.         {
  174.         str++;
  175.         pathbuf[0] = '/';
  176.         pathbuf[pathpos = 1] = '\0';
  177.         }
  178.     else        /* pattern is relative to pwd */
  179.         pathbuf[pathpos = 0] = '\0';
  180.     q = parsepat(str);
  181.     if (!q || errflag)    /* if parsing failed */
  182.         {
  183.         if (isset(NOBADPATTERN))
  184.             {
  185.             insnode(list,node,ostr);
  186.             return;
  187.             }
  188.         errflag = 0;
  189.         zerr("bad pattern: %s",ostr,0);
  190.         return;
  191.         }
  192.     matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
  193.     matchct = 0;
  194.     scanner(q);        /* do the globbing */
  195.     if (matchct)
  196.         badcshglob |= 2;
  197.     else if (!gf_nullglob)
  198.         if (isset(CSHNULLGLOB)) {
  199.             badcshglob |= 1;
  200.         } else if (unset(NONOMATCH)) {
  201.             zerr("no matches found: %s",ostr,0);
  202.             free(matchbuf);
  203.             return;
  204.         } else {
  205.             *matchptr++ = strdup(ostr);
  206.             matchct = 1;
  207.         }
  208.     qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
  209.     matchptr = matchbuf;
  210.     while (matchct--)            /* insert matches in the arg list */
  211.         insnode(list,node,*matchptr++);
  212.     free(matchbuf);
  213.     *np = (next) ? prevnode(next) : lastnode(list);
  214. }
  215.  
  216. /* get number after qualifier */
  217.  
  218. long qgetnum(s) /**/
  219. char **s;
  220. {
  221. long v = 0;
  222.  
  223.     if (!idigit(**s))
  224.         {
  225.         zerr("number expected",NULL,0);
  226.         return 0;
  227.         }
  228.     while (idigit(**s))
  229.         v = v*10+*(*s)++-'0';
  230.     return v;
  231. }
  232.  
  233. int notstrcmp(a,b) /**/
  234. char **a;char **b;
  235. {
  236. char *c = *b,*d = *a;
  237. int x1,x2;
  238.  
  239.     for (; *c == *d && *c; c++,d++);
  240.     x1 = atoi(c); x2 = atoi(d);
  241.     if (x1==x2 || unset(NUMERICGLOBSORT))
  242.         return ((int) (unsigned char) *c-(int) (unsigned char) *d);
  243.     return x1-x2;
  244. }
  245.  
  246. int forstrcmp(a,b) /**/
  247. char **a;char **b;
  248. {
  249. char *c = *b,*d = *a;
  250.  
  251.     for (; *c == *d && *c; c++,d++);
  252.     return ((int) (unsigned char) *d-(int) (unsigned char) *c);
  253. }
  254.  
  255. /* add a match to the list */
  256.  
  257. void insert(s) /**/
  258. char *s;
  259. {
  260. struct stat buf;
  261. int statted = 0;
  262.  
  263.     if (exclude && domatch(s,exclude,gf_noglobdots)) return;
  264.     if (gf_markdirs && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) {
  265.         char *t;
  266.         int ll = strlen(s);
  267.  
  268.         t = ncalloc(ll+2);
  269.         strcpy(t,s);
  270.         t[ll] = '/';
  271.         t[ll+1] = '\0';
  272.         s = t;
  273.         statted = 1;
  274.     }
  275.     if (qualct)    { /* do the (X) (^X) stuff */
  276.         int (**fptr)DCLPROTO((struct stat *,long)) = qualfuncs;
  277.         int *sptr = qualsense;
  278.         long *lptr = qualdata;
  279.         struct stat buf;
  280.  
  281.         if (statted || lstat(s,&buf) >= 0)
  282.             while (*fptr) if (!(!!((*fptr++)(&buf,*lptr++)) ^ *sptr++)) return;
  283.     }
  284.     *matchptr++ = s;
  285.     if (++matchct == matchsz) {
  286.         matchbuf = (char **) realloc((char *) matchbuf,
  287.             sizeof(char **)*(matchsz *= 2));
  288.         matchptr = matchbuf+matchct;
  289.     }
  290. }
  291.  
  292. /* check to see if str is eligible for filename generation */
  293.  
  294. int haswilds(str) /**/
  295. char *str;
  296. {
  297.     if ((*str == Inbrack || *str == Outbrack) && !str[1]) return 0;
  298.     if (str[0] == '%') return 0;
  299.     for (; *str; str++)
  300.         if (*str == Pound || *str == Hat || *str == Star ||
  301.                 *str == Bar || *str == Inbrack || *str == Inang ||
  302.                 *str == Quest) return 1;
  303.     return 0;
  304. }
  305.  
  306. /* check to see if str is eligible for brace expansion */
  307.  
  308. int hasbraces(str) /**/
  309. char *str;
  310. {
  311. int mb,bc,cmct1,cmct2;
  312. char *lbr = NULL;
  313.  
  314.     if (str[0] == Inbrace && str[1] == Outbrace)
  315.         return 0;
  316.     if (isset(BRACECCL)) {
  317.         for (mb = bc = 0; *str; ++str)
  318.             if (*str == Inbrace) {
  319.                 if (++bc > mb)
  320.                     mb = bc;
  321.             }
  322.             else if (*str == Outbrace)
  323.                 if (--bc < 0)
  324.                     return(0);
  325.         return(mb && bc == 0);
  326.     }
  327.     for (mb = bc = cmct1 = cmct2 = 0; *str; str++)
  328.         {
  329.         if (*str == Inbrace)
  330.             {
  331.             if (!bc)
  332.                 lbr = str;
  333.             bc++;
  334.             if (str[4] == Outbrace && str[2] == '-') /* {a-z} */
  335.                 {
  336.                 cmct1++;
  337.                 if (bc == 1)
  338.                     cmct2++;
  339.                 }
  340.             }
  341.         else if (*str == Outbrace)
  342.             {
  343.             bc--;
  344.             if (!bc)
  345.                 {
  346.                 if (!cmct2)
  347.                     {
  348.                     *lbr = '{';
  349.                     *str = '}';
  350.                     }
  351.                 cmct2 = 0;
  352.                 }
  353.             }
  354.         else if (*str == Comma && bc)
  355.             {
  356.             cmct1++;
  357.             if (bc == 1)
  358.                 cmct2++;
  359.             }
  360.         if (bc > mb)
  361.             mb = bc;
  362.         if (bc < 0)
  363.             return 0;
  364.         }
  365.     return (mb && bc == 0 && cmct1);
  366. }
  367.  
  368. /* expand stuff like >>*.c */
  369.  
  370. int xpandredir(fn,tab) /**/
  371. struct redir *fn;Lklist tab;
  372. {
  373. Lklist fake;
  374. char *nam;
  375. struct redir *ff;
  376. int ret = 0;
  377.  
  378.     fake = newlist();
  379.     addnode(fake,fn->name);
  380.     prefork(fake);
  381.     if (!errflag)
  382.         postfork(fake,1);
  383.     if (errflag) return 0;
  384.     if (full(fake) && !nextnode(firstnode(fake))) {
  385.         fn->name = peekfirst(fake);
  386.         untokenize(fn->name);
  387.     } else
  388.         while (nam = ugetnode(fake)) {
  389.             ff = alloc(sizeof *ff);
  390.             *ff = *fn;
  391.             ff->name = nam;
  392.             addnode(tab,ff);
  393.             ret = 1;
  394.         }
  395.     return ret;
  396. }
  397.  
  398. /* concatenate s1 and s2 in dynamically allocated buffer */
  399.  
  400. char *dyncat(s1,s2) /**/
  401. char *s1;char *s2;
  402. {
  403. char *ptr;
  404.  
  405.     ptr = ncalloc(strlen(s1)+strlen(s2)+1);
  406.     strcpy(ptr,s1);
  407.     strcat(ptr,s2);
  408.     return ptr;
  409. }
  410.  
  411. /* concatenate s1, s2, and s3 in dynamically allocated buffer */
  412.  
  413. char *tricat(s1,s2,s3) /**/
  414. char *s1;char *s2;char *s3;
  415. {
  416. char *ptr;
  417.  
  418.     ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1);
  419.     strcpy(ptr,s1);
  420.     strcat(ptr,s2);
  421.     strcat(ptr,s3);
  422.     return ptr;
  423. }
  424.  
  425. /* brace expansion */
  426.  
  427. void xpandbraces(list,np) /**/
  428. Lklist list;Lknode *np;
  429. {
  430. Lknode node = (*np),last = prevnode(node);
  431. char *str = getdata(node),*str3 = str,*str2;
  432. int prev, bc, comma;
  433.  
  434.     for (; *str != Inbrace; str++);
  435.     for (str2 = str, bc = comma = 0; *str2; ++str2)
  436.         if (*str2 == Inbrace)
  437.             ++bc;
  438.         else if (*str2 == Outbrace) {
  439.             if (--bc == 0)
  440.                 break;
  441.         }
  442.         else if (bc == 1 && *str2 == Comma)
  443.             ++comma;
  444.     if (!comma && !bc && isset(BRACECCL)) {            /* {a-mnop} */
  445.         char    ccl[256], *p;
  446.         unsigned char c1,c2,lastch;
  447.  
  448.         uremnode(list,node);
  449.         memset(ccl, 0, sizeof(ccl) / sizeof(ccl[0]));
  450.         for (p = str + 1, lastch = 0; p < str2; ) {
  451.             if (itok(c1 = *p++))
  452.                 c1 = ztokens[c1 - (unsigned char)Pound];
  453.             if (itok(c2 = *p))
  454.                 c2 = ztokens[c2 - (unsigned char)Pound];
  455.             if (c1 == '-' && lastch && p < str2 && lastch <= c2) {
  456.                 while (lastch < c2)
  457.                     ccl[lastch++] = 1;
  458.                 lastch = 0;
  459.             }
  460.             else
  461.                 ccl[lastch = c1] = 1;
  462.         }
  463.         strcpy(str + 1, str2 + 1);
  464.         for (p = ccl+255; p-- > ccl; )
  465.             if (*p) {
  466.                 *str = p - ccl;
  467.                 insnode(list, last, strdup(str3));
  468.             }
  469.         *np = nextnode(last);
  470.         return;
  471.     }
  472.      if (str[2] == '-' && str[4] == Outbrace)     /* {a-z} */
  473.         {
  474.         char c1,c2;
  475.  
  476.         uremnode(list,node);
  477.         chuck(str);
  478.         c1 = *str;
  479.         chuck(str);
  480.         chuck(str);
  481.         c2 = *str;
  482.         chuck(str);
  483.         if (itok(c1))
  484.             c1 = ztokens[c1-Pound];
  485.         if (itok(c2))
  486.             c2 = ztokens[c2-Pound];
  487.         if (c1 < c2)
  488.             for (; c2 >= c1; c2--)    /* {a-z} */
  489.                 {
  490.                 *str = c2;
  491.                 insnode(list,last,strdup(str3));
  492.                 }
  493.         else
  494.             for (; c2 <= c1; c2++)    /* {z-a} */
  495.                 {
  496.                 *str = c2;
  497.                 insnode(list,last,strdup(str3));
  498.                 }
  499.         *np = nextnode(last);
  500.         return;
  501.         }
  502.     prev = str-str3;
  503.     str2 = getparen(str++);
  504.     if (!str2)
  505.         {
  506.         zerr("how did you get this error?",NULL,0);
  507.         return;
  508.         }
  509.     uremnode(list,node);
  510.     node = last;
  511.     for(;;)
  512.         {
  513.         char *zz,*str4;
  514.         int cnt;
  515.         
  516.         for (str4 = str, cnt = 0; cnt || *str != Comma && *str !=
  517.                 Outbrace; str++)
  518.             if (*str == Inbrace)
  519.                 cnt++;
  520.             else if (*str == Outbrace)
  521.                 cnt--;
  522.             else if (!*str)
  523.                 exit(10);
  524.         zz = zalloc(prev+(str-str4)+strlen(str2)+1);
  525.         ztrncpy(zz,str3,prev);
  526.         strncat(zz,str4,str-str4);
  527.         strcat(zz,str2);
  528.         insnode(list,node,zz);
  529.         incnode(node);
  530.         if (*str != Outbrace)
  531.             str++;
  532.         else
  533.             break;
  534.         }
  535.     *np = nextnode(last);
  536. }
  537.  
  538. /* get closing paren, given pointer to opening paren */
  539.  
  540. char *getparen(str) /**/
  541. char *str;
  542. {
  543. int cnt = 1;
  544. char typein = *str++,typeout = typein+1;
  545.  
  546.     for (; *str && cnt; str++)
  547.         if (*str == typein)
  548.             cnt++;
  549.         else if (*str == typeout)
  550.             cnt--;
  551.     if (!str && cnt)
  552.         return NULL;
  553.     return str;
  554. }
  555.  
  556. /* check to see if a matches b (b is not a filename pattern) */
  557.  
  558. int matchpat(a,b) /**/
  559. char *a;char *b;
  560. {
  561. Comp c;
  562. int val,len;
  563. char *b2;
  564.  
  565.     remnulargs(b);
  566.     len = strlen(b);
  567.     b2 = alloc(len+3);
  568.     strcpy(b2+1,b);
  569.     b2[0] = Inpar;
  570.     b2[len+1] = Outpar;
  571.     b2[len+2] = '\0';
  572.     c = parsereg(b2);
  573.     if (!c)
  574.         {
  575.         zerr("bad pattern: %s",b,0);
  576.         return 0;
  577.         }
  578.     val = domatch(a,c,0);
  579.     return val;
  580. }
  581.  
  582. /* do the ${foo%%bar}, ${foo#bar} stuff */
  583. /* please do not laugh at this code. */
  584.  
  585. void getmatch(sp,pat,dd) /**/
  586. char **sp;char *pat;int dd;
  587. {
  588. Comp c;
  589. char *t,*lng = NULL,cc,*s = *sp;
  590.  
  591.     remnulargs(pat);
  592.     c = parsereg(pat);
  593.     if (!c)
  594.         {
  595.         zerr("bad pattern: %s",pat,0);
  596.         return;
  597.         }
  598.     if (!(dd & 2))
  599.         {
  600.         for (t = s; t==s || t[-1]; t++)
  601.             {
  602.             cc = *t;
  603.             *t = '\0';
  604.             if (domatch(s,c,0))
  605.                 {
  606.                 if (!(dd & 1))
  607.                     {
  608.                     *t = cc;
  609.                     t = strdup(t);
  610.                     *sp = t;
  611.                     return;
  612.                     }
  613.                 lng = t;
  614.                 }
  615.             *t = cc;
  616.             }
  617.         if (lng)
  618.             {
  619.             t = strdup(lng);
  620.             *sp = t;
  621.             return;
  622.             }
  623.         }
  624.     else
  625.         {
  626.         for (t = s+strlen(s); t >= s; t--)
  627.             {
  628.             if (domatch(t,c,0))
  629.                 {
  630.                 if (!(dd & 1))
  631.                     {
  632.                     cc = *t;
  633.                     *t = '\0';
  634.                     *sp = strdup(*sp);
  635.                     *t = cc;
  636.                     return;
  637.                     }
  638.                 lng = t;
  639.                 }
  640.             }
  641.         if (lng)
  642.             {
  643.             cc = *lng;
  644.             *lng = '\0';
  645.             *sp = strdup(*sp);
  646.             *lng = cc;
  647.             return;
  648.             }
  649.         }
  650. }
  651.  
  652. /* add a component to pathbuf */
  653.  
  654. static int addpath(s)
  655. char *s;
  656. {
  657.     if (strlen(s)+pathpos >= MAXPATHLEN) return 0;
  658.     while (pathbuf[pathpos++] = *s++);
  659.     pathbuf[pathpos-1] = '/';
  660.     pathbuf[pathpos] = '\0';
  661.     return 1;
  662. }
  663.  
  664. char *getfullpath(s) /**/
  665. char *s;
  666. {
  667. static char buf[MAXPATHLEN];
  668.  
  669.     strcpy(buf,pathbuf);
  670.     strcat(buf,s);
  671.     return buf;
  672. }
  673.  
  674. /* do the globbing */
  675.  
  676. void scanner(q) /**/
  677. Complist q;
  678. {
  679. Comp c;
  680. int closure;
  681.  
  682.     if (closure = q->closure)    /* (foo/)# */
  683.         if (q->closure == 2)        /* (foo/)## */
  684.             q->closure = 1;
  685.         else
  686.             scanner(q->next);
  687.     if (c = q->comp)
  688.         {
  689.         if (!(c->next || c->left) && !haswilds(c->str))
  690.             if (q->next)
  691.                 {
  692.                 int oppos = pathpos;
  693.  
  694.                 if (errflag)
  695.                     return;
  696.                 if (q->closure && !strcmp(c->str,".")) return;
  697.                 if (!addpath(c->str)) return;
  698.                 if (!closure || exists(pathbuf))
  699.                     scanner((q->closure) ? q : q->next);
  700.                 pathbuf[pathpos = oppos] = '\0';
  701.                 }
  702.             else
  703.                 {
  704.                 char *s;
  705.  
  706.                 if (exists(s = getfullpath(c->str)))
  707.                     insert(strdup(s));
  708.                 }
  709.         else
  710.             {
  711.             char *fn;
  712.             int dirs = !!q->next;
  713.             struct direct *de;
  714.             DIR *lock = opendir((*pathbuf) ? pathbuf : ".");
  715.              
  716.             if (lock == NULL)
  717.                 return;
  718.             readdir(lock); readdir(lock);     /* skip . and .. */
  719.             while (de = readdir(lock))
  720.                 {
  721.                 if (errflag)
  722.                     break;
  723.                 fn = &de->d_name[0];
  724.                 if (domatch(fn,c,gf_noglobdots))
  725.                     {
  726.                     int oppos = pathpos;
  727.  
  728.                     if (dirs)
  729.                         {
  730.                         if (closure)
  731.                             {
  732.                             int type3;
  733.                             struct stat buf;
  734.  
  735.                              if (lstat(getfullpath(fn),&buf) == -1)
  736.                                 {
  737.                                 if (errno != ENOENT && errno != EINTR &&
  738.                                         errno != ENOTDIR)
  739.                                     {
  740.                                     zerr("%e: %s",fn,errno);
  741.                                     errflag = 0;
  742.                                     }
  743.                                 continue;
  744.                                 }
  745.                             type3 = buf.st_mode & S_IFMT;
  746.                             if (type3 != S_IFDIR)
  747.                                 continue;
  748.                             }
  749.                         if (addpath(fn))
  750.                             scanner((q->closure) ? q : q->next); /* scan next level */
  751.                         pathbuf[pathpos = oppos] = '\0';
  752.                         }
  753.                     else insert(dyncat(pathbuf,fn));
  754.                     }
  755.                 }
  756.             closedir(lock);
  757.             }
  758.         }
  759.     else
  760.         zerr("no idea how you got this error message.",NULL,0);
  761. }
  762.  
  763. /* do the [..(foo)..] business */
  764.  
  765. int minimatch(pat,str) /**/
  766. char **pat;char **str;
  767. {
  768. char *pt = *pat+1,*s = *str;
  769.     
  770.     for (; *pt != Outpar; s++,pt++)
  771.         if ((*pt != Quest || !*s) && *pt != *s)
  772.             {
  773.             *pat = getparen(*pat)-1;
  774.             return 0;
  775.             }
  776.     *str = s-1;
  777.     return 1;
  778. }
  779.  
  780. static char *pptr;
  781. static Comp tail = 0;
  782. static int first;
  783.  
  784. int domatch(str,c,fist) /**/
  785. char *str;Comp c;int fist;
  786. {
  787.     pptr = str;
  788.     first = fist;
  789.     return doesmatch(c);
  790. }
  791.  
  792. /* see if current pattern matches c */
  793.  
  794. int doesmatch(c) /**/
  795. Comp c;
  796. {
  797. char *pat = c->str;
  798.  
  799.     if (c->closure == 1) {
  800.         char *saves = pptr;
  801.  
  802.         if (first && *pptr == '.') return 0;
  803.         if (doesmatch(c->next)) return 1;
  804.         pptr = saves;
  805.         first = 0;
  806.     }
  807.     for(;;)
  808.         {
  809.         if (!pat || !*pat)
  810.             {
  811.             char *saves;
  812.             int savei;
  813.  
  814.             if (errflag)
  815.                 return 0;
  816.             saves = pptr;
  817.             savei = first;
  818.             if (c->left || c->right)
  819.                 if (!doesmatch(c->left))
  820.                     if (c->right)
  821.                         {
  822.                         pptr = saves;
  823.                         first = savei;
  824.                         if (!doesmatch(c->right))
  825.                             return 0;
  826.                         }
  827.                     else
  828.                         return 0;
  829.             if (c->closure)
  830.                 return doesmatch(c);
  831.             if (!c->next)
  832.                 return (!c->last || !*pptr);
  833.             return doesmatch(c->next);
  834.             }
  835.         if (first && *pptr == '.' && *pat != '.')
  836.             return 0;
  837.         if (*pat == Star)    /* final * is not expanded to ?#; returns success */
  838.             {
  839.             while (*pptr) pptr++;
  840.             return 1;
  841.             }
  842.         first = 0;
  843.         if (*pat == Quest && *pptr)
  844.             {
  845.             pptr++;
  846.             pat++;
  847.             continue;
  848.             }
  849.         if (*pat == Hat)
  850.             return 1-doesmatch(c->next);
  851.         if (*pat == Inbrack) {
  852.             if (!*pptr) break;
  853.             if (pat[1] == Hat || pat[1] == '^') {
  854.                 pat[1] = Hat;
  855.                 for (pat += 2; *pat != Outbrack && *pat; pat++)
  856.                     if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack) {
  857.                         if (pat[-1] <= *pptr && pat[1] >= *pptr)
  858.                             break;
  859.                     } else if (*pptr == *pat) break;
  860.                 if (!*pat) {
  861.                     zerr("something is very wrong.",NULL,0);
  862.                     return 0;
  863.                 }
  864.                 if (*pat != Outbrack)
  865.                     break;
  866.                 pat++;
  867.                 pptr++;
  868.                 continue;
  869.             } else {
  870.                 for (pat++; *pat != Outbrack && *pat; pat++)
  871.                     if (*pat == Inpar) {
  872.                         if (minimatch(&pat,&pptr))
  873.                             break;
  874.                     } else if (*pat == '-' && pat[-1] != Inbrack &&
  875.                             pat[1] != Outbrack) {
  876.                         if (pat[-1] <= *pptr && pat[1] >= *pptr)
  877.                             break;
  878.                     } else if (*pptr == *pat) break;
  879.                 if (!pat || !*pat) {
  880.                     zerr("oh dear.  that CAN'T be right.",NULL,0);
  881.                     return 0;
  882.                 }
  883.                 if (*pat == Outbrack)
  884.                     break;
  885.                 for (pptr++; *pat != Outbrack; pat++);
  886.                 pat++;
  887.                 continue;
  888.             }
  889.         }
  890.         if (*pat == Inang)
  891.             {
  892.             int t1,t2,t3;
  893.             char *ptr;
  894.  
  895.             if (*++pat == Outang)    /* handle <> case */
  896.                 {
  897.                 ( void ) zstrtol(pptr,&ptr,10);
  898.                 if (ptr == pptr)
  899.                     break;
  900.                 pptr = ptr;
  901.                 pat++;
  902.                 }
  903.             else
  904.                 {
  905.                 t1 = zstrtol(pptr,&ptr,10);
  906.                 if (ptr == pptr)
  907.                     break;
  908.                 pptr = ptr;
  909.                 t2 = zstrtol(pat,&ptr,10);
  910.                 if (*ptr != '-')
  911.                     exit(31);
  912.                 t3 = zstrtol(ptr+1,&pat,10);
  913.                 if (!t3)
  914.                     t3 = -1;
  915.                 if (*pat++ != Outang)
  916.                     exit(21);
  917.                 if (t1 < t2 || (t3 != -1 && t1 > t3))
  918.                     break;
  919.                 }
  920.             continue;
  921.             }
  922.         if (*pptr == *pat)
  923.             {
  924.             pptr++;
  925.             pat++;
  926.             continue;
  927.             }
  928.         break;
  929.         }
  930.     return 0;
  931. }
  932.  
  933. Complist parsepat(str) /**/
  934. char *str;
  935. {
  936. char *s;
  937.  
  938.     exclude = NULL;
  939.     if (isset(EXTENDEDGLOB)) {
  940.         s = str+strlen(str);
  941.         while (s-- > str) {
  942.             if (*s == Tilde && s[1]) {
  943.                 *s++ = '\0';
  944.                 exclude = parsereg(s);
  945.                 if (!exclude) return NULL;
  946.                 break;
  947.             }
  948.         }
  949.     }
  950.     mode = 0;
  951.     pptr = str;
  952.     return parsecomplist();
  953. }
  954.  
  955. Comp parsereg(str) /**/
  956. char *str;
  957. {
  958.     mode = 1;
  959.     pptr = str;
  960.     return parsecompsw();
  961. }
  962.  
  963. Complist parsecomplist() /**/
  964. {
  965. Comp c1;
  966. Complist p1;
  967.  
  968.     if (pptr[0] == Star && pptr[1] == Star &&
  969.             (pptr[2] == '/' ||
  970.             (pptr[2] == Star && pptr[3] == Star && pptr[4] == '/'))) {
  971.         pptr += 3;
  972.         if (pptr[-1] == Star) pptr += 2;
  973.         p1 = (Complist) alloc(sizeof *p1);
  974.         p1->next = parsecomplist();
  975.         p1->comp = (Comp) alloc(sizeof *p1->comp);
  976.         p1->comp->last = 1;
  977.         p1->comp->str = strdup("*");
  978.         *p1->comp->str = Star;
  979.         p1->closure = 1;
  980.         return p1;
  981.     }
  982.     if (*pptr == Inpar)
  983.         {
  984.         char *str;
  985.         int pars = 1;
  986.  
  987.         for (str = pptr+1; *str && pars; str++)
  988.             if (*str == Inpar)
  989.                 pars++;
  990.             else if (*str == Outpar)
  991.                 pars--;
  992.         if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
  993.             goto kludge;
  994.         pptr++;
  995.         if (!(c1 = parsecompsw()))
  996.             return NULL;
  997.         if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
  998.             {
  999.             int pdflag = 0;
  1000.  
  1001.             pptr += 3;
  1002.             if (*pptr == Pound)
  1003.                 {
  1004.                 pdflag = 1;
  1005.                 pptr++;
  1006.                 }
  1007.             p1 = (Complist) alloc(sizeof *p1);
  1008.             p1->comp = c1;
  1009.             p1->closure = 1+pdflag;
  1010.             p1->next = parsecomplist();
  1011.             return (p1->comp) ? p1 : NULL;
  1012.             }
  1013.         }
  1014.     else
  1015.         {
  1016. kludge:
  1017.         if (!(c1 = parsecompsw()))
  1018.             return NULL;
  1019.         if (*pptr == '/' || !*pptr)
  1020.             {
  1021.             int ef = *pptr == '/';
  1022.  
  1023.             p1 = (Complist) alloc(sizeof *p1);
  1024.             p1->comp = c1;
  1025.             p1->closure = 0;
  1026.             p1->next = (*pptr == '/') ? (pptr++,parsecomplist()) : NULL;
  1027.             return (ef && !p1->next) ? NULL : p1;
  1028.             }
  1029.         }
  1030.     errflag = 1;
  1031.     return NULL;
  1032. }
  1033.  
  1034. Comp parsecomp() /**/
  1035. {
  1036. Comp c = (Comp) alloc(sizeof *c),c1,c2;
  1037. char *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
  1038.  
  1039.     c->next = tail;
  1040.  
  1041.     while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
  1042.             *pptr != Outpar)
  1043.         {
  1044.         if (*pptr == Hat)
  1045.             {
  1046.             *s++ = Hat;
  1047.             *s++ = '\0';
  1048.             pptr++;
  1049.             if (!(c->next = parsecomp()))
  1050.                 return NULL;
  1051.             return c;
  1052.             }
  1053.         if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))
  1054.             {
  1055.             *s++ = '\0';
  1056.             pptr++;
  1057.             c1 = (Comp) alloc(sizeof *c1);
  1058.             *(c1->str = strdup("?")) = Quest;
  1059.             c1->closure = 1;
  1060.             if (!(c2 = parsecomp())) return NULL;
  1061.             c1->next = c2;
  1062.             c->next = c1;
  1063.             return c;
  1064.             }
  1065.         if (*pptr == Inpar)
  1066.             {
  1067.             int pars = 1;
  1068.             char *startp = pptr, *endp;
  1069.             Comp stail = tail;
  1070.             int dpnd = 0;
  1071.  
  1072.             for (pptr = pptr+1; *pptr && pars; pptr++)
  1073.                 if (*pptr == Inpar)
  1074.                     pars++;
  1075.                 else if (*pptr == Outpar)
  1076.                     pars--;
  1077.             if (pptr[-1] != Outpar)
  1078.                 {
  1079.                 errflag = 1;
  1080.                 return NULL;
  1081.                 }
  1082.             if (*pptr == Pound)
  1083.                 {
  1084.                 dpnd = 1;
  1085.                 pptr++;
  1086.                 if (*pptr == Pound)
  1087.                     {
  1088.                     pptr++;
  1089.                     dpnd = 2;
  1090.                     }
  1091.                 }
  1092.             if (!(c1 = parsecomp())) return NULL;
  1093.             tail = c1;
  1094.             endp = pptr;
  1095.             pptr = startp;
  1096.             pptr++;
  1097.             *s++ = '\0';
  1098.             c->next = (Comp) alloc(sizeof *c);
  1099.             c->next->left = parsecompsw();
  1100.             c->next->closure = dpnd;
  1101.             c->next->next = (Comp) alloc(sizeof *c);
  1102.             pptr = endp;
  1103.             tail = stail;
  1104.             return c;
  1105.             }
  1106.         if (*pptr == Pound)
  1107.             {
  1108.             *s = '\0';
  1109.             pptr++;
  1110.             if (!ls)
  1111.                 return NULL;
  1112.             if (*pptr == Pound) 
  1113.                 {
  1114.                 pptr++;
  1115.                 c->next = c1 = (Comp) alloc(sizeof *c);
  1116.                 c1->str = strdup(ls);
  1117.                 }
  1118.             else
  1119.                 c1 = c;
  1120.             c1->next = c2 = (Comp) alloc(sizeof *c);
  1121.             c2->str = strdup(ls);
  1122.             c2->closure = 1;
  1123.             c2->next = parsecomp();
  1124.             if (!c2->next)
  1125.                 return NULL;
  1126.             *ls++ = '\0';
  1127.             return c;
  1128.             }
  1129.         ls = s;
  1130.         if (*pptr == Inang)
  1131.             {
  1132.             int dshct;
  1133.  
  1134.             dshct = (pptr[1] == Outang);
  1135.             *s++ = *pptr++;
  1136.             while (*pptr && (*s++ = *pptr++) != Outang)
  1137.                 if (s[-1] == '-')
  1138.                     dshct++;
  1139.                 else if (!idigit(s[-1]))
  1140.                     break;
  1141.             if (s[-1] != Outang || dshct != 1)
  1142.                 return NULL;
  1143.             }
  1144.         else if (*pptr == Inbrack)
  1145.             {
  1146.             while (*pptr && (*s++ = *pptr++) != Outbrack);
  1147.             if (s[-1] != Outbrack)
  1148.                 return NULL;
  1149.             }
  1150.         else if (itok(*pptr) && *pptr != Star && *pptr != Quest)
  1151.             *s++ = ztokens[*pptr++-Pound];
  1152.         else
  1153.             *s++ = *pptr++;
  1154.         }
  1155.     if (*pptr == '/' || !*pptr)
  1156.         c->last = 1;
  1157.     *s++ = '\0';
  1158.     return c;
  1159. }
  1160.  
  1161. Comp parsecompsw() /**/
  1162. {
  1163. Comp c1,c2,c3;
  1164.  
  1165.     c1 = parsecomp();
  1166.     if (!c1)
  1167.         return NULL;
  1168.     if (*pptr == Bar)
  1169.         {
  1170.         c2 = (Comp) alloc(sizeof *c2);
  1171.         pptr++;
  1172.         c3 = parsecompsw();
  1173.         if (!c3)
  1174.             return NULL;
  1175.         c2->str = strdup("");
  1176.         c2->left = c1;
  1177.         c2->right = c3;
  1178.         return c2;
  1179.         }
  1180.     return c1;
  1181. }
  1182.  
  1183. /* tokenize and see if ss matches tt */
  1184.  
  1185. int patmatch(ss,tt) /**/
  1186. char *ss;char *tt;
  1187. {
  1188. char *s = ss,*t;
  1189.  
  1190.     for (; *s; s++)
  1191.         if (*s == '\\')
  1192.             chuck(s);
  1193.         else
  1194.             for (t = ztokens; *t; t++)
  1195.                 if (*t == *s)
  1196.                     {
  1197.                     *s = (t-ztokens)+Pound;
  1198.                     break;
  1199.                     }
  1200.     return matchpat(ss,tt);
  1201. }
  1202.  
  1203. /* remove unnecessary Nulargs */
  1204.  
  1205. void remnulargs(s) /**/
  1206. char *s;
  1207. {
  1208. int nl = *s;
  1209. char *t = s;
  1210.  
  1211.     while (*s)
  1212.         if (*s == Nularg)
  1213.             chuck(s);
  1214.         else
  1215.             s++;
  1216.     if (!*t && nl)
  1217.         {
  1218.         t[0] = Nularg;
  1219.         t[1] = '\0';
  1220.         }
  1221. }
  1222.  
  1223. /* qualifier functions */
  1224.  
  1225. int qualdev(buf,dv) /**/
  1226. struct stat *buf;long dv;
  1227. {
  1228.     return buf->st_dev == dv;
  1229. }
  1230.  
  1231. int qualnlink(buf,ct) /**/
  1232. struct stat *buf;long ct;
  1233. {
  1234.     return buf->st_nlink == ct;
  1235. }
  1236.  
  1237. int qualuid(buf,uid) /**/
  1238. struct stat *buf;long uid;
  1239. {
  1240.     return buf->st_uid == uid;
  1241. }
  1242.  
  1243. int qualgid(buf,gid) /**/
  1244. struct stat *buf;long gid;
  1245. {
  1246.     return buf->st_gid == gid;
  1247. }
  1248.  
  1249. int qualisdev(buf,junk) /**/
  1250. struct stat *buf;long junk;
  1251. {
  1252.     junk = buf->st_mode & S_IFMT;
  1253.     return junk == S_IFBLK || junk == S_IFCHR;
  1254. }
  1255.  
  1256. int qualmode(buf,mod) /**/
  1257. struct stat *buf;long mod;
  1258. {
  1259.     return (buf->st_mode & S_IFMT) == mod;
  1260. }
  1261.  
  1262. int qualflags(buf,mod) /**/
  1263. struct stat *buf;long mod;
  1264. {
  1265.     return buf->st_mode & mod;
  1266. }
  1267.  
  1268. int qualiscom(buf,mod) /**/
  1269. struct stat *buf;long mod;
  1270. {
  1271.     return (buf->st_mode & (S_IFMT|S_IEXEC)) == (S_IFREG|S_IEXEC);
  1272. }
  1273.  
  1274.