[PATCH] COM_ScanDir

Introduce a new helper function: COM_ScanDir.

The function populates a string tree with the filesnames found in the
given folder. An optional prefix and file extension can be specified
to filter the results. File extensions can be optionally stripped.

diff -urN b/NQ/common.c head/NQ/common.c
--- b/NQ/common.c	2006-02-08 17:53:35.000000000 +1030
+++ head/NQ/common.c	2006-02-07 21:08:58.000000000 +1030
@@ -19,6 +19,10 @@
 */
 // common.c -- misc functions used in client and server
 
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
 #include "cmd.h"
 #include "common.h"
 #include "console.h"
@@ -27,6 +31,7 @@
 #include "host.h"
 #include "net.h"
 #include "quakedef.h"
+#include "shell.h"
 #include "sys.h"
 #include "zone.h"
 
@@ -1321,6 +1326,97 @@
     return -1;
 }
 
+static void
+COM_ScanDirDir(struct rb_string_root *root, DIR *dir, const char *pfx,
+	       const char *ext, qboolean stripext)
+{
+    int pfx_len, ext_len;
+    struct dirent *d;
+    char *fname;
+
+    pfx_len = pfx ? strlen(pfx) : 0;
+    ext_len = ext ? strlen(ext) : 0;
+
+    while ((d = readdir(dir))) {
+	if ((!pfx || !strncasecmp(d->d_name, pfx, pfx_len)) &&
+	    (!ext || COM_CheckExtension(d->d_name, ext))) {
+	    int len = strlen(d->d_name);
+	    if (ext && stripext)
+		len -= ext_len;
+	    fname = Z_Malloc(len + 1);
+	    if (fname) {
+		strncpy(fname, d->d_name, len);
+		fname[len] = '\0';
+		ST_InsertAlloc(root, fname, NULL);
+		Z_Free(fname);
+	    }
+	}
+    }
+}
+
+static void
+COM_ScanDirPak(struct rb_string_root *root, pack_t *pak, const char *pfx,
+	       const char *ext, qboolean stripext)
+{
+    int i, pfx_len, ext_len;
+    char *pak_f, *fname;
+
+    pfx_len = pfx ? strlen(pfx) : 0;
+    ext_len = ext ? strlen(ext) : 0;
+
+    for (i = 0; i < pak->numfiles; i++) {
+	pak_f = strrchr(pak->files[i].name, '/');
+	if (pak_f)
+	    pak_f++;
+	else
+	    pak_f = pak->files[i].name;
+
+	if ((!pfx || !strncasecmp(pak_f, pfx, pfx_len)) &&
+	    (!ext || COM_CheckExtension(pak_f, ext))) {
+	    int len = strlen(pak_f);
+	    if (ext && stripext)
+		len -= ext_len;
+	    fname = Z_Malloc(len + 1);
+	    if (fname) {
+		strncpy(fname, pak_f, len);
+		fname[len] = '\0';
+		ST_InsertAlloc(root, fname, NULL);
+		Z_Free(fname);
+	    }
+	}
+    }
+}
+
+/*
+============
+COM_ScanDir
+
+Scan the contents of a the given directory. Any filenames that match
+both the given prefix and extension are added to the string tree.
+Caller MUST have already called ST_AllocInit()
+============
+*/
+void
+COM_ScanDir(struct rb_string_root *root, const char *path, const char *pfx,
+	    const char *ext, qboolean stripext)
+{
+    searchpath_t *search;
+    char fullpath[MAX_OSPATH];
+    DIR *dir;
+
+    for (search = com_searchpaths; search; search = search->next) {
+	if (search->pack) {
+	    COM_ScanDirPak(root, search->pack, pfx, ext, stripext);
+	} else {
+	    sprintf(fullpath, "%s/%s", search->filename, path);
+	    dir = opendir(fullpath);
+	    if (dir) {
+		COM_ScanDirDir(root, dir, pfx, ext, stripext);
+		closedir(dir);
+	    }
+	}
+    }
+}
 
 /*
 ===========
diff -urN b/NQ/common.h head/NQ/common.h
--- b/NQ/common.h	2006-02-08 17:53:35.000000000 +1030
+++ head/NQ/common.h	2006-02-07 20:42:33.000000000 +1030
@@ -27,6 +27,7 @@
 
 #include "quakedef.h"
 #include "qtypes.h"
+#include "shell.h"
 
 #define stringify__(x) #x
 #define stringify(x) stringify__(x)
@@ -160,6 +161,8 @@
 int COM_OpenFile(const char *filename, int *hndl);
 int COM_FOpenFile(const char *filename, FILE **file);
 void COM_CloseFile(int h);
+void COM_ScanDir(struct rb_string_root *root, const char *path,
+		 const char *pfx, const char *ext, qboolean stripext);
 
 byte *COM_LoadStackFile(const char *path, void *buffer, int bufsize,
 			unsigned long *length);
diff -urN b/QW/client/common.h head/QW/client/common.h
--- b/QW/client/common.h	2006-02-08 17:53:35.000000000 +1030
+++ head/QW/client/common.h	2006-02-08 17:56:16.000000000 +1030
@@ -26,6 +26,7 @@
 
 #include "qtypes.h"
 #include "bothdefs.h"
+#include "shell.h"
 
 #define stringify__(x) #x
 #define stringify(x) stringify__(x)
@@ -175,6 +176,8 @@
 void COM_WriteFile(const char *filename, const void *data, int len);
 int COM_FOpenFile(const char *filename, FILE **file);
 void COM_CloseFile(FILE *h);
+void COM_ScanDir(struct rb_string_root *root, const char *path,
+		 const char *pfx, const char *ext, qboolean stripext);
 
 byte *COM_LoadStackFile(const char *path, void *buffer, int bufsize,
 			unsigned long *length);
diff -urN b/QW/common/common.c head/QW/common/common.c
--- b/QW/common/common.c	2006-02-08 17:53:35.000000000 +1030
+++ head/QW/common/common.c	2006-02-08 17:55:22.000000000 +1030
@@ -19,6 +19,9 @@
 */
 // common.c -- misc functions used in client and server
 
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
 #include <ctype.h>
 
 #ifdef SERVERONLY
@@ -33,6 +36,7 @@
 #include "draw.h"
 #include "net.h"
 #include "protocol.h"
+#include "shell.h"
 #include "sys.h"
 #include "zone.h"
 
@@ -1413,6 +1417,98 @@
     return -1;
 }
 
+static void
+COM_ScanDirDir(struct rb_string_root *root, DIR *dir, const char *pfx,
+	       const char *ext, qboolean stripext)
+{
+    int pfx_len, ext_len;
+    struct dirent *d;
+    char *fname;
+
+    pfx_len = pfx ? strlen(pfx) : 0;
+    ext_len = ext ? strlen(ext) : 0;
+
+    while ((d = readdir(dir))) {
+	if ((!pfx || !strncasecmp(d->d_name, pfx, pfx_len)) &&
+	    (!ext || COM_CheckExtension(d->d_name, ext))) {
+	    int len = strlen(d->d_name);
+	    if (ext && stripext)
+		len -= ext_len;
+	    fname = Z_Malloc(len + 1);
+	    if (fname) {
+		strncpy(fname, d->d_name, len);
+		fname[len] = '\0';
+		ST_InsertAlloc(root, fname, NULL);
+		Z_Free(fname);
+	    }
+	}
+    }
+}
+
+static void
+COM_ScanDirPak(struct rb_string_root *root, pack_t *pak, const char *pfx,
+	       const char *ext, qboolean stripext)
+{
+    int i, pfx_len, ext_len;
+    char *pak_f, *fname;
+
+    pfx_len = pfx ? strlen(pfx) : 0;
+    ext_len = ext ? strlen(ext) : 0;
+
+    for (i = 0; i < pak->numfiles; i++) {
+	pak_f = strrchr(pak->files[i].name, '/');
+	if (pak_f)
+	    pak_f++;
+	else
+	    pak_f = pak->files[i].name;
+
+	if ((!pfx || !strncasecmp(pak_f, pfx, pfx_len)) &&
+	    (!ext || COM_CheckExtension(pak_f, ext))) {
+	    int len = strlen(pak_f);
+	    if (ext && stripext)
+		len -= ext_len;
+	    fname = Z_Malloc(len + 1);
+	    if (fname) {
+		strncpy(fname, pak_f, len);
+		fname[len] = '\0';
+		ST_InsertAlloc(root, fname, NULL);
+		Z_Free(fname);
+	    }
+	}
+    }
+}
+
+/*
+============
+COM_ScanDir
+
+Scan the contents of a the given directory. Any filenames that match
+both the given prefix and extension are added to the string tree.
+Caller MUST have already called ST_AllocInit()
+============
+*/
+void
+COM_ScanDir(struct rb_string_root *root, const char *path, const char *pfx,
+	    const char *ext, qboolean stripext)
+{
+    searchpath_t *search;
+    char fullpath[MAX_OSPATH];
+    DIR *dir;
+
+    for (search = com_searchpaths; search; search = search->next) {
+	if (search->pack) {
+	    COM_ScanDirPak(root, search->pack, pfx, ext, stripext);
+	} else {
+	    sprintf(fullpath, "%s/%s", search->filename, path);
+	    dir = opendir(fullpath);
+	    if (dir) {
+		COM_ScanDirDir(root, dir, pfx, ext, stripext);
+		closedir(dir);
+	    }
+	}
+    }
+}
+
 /*
 ============
 COM_LoadFile
