b1117fc9d8
- fixed a long standing bug involving USERPREF_DIR and Sys_Find*
228 lines
5.1 KiB
C
228 lines
5.1 KiB
C
/*
|
|
Copyright (C) 2003 Tenebrae Team
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU 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 General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
/*
|
|
Sys_Find* implementation for UNIX like systems
|
|
system conformance :
|
|
|
|
system not having the glob system call :
|
|
|
|
ISO/IEC 9945-2 (fnmatch)
|
|
BSD 4.3 (dirent syscalls)
|
|
|
|
OTHER :
|
|
|
|
POSIX.2 (glob)
|
|
|
|
*/
|
|
|
|
#include "quakedef.h"
|
|
#include <errno.h>
|
|
|
|
#if !defined(__GLIBC__)
|
|
|
|
#include <dirent.h>
|
|
#include <fnmatch.h>
|
|
|
|
#define UXDATA_GRANULARITY 10
|
|
|
|
typedef struct {
|
|
int pathlen;
|
|
size_t count;
|
|
size_t lsize;
|
|
DIR *dir;
|
|
struct dirent **list;
|
|
} uxdirdata_t;
|
|
|
|
int uxdata_free (uxdirdata_t *ud)
|
|
{
|
|
int i;
|
|
closedir (ud->dir);
|
|
Z_Free (ud->list);
|
|
}
|
|
|
|
|
|
int direntp_compare (struct dirent **p1, struct dirent **p2)
|
|
{
|
|
return strncmp ((*p1)->d_name, (*p2)->d_name, sizeof ((*p1)->d_name));
|
|
}
|
|
|
|
dirdata_t *Sys_Findfirst (char *dirname, char *filter, dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
DIR *dir;
|
|
struct dirent *entry;
|
|
struct dirent **list;
|
|
int pathlen;
|
|
|
|
if (dirdata && filter){
|
|
pathlen = strlen (dirname);
|
|
if (pathlen >= MAX_OSPATH-1)
|
|
return NULL;
|
|
strncpy (dirdata->entry, dirname, sizeof(dirdata->entry));
|
|
dir = opendir (dirdata->entry);
|
|
if (dir == NULL) {
|
|
return NULL;
|
|
}
|
|
uxdata = Z_Malloc (sizeof(uxdirdata_t));
|
|
uxdata->count = 0;
|
|
uxdata->pathlen = pathlen;
|
|
uxdata->lsize = 10;
|
|
uxdata->list = Z_Malloc (sizeof(struct dirent *) * (uxdata->lsize));
|
|
|
|
while (entry = readdir (dir)){
|
|
int code;
|
|
|
|
// realloc entry list
|
|
if (uxdata->lsize == uxdata->count) {
|
|
list = Z_Malloc (sizeof(struct dirent *) * (uxdata->lsize += UXDATA_GRANULARITY));
|
|
memcpy (list, uxdata->list, uxdata->count);
|
|
Z_Free (uxdata->list);
|
|
uxdata->list = list;
|
|
}
|
|
// check name matching filter
|
|
code = fnmatch (filter, entry->d_name, 0);
|
|
switch (code){
|
|
case 0: /* match */
|
|
uxdata->list[uxdata->count] = entry;
|
|
uxdata->count++;
|
|
break;
|
|
case FNM_NOMATCH:
|
|
break;
|
|
default:
|
|
Sys_Error ("Sys_Glob_select : fnmatch call (%d)\n",errno);
|
|
}
|
|
}
|
|
if (uxdata->count) {
|
|
uxdata->lsize = uxdata->count;
|
|
uxdata->count = 0;
|
|
// sort the entry list
|
|
qsort(uxdata->list, uxdata->lsize, sizeof(struct dirent *),direntp_compare);
|
|
if (dirname[pathlen-1] != '/') {
|
|
dirdata->entry[pathlen]='/';
|
|
uxdata->pathlen++;
|
|
dirdata->entry[uxdata->pathlen]=0;
|
|
}
|
|
strncpy (dirdata->entry+uxdata->pathlen, uxdata->list[0]->d_name, sizeof(dirdata->entry)-uxdata->pathlen);
|
|
uxdata->dir = dir;
|
|
dirdata->internal = uxdata;
|
|
return dirdata;
|
|
}
|
|
else uxdata_free (uxdata);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
dirdata_t *Sys_Findnext (dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
if (dirdata){
|
|
uxdata=dirdata->internal;
|
|
if (uxdata) {
|
|
uxdata->count++;
|
|
// next entry ?
|
|
if (uxdata->count<uxdata->lsize){
|
|
strncpy (dirdata->entry+uxdata->pathlen, uxdata->list[0]->d_name, sizeof(dirdata->entry)-uxdata->pathlen);
|
|
return dirdata;
|
|
}
|
|
// no -> close (just in case Findclose isn't called)
|
|
uxdata_free (dirdata->internal);
|
|
dirdata->internal=NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Sys_Findclose (dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
if (dirdata){
|
|
uxdata=dirdata->internal;
|
|
if (uxdata){
|
|
uxdata_free (uxdata);
|
|
dirdata->internal=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
#include <glob.h>
|
|
|
|
typedef struct {
|
|
glob_t globbuf;
|
|
size_t count;
|
|
} uxdirdata_t;
|
|
|
|
|
|
dirdata_t *Sys_Findfirst (char *dir, char *filter, dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
if (dirdata && filter){
|
|
char dirfilter[MAX_OSPATH];
|
|
uxdata=Z_Malloc (sizeof(uxdirdata_t));
|
|
sprintf (dirfilter,"%s/%s", dir, filter);
|
|
glob (dirfilter,0,NULL,&uxdata->globbuf);
|
|
if (uxdata->globbuf.gl_pathc){
|
|
dirdata->internal=uxdata;
|
|
strncpy (dirdata->entry,uxdata->globbuf.gl_pathv[0],sizeof(dirdata->entry));
|
|
uxdata->count=0;
|
|
return dirdata;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
dirdata_t *Sys_Findnext (dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
if (dirdata){
|
|
uxdata=dirdata->internal;
|
|
if (uxdata) {
|
|
uxdata->count++;
|
|
// next entry ?
|
|
if (uxdata->count<uxdata->globbuf.gl_pathc){
|
|
strncpy (dirdata->entry,uxdata->globbuf.gl_pathv[uxdata->count],sizeof(dirdata->entry));
|
|
return dirdata;
|
|
}
|
|
// no -> close (just in case Findclose isn't called)
|
|
globfree (&uxdata->globbuf);
|
|
Z_Free (dirdata->internal);
|
|
dirdata->internal=NULL;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void Sys_Findclose (dirdata_t *dirdata)
|
|
{
|
|
uxdirdata_t *uxdata;
|
|
if (dirdata){
|
|
uxdata=dirdata->internal;
|
|
if (uxdata){
|
|
globfree (&uxdata->globbuf);
|
|
Z_Free (uxdata);
|
|
dirdata->internal=NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|