Reimplement Sys_ListFiles and Sys_ListFilteredFiles

They had several bugs, like showing the current and parent directory entires twice, not seeing files but only directories, etc.
This commit is contained in:
pryon 2024-09-21 19:36:13 +02:00
parent 92190220aa
commit 6b91846b0c
2 changed files with 312 additions and 268 deletions

View file

@ -369,7 +369,9 @@ DIRECTORY SCANNING
Sys_ListFilteredFiles
==================
*/
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
void Sys_ListFilteredFiles(
const char *basedir, char *subdirs, char *filter, qboolean wantsubs, char **list, int *numfiles
)
{
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
@ -387,8 +389,7 @@ void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, ch
if (strlen(subdirs)) {
Com_sprintf(search, sizeof(search), "%s/%s", basedir, subdirs);
}
else {
} else {
Com_sprintf(search, sizeof(search), "%s", basedir);
}
@ -397,27 +398,42 @@ void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, ch
}
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
if (stat(filename, &st) == -1)
// Fixed in OPM:
// don't show current and parent dir entries twice
if (!(Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) && Q_stricmp(d->d_name, "cvs")) {
continue;
}
if (st.st_mode & S_IFDIR) {
if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) {
Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name);
if (stat(filename, &st) == -1) {
continue;
}
if ((st.st_mode & S_IFDIR) != 0 && wantsubs) {
if (strlen(subdirs)) {
Com_sprintf(newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name);
}
else {
} else {
Com_sprintf(newsubdirs, sizeof(newsubdirs), "%s", d->d_name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
// recursively iterate into subdirectory
Sys_ListFilteredFiles(basedir, newsubdirs, filter, wantsubs, list, numfiles);
}
if (*numfiles >= MAX_FOUND_FILES - 1) {
break;
}
if (strlen(subdirs)) {
Com_sprintf(filename, sizeof(filename), "%s/%s", subdirs, d->d_name);
if (!Com_FilterPath( filter, filename, qfalse ))
} else {
Q_strncpyz(filename, d->d_name, sizeof(filename));
}
if (!Com_FilterPath(filter, filename, qfalse)) {
continue;
}
list[*numfiles] = CopyString(filename);
(*numfiles)++;
}
@ -434,26 +450,39 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
{
struct dirent *d;
DIR *fdir;
qboolean dironly = wantsubs;
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
int i;
struct stat st;
char buffer[64];
int extLen;
if (directory[0] == '\0') {
*numfiles = 0;
return NULL;
}
if (!extension) {
extension = "";
}
// passing a slash as extension will find directories,
// anything else looks only for files with that extension
if (!filter && (extension[0] != '/' || extension[1])) {
Q_snprintf(buffer, sizeof(buffer), "*%s", extension);
filter = buffer;
}
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
Sys_ListFilteredFiles(directory, "", filter, wantsubs, list, &nfiles);
list[nfiles] = NULL;
*numfiles = nfiles;
if (!nfiles)
if (!nfiles) {
return NULL;
}
listCopy = Z_Malloc((nfiles + 1) * sizeof(*listCopy));
for (i = 0; i < nfiles; i++) {
@ -464,20 +493,7 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
return listCopy;
}
if ( directory[0] == '\0' ) {
*numfiles = 0;
return NULL;
}
if ( !extension)
extension = "";
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
dironly = qtrue;
}
extLen = strlen( extension );
// only enumerate directories from this point onward
// search
nfiles = 0;
@ -489,23 +505,24 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
while ((d = readdir(fdir)) != NULL) {
Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name);
if (stat(search, &st) == -1)
if (stat(search, &st) == -1) {
continue;
if ((dironly && !(st.st_mode & S_IFDIR)) ||
(!dironly && (st.st_mode & S_IFDIR)))
continue;
if (*extension) {
if ( strlen( d->d_name ) < extLen ||
Q_stricmp(
d->d_name + strlen( d->d_name ) - extLen,
extension ) ) {
continue; // didn't match
}
}
if ( nfiles == MAX_FOUND_FILES - 1 )
// Fixed in OPM:
// don't show current and parent dir entries twice
if (!(Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..") && Q_stricmp(d->d_name, "cvs"))) {
continue;
}
if ((st.st_mode & S_IFDIR) == 0) {
continue;
}
if (nfiles == MAX_FOUND_FILES - 1) {
break;
}
list[nfiles] = CopyString(d->d_name);
nfiles++;
}

View file

@ -477,7 +477,9 @@ DIRECTORY SCANNING
Sys_ListFilteredFiles
==============
*/
void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles )
void Sys_ListFilteredFiles(
const char *basedir, const char *subdirs, char *filter, qboolean wantsubs, char **list, int *numfiles
)
{
char search[MAX_OSPATH], newsubdirs[MAX_OSPATH];
char filename[MAX_OSPATH];
@ -494,8 +496,7 @@ void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, ch
if (strlen(subdirs)) {
Com_sprintf(search, sizeof(search), "%s\\%s\\*", basedir, subdirs);
}
else {
} else {
Com_sprintf(search, sizeof(search), "%s\\*", basedir);
}
@ -505,24 +506,45 @@ void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, ch
}
do {
if (findinfo.attrib & _A_SUBDIR) {
if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) {
if (strlen(subdirs)) {
Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name);
// Fixed in OPM:
// don't show current and parent dir entries twice
if (!(Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..") && Q_stricmp(findinfo.name, "cvs"))) {
continue;
}
else {
if ((findinfo.attrib & _A_SUBDIR) != 0 && wantsubs) {
if (strlen(subdirs)) {
Com_sprintf(newsubdirs, sizeof(newsubdirs), "%s\\%s\\*", subdirs, findinfo.name);
} else {
Com_sprintf(newsubdirs, sizeof(newsubdirs), "%s", findinfo.name);
}
Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles );
}
// recursively iterate into subdirectory
Sys_ListFilteredFiles(basedir, newsubdirs, filter, wantsubs, list, numfiles);
}
if (*numfiles >= MAX_FOUND_FILES - 1) {
break;
}
if (strlen(subdirs)) {
Com_sprintf(filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name);
if (!Com_FilterPath( filter, filename, qfalse ))
} else {
Q_strncpyz(filename, findinfo.name, sizeof(filename));
}
if (!Com_FilterPath(filter, filename, qfalse)) {
continue;
}
list[*numfiles] = CopyString(filename);
// replace backslashes with forward slashes, if any
// FS_ReplaceSeparators would be nice but it does the opposite
for (char *c = strchr(list[*numfiles], '\\'); c; c = strchr(list[*numfiles], '\\')) {
*c = '/';
}
(*numfiles)++;
} while (_findnext(findhandle, &findinfo) != -1);
@ -566,23 +588,38 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
char search[MAX_OSPATH];
int nfiles;
char **listCopy;
char *list[MAX_FOUND_FILES];
char *list[MAX_FOUND_FILES] = {NULL};
struct _finddata_t findinfo;
intptr_t findhandle;
int flag;
qboolean swapped;
int i;
int extLen;
char buffer[64];
if (directory[0] == NULL) {
*numfiles = 0;
return NULL;
}
if (!extension) {
extension = "";
}
// passing a slash as extension will find directories,
// anything else looks only for files with that extension
if (!filter && (extension[0] != '/' || extension[1])) {
Q_snprintf(buffer, sizeof(buffer), "*%s", extension);
filter = buffer;
}
if (filter) {
nfiles = 0;
Sys_ListFilteredFiles( directory, "", filter, list, &nfiles );
Sys_ListFilteredFiles(directory, "", filter, wantsubs, list, &nfiles);
list[ nfiles ] = 0;
list[nfiles] = NULL;
*numfiles = nfiles;
if (!nfiles)
if (!nfiles) {
return NULL;
}
listCopy = Z_Malloc((nfiles + 1) * sizeof(*listCopy));
for (i = 0; i < nfiles; i++) {
@ -593,30 +630,11 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
return listCopy;
}
if ( directory[0] == '\0' ) {
*numfiles = 0;
return NULL;
}
if ( !extension) {
extension = "";
}
// passing a slash as extension will find directories
if ( extension[0] == '/' && extension[1] == 0 ) {
extension = "";
flag = 0;
} else {
flag = _A_SUBDIR;
}
extLen = strlen( extension );
Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension );
// only enumerate directories from this point onward
Com_sprintf(search, 256, "%s\\*", directory);
// search
nfiles = 0;
findhandle = _findfirst(search, &findinfo);
if (findhandle == -1) {
*numfiles = 0;
@ -624,24 +642,32 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
}
do {
if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) {
if (*extension) {
if ( strlen( findinfo.name ) < extLen ||
Q_stricmp(
findinfo.name + strlen( findinfo.name ) - extLen,
extension ) ) {
continue; // didn't match
// Fixed in OPM:
// don't show current and parent dir entries twice
if (!(Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..") && Q_stricmp(findinfo.name, "cvs"))) {
continue;
}
if ((findinfo.attrib & _A_SUBDIR) == 0) {
continue;
}
if ( nfiles == MAX_FOUND_FILES - 1 ) {
if (nfiles >= MAX_FOUND_FILES - 1) {
break;
}
list[nfiles] = CopyString(findinfo.name);
nfiles++;
// replace backslashes with forward slashes
// FS_ReplaceSeparators would be nice but it does the opposite
for (char *c = strchr(list[nfiles], '\\'); c; c = strchr(list[nfiles], '\\')) {
*c = '/';
}
++nfiles;
} while (_findnext(findhandle, &findinfo) != -1);
list[ nfiles ] = 0;
list[nfiles] = NULL;
_findclose(findhandle);
@ -658,17 +684,18 @@ char **Sys_ListFiles( const char *directory, const char *extension, const char *
}
listCopy[i] = NULL;
// bubble-sort name entries alphabetically, in ascending order
do {
flag = 0;
swapped = qfalse;
for (i = 1; i < nfiles; i++) {
if (strgtr(listCopy[i - 1], listCopy[i])) {
char *temp = listCopy[i];
listCopy[i] = listCopy[i - 1];
listCopy[i - 1] = temp;
flag = 1;
swapped = qtrue;
}
}
} while(flag);
} while (swapped);
return listCopy;
}