/* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1