glob.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       glob.c (4540B)
       ---
            1 #include "rc.h"
            2 #include "exec.h"
            3 #include "fns.h"
            4 char *globname;
            5 struct word *globv;
            6 /*
            7  * delete all the GLOB marks from s, in place
            8  */
            9 
           10 void
           11 deglob(char *s)
           12 {
           13         char *t = s;
           14         do{
           15                 if(*t==GLOB)
           16                         t++;
           17                 *s++=*t;
           18         }while(*t++);
           19 }
           20 
           21 int
           22 globcmp(const void *s, const void *t)
           23 {
           24         return strcmp(*(char**)s, *(char**)t);
           25 }
           26 
           27 void
           28 globsort(word *left, word *right)
           29 {
           30         char **list;
           31         word *a;
           32         int n = 0;
           33         for(a = left;a!=right;a = a->next) n++;
           34         list = (char **)emalloc(n*sizeof(char *));
           35         for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
           36         qsort((void *)list, n, sizeof(void *), globcmp);
           37         for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
           38         efree((char *)list);
           39 }
           40 /*
           41  * Push names prefixed by globname and suffixed by a match of p onto the astack.
           42  * namep points to the end of the prefix in globname.
           43  */
           44 
           45 void
           46 globdir(char *p, char *namep)
           47 {
           48         char *t, *newp;
           49         int f;
           50         /* scan the pattern looking for a component with a metacharacter in it */
           51         if(*p=='\0'){
           52                 globv = newword(globname, globv);
           53                 return;
           54         }
           55         t = namep;
           56         newp = p;
           57         while(*newp){
           58                 if(*newp==GLOB)
           59                         break;
           60                 *t=*newp++;
           61                 if(*t++=='/'){
           62                         namep = t;
           63                         p = newp;
           64                 }
           65         }
           66         /* If we ran out of pattern, append the name if accessible */
           67         if(*newp=='\0'){
           68                 *t='\0';
           69                 if(access(globname, 0)==0)
           70                         globv = newword(globname, globv);
           71                 return;
           72         }
           73         /* read the directory and recur for any entry that matches */
           74         *namep='\0';
           75         if((f = Opendir(globname[0]?globname:"."))<0) return;
           76         while(*newp!='/' && *newp!='\0') newp++;
           77         while(Readdir(f, namep, *newp=='/')){
           78                 if(matchfn(namep, p)){
           79                         for(t = namep;*t;t++);
           80                         globdir(newp, t);
           81                 }
           82         }
           83         Closedir(f);
           84 }
           85 /*
           86  * Push all file names matched by p on the current thread's stack.
           87  * If there are no matches, the list consists of p.
           88  */
           89 
           90 void
           91 glob(char *p)
           92 {
           93         word *svglobv = globv;
           94         int globlen = Globsize(p);
           95         if(!globlen){
           96                 deglob(p);
           97                 globv = newword(p, globv);
           98                 return;
           99         }
          100         globname = emalloc(globlen);
          101         globname[0]='\0';
          102         globdir(p, globname);
          103         efree(globname);
          104         if(svglobv==globv){
          105                 deglob(p);
          106                 globv = newword(p, globv);
          107         }
          108         else
          109                 globsort(globv, svglobv);
          110 }
          111 /*
          112  * Do p and q point at equal utf codes
          113  */
          114 
          115 int
          116 equtf(char *p, char *q)
          117 {
          118         if(*p!=*q)
          119                 return 0;
          120         if(twobyte(*p)) return p[1]==q[1];
          121         if(threebyte(*p)){
          122                 if(p[1]!=q[1])
          123                         return 0;
          124                 if(p[1]=='\0')
          125                         return 1;        /* broken code at end of string! */
          126                 return p[2]==q[2];
          127         }
          128         return 1;
          129 }
          130 /*
          131  * Return a pointer to the next utf code in the string,
          132  * not jumping past nuls in broken utf codes!
          133  */
          134 
          135 char*
          136 nextutf(char *p)
          137 {
          138         if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
          139         if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
          140         return p+1;
          141 }
          142 /*
          143  * Convert the utf code at *p to a unicode value
          144  */
          145 
          146 int
          147 unicode(char *p)
          148 {
          149         int u=*p&0xff;
          150         if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
          151         if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
          152         return u;
          153 }
          154 /*
          155  * Does the string s match the pattern p
          156  * . and .. are only matched by patterns starting with .
          157  * * matches any sequence of characters
          158  * ? matches any single character
          159  * [...] matches the enclosed list of characters
          160  */
          161 
          162 int
          163 matchfn(char *s, char *p)
          164 {
          165         if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
          166                 return 0;
          167         return match(s, p, '/');
          168 }
          169 
          170 int
          171 match(char *s, char *p, int stop)
          172 {
          173         int compl, hit, lo, hi, t, c;
          174         for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
          175                 if(*p!=GLOB){
          176                         if(!equtf(p, s)) return 0;
          177                 }
          178                 else switch(*++p){
          179                 case GLOB:
          180                         if(*s!=GLOB)
          181                                 return 0;
          182                         break;
          183                 case '*':
          184                         for(;;){
          185                                 if(match(s, nextutf(p), stop)) return 1;
          186                                 if(!*s)
          187                                         break;
          188                                 s = nextutf(s);
          189                         }
          190                         return 0;
          191                 case '?':
          192                         if(*s=='\0')
          193                                 return 0;
          194                         break;
          195                 case '[':
          196                         if(*s=='\0')
          197                                 return 0;
          198                         c = unicode(s);
          199                         p++;
          200                         compl=*p=='~';
          201                         if(compl)
          202                                 p++;
          203                         hit = 0;
          204                         while(*p!=']'){
          205                                 if(*p=='\0')
          206                                         return 0;                /* syntax error */
          207                                 lo = unicode(p);
          208                                 p = nextutf(p);
          209                                 if(*p!='-')
          210                                         hi = lo;
          211                                 else{
          212                                         p++;
          213                                         if(*p=='\0')
          214                                                 return 0;        /* syntax error */
          215                                         hi = unicode(p);
          216                                         p = nextutf(p);
          217                                         if(hi<lo){ t = lo; lo = hi; hi = t; }
          218                                 }
          219                                 if(lo<=c && c<=hi)
          220                                         hit = 1;
          221                         }
          222                         if(compl)
          223                                 hit=!hit;
          224                         if(!hit)
          225                                 return 0;
          226                         break;
          227                 }
          228         }
          229         return *s=='\0';
          230 }
          231 
          232 void
          233 globlist1(word *gl)
          234 {
          235         if(gl){
          236                 globlist1(gl->next);
          237                 glob(gl->word);
          238         }
          239 }
          240 
          241 void
          242 globlist(void)
          243 {
          244         word *a;
          245         globv = 0;
          246         globlist1(runq->argv->words);
          247         poplist();
          248         pushlist();
          249         if(globv){
          250                 for(a = globv;a->next;a = a->next);
          251                 a->next = runq->argv->words;
          252                 runq->argv->words = globv;
          253         }
          254 }