/* * Read entries from dir, one at a time. * edir points at the nul at the end of dir. * The buffer pointed to by dir is guaranteed to be long enough to hold * any matching file name. */ void matchdir(char *dir, char *edir, char *pattern){ DIR *fd; struct dirent *dp; struct stat st; int n; char *npattern, *s, *t; *edir='\0'; fd=opendir(*dir?dir:"."); if(fd==0) return; while((dp=readdir(fd))!=0){ if(npattern=match(dp->d_name, pattern)){ t=edir; if(edir!=dir && edir[-1]!='/') *t++='/'; for(s=dp->d_name;*s;s++,t++) *t=*s; *t='\0'; if(*npattern=='\0'){ arg(chargp); for(s=dir;*s;s++) argchr(*s); argchr('\0'); } else if(stat(dir, &st)==0 && S_ISDIR(st.st_mode)) matchdir(dir, t, npattern); } } closedir(fd); } int globcmp(const void *a, const void *b){ return strcmp(*(char **)a, *(char **)b); } #define NAMELEN 256 /* file name components can be no longer than this */ void glob(void){ char *s, *t, *buf, *pattern, **p; int mark; int nbuf; mark=argp-args-1; pattern=strdup(argp[-1]); nbuf=strlen(pattern+1); for(s=pattern;*s;s++) if(*s==GLOB && *++s=='*') nbuf+=NAMELEN; buf=malloc(nbuf); if(buf==0) nomem(); if(pattern[0]=='/'){ buf[0]='/'; matchdir(buf, buf+1, pattern+1); } else matchdir(buf, buf, pattern); if(argp==args+mark+1){ /* no match, just remove GLOB markers */ for(s=t=args[mark];*t;s++,t++){ if(*s==GLOB) s++; *t=*s; } } else{ /* discard pattern, sort matches */ for(p=args+mark+1;p!=argp;p++) p[-1]=p[0]; --argp; p=args+mark; qsort(p, argp-p, sizeof(char *), globcmp); } free(pattern); free(buf); }
/* * Read entries from dir, one at a time. * edir points at the nul at the end of dir. * The buffer pointed to by dir is guaranteed to be long enough to hold * any matching file name. */ void matchdir(char *dir, char *edir, char *pattern){ DIR *fd; struct dirent *dp; struct stat st; int n; char *npattern, *s, *t; *edir='\0'; fd=opendir(*dir?dir:"."); if(fd==0) return; while((dp=readdir(fd))!=0){ if(npattern=match(dp->d_name, pattern)){ t=edir; if(edir!=dir && edir[-1]!='/') *t++='/'; for(s=dp->d_name;*s;s++,t++) *t=*s; *t='\0'; if(*npattern=='\0'){ arg(chargp); for(s=dir;*s;s++) argchr(*s); argchr('\0'); } else if(stat(dir, &st)==0 && S_ISDIR(st.st_mode)) matchdir(dir, t, npattern); } } closedir(fd); }
static void expand(const char *as) { const char *cs; const char *oldcs; char *sgpathp; struct stat stb; sgpathp = gpathp; cs = as; if (*cs == '~' && gpathp == gpath) { addpath('~'); for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) addpath(*cs++); if (!*cs || *cs == '/') { if (gpathp != gpath + 1) { *gpathp = 0; if (gethdir(gpath + 1)) globerr = "Unknown user name after ~"; /* * Was: strcpy(gpath, gpath + 1); * but that's WRONG */ memmove(gpath, gpath+1, strlen(gpath+1)+1); } else { (void) strcpy(gpath, home); } gpathp = strend(gpath); } } while (!any(*cs, globchars)) { if (*cs == 0) { if (!globbed) Gcat(gpath, ""); else if (stat(gpath, &stb) >= 0) { Gcat(gpath, ""); globcnt++; } goto endit; } addpath(*cs++); } oldcs = cs; while (cs > as && *cs != '/') cs--, gpathp--; if (*cs == '/') cs++, gpathp++; *gpathp = 0; if (*oldcs == '{') { (void) execbrc(cs, ((char *)0)); return; } matchdir(cs); endit: gpathp = sgpathp; *gpathp = 0; }
static void expand(char *as) { char *cs; char *sgpathp, *oldcs; struct stat stb; sgpathp = gpathp; cs = as; if (*cs == '~' && gpathp == gpath) { addpath('~'); for (cs++; letter(*cs) || digit(*cs) || *cs == '-';) addpath(*cs++); if (!*cs || *cs == '/') { if (gpathp != gpath + 1) { *gpathp = 0; if (gethdir(gpath + 1)) { (void)sprintf(errstring = errbuf, "Unknown user name: %s after '~'", gpath+1); globerr = IPS; } strcpy(gpath, gpath + 1); } else strcpy(gpath, home); gpathp = strend(gpath); } } while (!any(*cs, globchars) && globerr == 0) { if (*cs == 0) { if (!globbed) Gcat(gpath, ""); else if (stat(gpath, &stb) >= 0) { Gcat(gpath, ""); globcnt++; } goto endit; } addpath(*cs++); } oldcs = cs; while (cs > as && *cs != '/') cs--, gpathp--; if (*cs == '/') cs++, gpathp++; *gpathp = 0; if (*oldcs == '{') { (void)execbrc(cs, ((char *)0)); return; } matchdir(cs); endit: gpathp = sgpathp; *gpathp = 0; }
static int doglob(struct dirbuf *np, const char *pattern) { struct dirbuf name = *np; struct stat stb; const char *s; /* Loop over all pattern components */ while (*pattern) { /* Skip slashes, but make sure the named file * exists and is a directory. * This takes care of "foobar/" patterns */ if (*pattern == '/' || !strncmp(pattern, "./", 2)) { if (stat(dirbuf_as_path(&name), &stb) < 0 || !S_ISDIR(stb.st_mode)) return 0; pattern++; continue; } /* Try to match a component of the path name */ for (s = pattern; *s && *s != '/'; s++) { /* Remainder has globbing chars */ if (strchr(GLOBCHARS, *s)) return matchdir(&name, pattern); } /* This path component didn't contain a special * character, so no matching required. * Make sure though that the file exists. */ if (!dirbuf_addslash(&name) || !dirbuf_appends(&name, pattern, s - pattern) || access(dirbuf_as_path(&name), F_OK) < 0) return 0; pattern = s; } remember(dirbuf_as_path(&name)); return 1; }
/* NOTREACHED */ } if ( p == '\0' ) return FAIL; if ( p == '[' ) { char s = *string++; char reverse = '\0'; char first, last; char gotcha = '\0'; NEXTP; if ( p == '^' ) { reverse = '\1'; NEXTP; } if ( p == ']' ) { /* special case */ gotcha = (s==p); NEXTP; } while ( p != ']' && !gotcha ) { first = p; NEXTP; if ( p == '-' && pattern[1] != ']' ) { NEXTP; last = p; NEXTP; } else last = first; if ( first > last ) return ERROR; gotcha = (first <= s && s <= last ); } while ( p != ']' ) NEXTP; if ( reverse ? gotcha : !gotcha ) return FAIL; } else if ( p != *string ) return FAIL; else string++; } } if ( seenstar ) return SUCCES; if ( *string ) return FAIL; return SUCCES; } static char *main_path; /* ptr to scratchpad */ static int offset; /* no of leading char in main_path to ignore */ static char **namelist; /* name list buildup */ static int nnames; /* no of names found */ static int left; /* no of slots allocated but not used yet */ #define GLOBMAXSEG 50 /* max segments in pattern */ #define GLOBCHUNK 20 /* no of slots to allocate at a time */ #ifndef MAXNAMLEN #define MAXNAMLEN 256 #endif int #ifndef ANSI_PROTOTYPES glob_path( pattern, names ) char *pattern; char ***names; #else /* ANSI_PROTOTYPES */ glob_path(char *pattern, char ***names) #endif /* ANSI_PROTOTYPES */ { char mpath[ MAXPATHLEN + MAXNAMLEN + 1 ]; char *gpat[GLOBMAXSEG]; char *pat; if (pattern == 0) return -1; if ((pat = strdup(pattern)) == NULL) return -1; if (split_pat(pat, gpat) < 0) { (void)free(pat); return -1; } main_path = mpath; /* initalisation of static storage */ namelist = 0; nnames = left = 0; if ( *gpat && **gpat == '/' ) { main_path[0] = '/'; main_path[1] = '\0'; offset = 0; do_glob(main_path, gpat + 1); } else { main_path[0] = '.'; main_path[1] = '\0'; offset = 2; do_glob(main_path + 1, gpat); } (void)free(pat); if (namelist == 0) *names = (char **)malloc(sizeof(char *)); else *names = (char **)realloc(namelist, (nnames+1) * sizeof(char *)); if (*names == 0) return -1; (*names)[nnames] = 0; return nnames; } static int #ifndef ANSI_PROTOTYPES split_pat(pattern, table) char *pattern; char **table; #else /* ANSI_PROTOTYPES */ split_pat(char *pattern, char **table) #endif /* ANSI_PROTOTYPES */ { char *pp = pattern; int size = GLOBMAXSEG; if (*pattern == '/') { *table++ = "/"; --size; } do { while (*pp == '/') *pp++ = '\0'; if (*pp == '\0') break; if (--size < 0) return -1; *table++ = pp; while (*pp && *pp != '/') pp++; } while (*pp); *table = 0; return 0; } #define ISGLOB(x) ((x)=='*' || (x)=='?' || (x)=='[') static int #ifndef ANSI_PROTOTYPES no_glob(pat) char *pat; #else /* ANSI_PROTOTYPES */ no_glob(char *pat) #endif /* ANSI_PROTOTYPES */ { while (*pat && !ISGLOB(*pat)) pat++; return (*pat == '\0'); } static void #ifndef ANSI_PROTOTYPES do_glob(path_end, gpat) char *path_end; /* ptr to the end of main_path */ char **gpat; /* the rest of the pattern segments */ #else /* ANSI_PROTOTYPES */ do_glob(char *path_end, char **gpat) /* ptr to the end of main_path */ /* the rest of the pattern segments */ #endif /* ANSI_PROTOTYPES */ { char *saved_end = path_end; /* saved to be resored */ char *pat; /* current pattern segment */ struct stat st; /* to check if file exists */ #ifdef GLOBDEBUG ffprintf(STDDBG,"do_glob: path = '%s', pat = '%s'\n", main_path, *gpat ); #endif for ( ; (pat = *gpat) != 0 && no_glob(pat); gpat++ ) { #ifdef GLOBDEBUG ffprintf(STDDBG,"no_glob: path = '%s', pat = '%s'\n", main_path, pat ); #endif *path_end = '/'; (void)strcpy(path_end+1, pat); path_end += strlen(pat) + 1; if (GLOBSTAT(main_path, &st) != 0 ) { *saved_end = '\0'; return; } } if (pat) matchdir(path_end, gpat); else add_name(); *saved_end = '\0'; return; }
/* * If there are any Shell meta characters in the name, * expand into a list, after searching directory */ static void expsh(char *s) { char *cp; char *spathp, *oldcp; struct stat stb; spathp = pathp; cp = s; while (!any(*cp, shchars)) { if (*cp == '\0') { if (!expany || stat(path, &stb) >= 0) { if (which & E_TILDE) Cat(path, ""); else Cat(tilde, tpathp); } goto endit; } addpath(*cp++); } oldcp = cp; while (cp > s && *cp != '/') cp--, pathp--; if (*cp == '/') cp++, pathp++; *pathp = '\0'; if (*oldcp == '{') { execbrc(cp, NULL); return; } matchdir(cp); endit: pathp = spathp; *pathp = '\0'; }