/* Copyright (C) 1999 Beau Kuiper. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "ftpd.h" /* My attempt at creating a fnmatch funciton. This actually isn't bad for my first attempt, It seems to beat the library equivelent in the GNU library for everything but complicated expressions with many star tokens. */ /* this matches square bracket stuff */ int bracket_match(unsigned char letter, unsigned char *pattern) { unsigned fchar = 0; int partdone; int inverse = FALSE; /* see if the pattern is inversed */ if ((*pattern == '!') || (*pattern == '^')) { inverse = TRUE; pattern++; } while (*pattern != 0) { fchar = *pattern; partdone = FALSE; /* search for character range */ if (*(pattern + 1) != 0) if ((*(pattern + 1) == '-') && (*(pattern + 2) != 0)) { /* found an a-z thingy */ if ((letter >= fchar) && (letter <= *(pattern + 2))) return(!inverse); partdone = TRUE; pattern += 3; } if (!partdone) { /* match as a single character */ if (letter == *pattern) return(!inverse); pattern++; } } return(inverse); } int my_dofnmatch(char *pattern, char *string, char *endstr) { unsigned char *ppos, *spos; ppos = pattern; spos = string; while(*ppos != 0) { switch(*ppos) { /* this is simple too */ case '\\' : { ppos++; if ((*ppos == 0) || (*spos == 0)) return(-1); if (*spos != *ppos) return(-1); spos++; break; } /* this one is easy, one character */ case '?' : { if (*spos != 0) spos++; else return(-1); break; } /* this one is a hard one! */ case '[' : { char *start = ppos + 1; char oldchar; while((*ppos != 0) && (*ppos != ']')) ppos++; if (*ppos == 0) return(-1); if (*(ppos + 1) == ']') ppos++; oldchar = *(ppos + 1); *(ppos + 1) = 0; if (!bracket_match(*spos, start)) return(-1); *(ppos + 1) = oldchar; spos++; break; } /* this one sucks bigtime */ case '*' : { unsigned char *subpat; /* this is a fast track for common patterns like '*' */ /* since * matches any string, if everything has matched so far, and no more info pattern is after the star, then the match is successful */ if (*(ppos + 1) == 0) return(0); /* since there is data after the *, we have to greedyly (by starting at the end of the string) match the * */ subpat = endstr; while(subpat != spos) { subpat--; if (my_dofnmatch(ppos + 1, subpat, endstr) == 0) return(0); } /* if we cannot match the subpattern, then it is not going to work no matter what */ return(-1); } /* this is trivial */ default: { if (*spos != *ppos) return(-1); spos++; } } ppos++; } /* if we reach the end of the pattern, then we must also have nothing left in the string */ if (*spos == 0) return(0); return(-1); } int my_dofnmatchpath(unsigned char *pattern, unsigned char *string, unsigned char *endstr) { unsigned char *ppos, *spos; ppos = pattern; spos = string; while(*ppos != 0) { switch(*ppos) { /* this is simple too */ case '\\' : { ppos++; if ((*ppos == 0) || (*spos == 0)) return(-1); if (*spos != *ppos) return(-1); spos++; break; } /* this one is easy, one character */ case '?' : { if ((*spos != 0) && (*spos != '/')) spos++; else return(-1); break; } /* this one is a hard one! */ case '[' : { char *start = ppos + 1; char oldchar; if ((*spos == '/') || (*spos == 0)) return(-1); while((*ppos != 0) && (*ppos != ']')) ppos++; if (*ppos == 0) return(-1); if (*(ppos + 1) == ']') ppos++; oldchar = *(ppos + 1); *(ppos + 1) = 0; if (!bracket_match(*spos, start)) return(-1); *(ppos + 1) = oldchar; spos++; break; } /* this one sucks bigtime */ case '*' : { unsigned char *subpat; /* this is a fast track for common patterns like '*' disabled for path work since * means everything except / */ /* start from curret pos and attempt to find first /, since * cannot match any further than that! */ subpat = spos; while((*subpat != '/') && (subpat != endstr)) subpat++; /* since there is data after the *, we have to greedyly (by starting at the end of the string) match the * */ while(subpat != spos) { subpat--; if (my_dofnmatchpath(ppos + 1, subpat, endstr) == 0) return(0); } /* if we cannot match the subpattern, then it is not going to work no matter what */ return(-1); } /* this is trivial */ default: { if (*spos != *ppos) return(-1); spos++; } } ppos++; } /* if we reach the end of the pattern, then we must also have nothing left in the string */ if (*spos == 0) return(0); return(-1); } /* this is a wrapper for the recursive function about, giving the correct parameters. */ int my_fnmatch(char *pattern, char *string, int flags) { if (flags != FNM_PATHNAME) { if ((pattern[0] == '*') && (pattern[1] == 0)) return(0); return(my_dofnmatch(pattern, string, strchr(string, 0))); } else return(my_dofnmatchpath(pattern, string, strchr(string, 0))); } void qsortarray(char **l, int start, int end) { int left = start; int right = end; int pivot = left; char *temp; if (left == right) return; while(left != right) { if (strcmp(l[left], l[right]) > 0) { /* swap left and right */ temp = l[left]; l[left] = l[right]; l[right] = temp; if (pivot == left) { pivot = right; left++; } else { pivot = left; right--; } } else { if (pivot == left) right--; else left++; } } if (pivot > start) qsortarray(l, start, pivot - 1); if (pivot < end) qsortarray(l, pivot + 1, end); } MYGLOBDATA *myglob (char *dir, char *pattern, int allfiles, int sortforward) { MYGLOBDATA *g = NULL; int error = 0; DIR *globdir = NULL; int count; struct dirent *filedat; error = chdir(dir); if (!error) error = ((globdir = opendir(".")) == NULL); if (!error) { g = mallocwrapper(sizeof(MYGLOBDATA)); g->namecount = 0; g->name = NULL; g->stat_buf = NULL; g->blocks = 0; while((filedat = readdir(globdir)) != NULL) { if ((filedat->d_name[0] != '.') || (allfiles)) { if (my_fnmatch(pattern, filedat->d_name, 0) == 0) { (g->namecount)++; reallocwrapper(sizeof(char **) * g->namecount, (void *)&(g->name)); g->name[g->namecount - 1] = strdupwrapper(filedat->d_name); } } } reallocwrapper(sizeof(char **) * (g->namecount + 1), (void *)&(g->name)); g->name[g->namecount] = NULL; if (g->namecount > 0) { qsortarray(g->name, 0, g->namecount-1); g->stat_buf = mallocwrapper(sizeof(struct stat) * (g->namecount)); for(count = 0; count < g->namecount; count++) { if (lstat(g->name[count], g->stat_buf + count) == -1) { printf("stat error\n"); memset(g->stat_buf + count, 0, sizeof(struct stat)); } else g->blocks += g->stat_buf[count].st_blocks / 2; } } } if (globdir) closedir(globdir); return(g); } void myglobfree (MYGLOBDATA *g) { int count; if (g->name) { for (count = 0; count < g->namecount; count++) freewrapper(g->name[count]); freewrapper(g->name); freeifnotnull(g->stat_buf); } freewrapper(g); }