Index: darkplaces/common.h
diff -u darkplaces/common.h:1.100 darkplaces/common.h:1.101
--- darkplaces/common.h:1.100	Sun Jan 14 05:19:20 2007
+++ darkplaces/common.h	Thu Mar 15 09:54:37 2007
@@ -289,16 +289,18 @@
 
 typedef struct stringlist_s
 {
-	struct stringlist_s *next;
-	char *text;
+	// maxstrings changes as needed, causing reallocation of strings[] array
+	int maxstrings;
+	int numstrings;
+	char **strings;
 } stringlist_t;
 
 int matchpattern(const char *in, const char *pattern, int caseinsensitive);
-stringlist_t *stringlistappend(stringlist_t *current, char *text);
-void stringlistfree(stringlist_t *current);
-stringlist_t *stringlistsort(stringlist_t *start);
-stringlist_t *listdirectory(const char *path);
-void freedirectory(stringlist_t *list);
+void stringlistinit(stringlist_t *list);
+void stringlistfreecontents(stringlist_t *list);
+void stringlistappend(stringlist_t *list, char *text);
+void stringlistsort(stringlist_t *list);
+void listdirectory(stringlist_t *list, const char *path);
 
 char *SearchInfostring(const char *infostring, const char *key);
 
Index: darkplaces/filematch.c
diff -u darkplaces/filematch.c:1.11 darkplaces/filematch.c:1.12
--- darkplaces/filematch.c:1.11	Sat Aug  5 08:31:02 2006
+++ darkplaces/filematch.c	Thu Mar 15 09:54:37 2007
@@ -57,79 +57,76 @@
 	return 1; // success
 }
 
-// a little chained strings system
-stringlist_t *stringlistappend(stringlist_t *current, char *text)
+// a little strings system
+void stringlistinit(stringlist_t *list)
 {
-	stringlist_t *newitem;
-	size_t textlen;
+	memset(list, 0, sizeof(*list));
+}
 
-	textlen = strlen(text) + 1;
-	newitem = (stringlist_t *)Z_Malloc(textlen + sizeof(stringlist_t));
-	newitem->next = NULL;
-	newitem->text = (char *)(newitem + 1);
-	memcpy(newitem->text, text, textlen);
-	if (current)
-		current->next = newitem;
-	return newitem;
+void stringlistfreecontents(stringlist_t *list)
+{
+	int i;
+	for (i = 0;i < list->numstrings;i++)
+	{
+		if (list->strings[i])
+			Z_Free(list->strings[i]);
+		list->strings[i] = NULL;
+	}
+	list->numstrings = 0;
+	list->maxstrings = 0;
+	if (list->strings)
+		Z_Free(list->strings);
 }
 
-void stringlistfree(stringlist_t *current)
+void stringlistappend(stringlist_t *list, char *text)
 {
-	stringlist_t *next;
-	while (current)
+	size_t textlen;
+	char **oldstrings;
+
+	if (list->numstrings >= list->maxstrings)
 	{
-		next = current->next;
-		Z_Free(current);
-		current = next;
+		oldstrings = list->strings;
+		list->maxstrings += 4096;
+		list->strings = Z_Malloc(list->maxstrings * sizeof(*list->strings));
+		if (list->numstrings)
+			memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings));
+		if (oldstrings)
+			Z_Free(oldstrings);
 	}
+	textlen = strlen(text) + 1;
+	list->strings[list->numstrings] = Z_Malloc(textlen);
+	memcpy(list->strings[list->numstrings], text, textlen);
+	list->numstrings++;
 }
 
-stringlist_t *stringlistsort(stringlist_t *start)
+void stringlistsort(stringlist_t *list)
 {
-	int notdone;
-	stringlist_t *current, *previous, *temp2, *temp3, *temp4;
-	// exit early if there's nothing to sort
-	if (start == NULL || start->next == NULL)
-		return start;
-	notdone = 1;
-	while (notdone)
+	int i, j;
+	char *temp;
+	// this is a selection sort (finds the best entry for each slot)
+	for (i = 0;i < list->numstrings - 1;i++)
 	{
-		current = start;
-		notdone = 0;
-		previous = NULL;
-		while (current && current->next)
+		for (j = i + 1;j < list->numstrings;j++)
 		{
-			if (strcmp(current->text, current->next->text) > 0)
+			if (strcmp(list->strings[i], list->strings[j]) > 0)
 			{
-				// current is greater than next
-				notdone = 1;
-				temp2 = current->next;
-				temp3 = current;
-				temp4 = current->next->next;
-				if (previous)
-					previous->next = temp2;
-				else
-					start = temp2;
-				temp2->next = temp3;
-				temp3->next = temp4;
-				break;
+				temp = list->strings[i];
+				list->strings[i] = list->strings[j];
+				list->strings[j] = temp;
 			}
-			previous = current;
-			current = current->next;
 		}
 	}
-	return start;
 }
 
 // operating system specific code
 #ifdef WIN32
 #include <io.h>
-stringlist_t *listdirectory(const char *path)
+void listdirectory(stringlist_t *list, const char *path)
 {
+	int i;
 	char pattern[4096], *c;
 	struct _finddata_t n_file;
 	long hFile;
-	stringlist_t *start, *current;
 	strlcpy (pattern, path, sizeof (pattern));
 	strlcat (pattern, "*", sizeof (pattern));
 	// ask for the directory listing handle
@@ -137,49 +134,31 @@
 	if(hFile == -1)
 		return NULL;
 	// start a new chain with the the first name
-	start = current = stringlistappend(NULL, n_file.name);
+	stringlistappend(list, n_file.name);
 	// iterate through the directory
 	while (_findnext(hFile, &n_file) == 0)
-		current = stringlistappend(current, n_file.name);
+		stringlistappend(list, n_file.name);
 	_findclose(hFile);
 
 	// convert names to lowercase because windows does not care, but pattern matching code often does
-	for (current = start;current;current = current->next)
-		for (c = current->text;*c;c++)
+	for (i = 0;i < list->numstrings;i++)
+		for (c = list->strings[i];*c;c++)
 			if (*c >= 'A' && *c <= 'Z')
 				*c += 'a' - 'A';
-
-	// sort the list alphanumerically
-	return stringlistsort(start);
 }
 #else
 #include <dirent.h>
-stringlist_t *listdirectory(const char *path)
+void listdirectory(stringlist_t *list, const char *path)
 {
 	DIR *dir;
 	struct dirent *ent;
-	stringlist_t *start, *current;
 	dir = opendir(path);
 	if (!dir)
-		return NULL;
-	start = current = NULL;
+		return;
 	while ((ent = readdir(dir)))
-	{
 		if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
-		{
-			current = stringlistappend(current, ent->d_name);
-			if (!start)
-				start = current;
-		}
-	}
+			stringlistappend(list, ent->d_name);
 	closedir(dir);
-	// sort the list alphanumerically
-	return stringlistsort(start);
 }
 #endif
 
-void freedirectory(stringlist_t *list)
-{
-	stringlistfree(list);
-}
-
Index: darkplaces/fs.c
diff -u darkplaces/fs.c:1.108 darkplaces/fs.c:1.109
--- darkplaces/fs.c:1.108	Sun Mar 11 19:54:14 2007
+++ darkplaces/fs.c	Thu Mar 15 09:54:37 2007
@@ -961,35 +961,38 @@
 */
 void FS_AddGameDirectory (const char *dir)
 {
-	stringlist_t *list, *current;
+	int i;
+	stringlist_t list;
 	searchpath_t *search;
 	char pakfile[MAX_OSPATH];
 
 	strlcpy (fs_gamedir, dir, sizeof (fs_gamedir));
 
-	list = listdirectory(dir);
+	stringlistinit(&list);
+	listdirectory(&list, dir);
+	stringlistsort(&list);
 
 	// add any PAK package in the directory
-	for (current = list;current;current = current->next)
+	for (i = 0;i < list.numstrings;i++)
 	{
-		if (!strcasecmp(FS_FileExtension(current->text), "pak"))
+		if (!strcasecmp(FS_FileExtension(list.strings[i]), "pak"))
 		{
-			dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+			dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
 			FS_AddPack_Fullpath(pakfile, NULL, false);
 		}
 	}
 
 	// add any PK3 package in the directory
-	for (current = list;current;current = current->next)
+	for (i = 0;i < list.numstrings;i++)
 	{
-		if (!strcasecmp(FS_FileExtension(current->text), "pk3"))
+		if (!strcasecmp(FS_FileExtension(list.strings[i]), "pk3"))
 		{
-			dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, current->text);
+			dpsnprintf (pakfile, sizeof (pakfile), "%s%s", dir, list.strings[i]);
 			FS_AddPack_Fullpath(pakfile, NULL, false);
 		}
 	}
 
-	freedirectory(list);
+	stringlistfreecontents(&list);
 
 	// Add the directory to the search path
 	// (unpacked files have the priority over packed files)
@@ -1281,10 +1284,13 @@
 */
 qboolean FS_CheckGameDir(const char *gamedir)
 {
-	stringlist_t *list = listdirectory(va("%s%s/", fs_basedir, gamedir));
-	if (list)
-		freedirectory(list);
-	return list != NULL;
+	qboolean success;
+	stringlist_t list;
+	stringlistinit(&list);
+	listdirectory(&list, va("%s%s/", fs_basedir, gamedir));
+	success = list.numstrings > 0;
+	stringlistfreecontents(&list);
+	return success;
 }
 
 
@@ -2423,8 +2429,9 @@
 	fssearch_t *search;
 	searchpath_t *searchpath;
 	pack_t *pak;
-	int i, basepathlength, numfiles, numchars;
-	stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
+	int i, basepathlength, numfiles, numchars, resultlistindex, dirlistindex;
+	stringlist_t resultlist;
+	stringlist_t dirlist;
 	const char *slash, *backslash, *colon, *separator;
 	char *basepath;
 	char netpath[MAX_OSPATH];
@@ -2439,10 +2446,9 @@
 		return NULL;
 	}
 
+	stringlistinit(&resultlist);
+	stringlistinit(&dirlist);
 	search = NULL;
-	liststart = NULL;
-	listcurrent = NULL;
-	listtemp = NULL;
 	slash = strrchr(pattern, '/');
 	backslash = strrchr(pattern, '\\');
 	colon = strrchr(pattern, ':');
@@ -2469,14 +2475,12 @@
 				{
 					if (matchpattern(temp, (char *)pattern, true))
 					{
-						for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-							if (!strcmp(listtemp->text, temp))
+						for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+							if (!strcmp(resultlist.strings[resultlistindex], temp))
 								break;
-						if (listtemp == NULL)
+						if (resultlistindex == resultlist.numstrings)
 						{
-							listcurrent = stringlistappend(listcurrent, temp);
-							if (liststart == NULL)
-								liststart = listcurrent;
+							stringlistappend(&resultlist, temp);
 							if (!quiet)
 								Con_DPrintf("SearchPackFile: %s : %s\n", pak->filename, temp);
 						}
@@ -2501,59 +2505,52 @@
 		{
 			// get a directory listing and look at each name
 			dpsnprintf(netpath, sizeof (netpath), "%s%s", searchpath->filename, basepath);
-			if ((dir = listdirectory(netpath)))
+			stringlistinit(&dirlist);
+			listdirectory(&dirlist, netpath);
+			for (dirlistindex = 0;dirlistindex < dirlist.numstrings;dirlistindex++)
 			{
-				for (dirfile = dir;dirfile;dirfile = dirfile->next)
+				dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirlist.strings[dirlistindex]);
+				if (matchpattern(temp, (char *)pattern, true))
 				{
-					dpsnprintf(temp, sizeof(temp), "%s%s", basepath, dirfile->text);
-					if (matchpattern(temp, (char *)pattern, true))
+					for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+						if (!strcmp(resultlist.strings[resultlistindex], temp))
+							break;
+					if (resultlistindex == resultlist.numstrings)
 					{
-						for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-							if (!strcmp(listtemp->text, temp))
-								break;
-						if (listtemp == NULL)
-						{
-							listcurrent = stringlistappend(listcurrent, temp);
-							if (liststart == NULL)
-								liststart = listcurrent;
-							if (!quiet)
-								Con_DPrintf("SearchDirFile: %s\n", temp);
-						}
+						stringlistappend(&resultlist, temp);
+						if (!quiet)
+							Con_DPrintf("SearchDirFile: %s\n", temp);
 					}
 				}
-				freedirectory(dir);
 			}
+			stringlistfreecontents(&dirlist);
 		}
 	}
 
-	if (liststart)
+	if (resultlist.numstrings)
 	{
-		liststart = stringlistsort(liststart);
-		numfiles = 0;
+		stringlistsort(&resultlist);
+		numfiles = resultlist.numstrings;
 		numchars = 0;
-		for (listtemp = liststart;listtemp;listtemp = listtemp->next)
-		{
-			numfiles++;
-			numchars += (int)strlen(listtemp->text) + 1;
-		}
+		for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
+			numchars += (int)strlen(resultlist.strings[resultlistindex]) + 1;
 		search = (fssearch_t *)Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
 		search->filenames = (char **)((char *)search + sizeof(fssearch_t));
 		search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
 		search->numfilenames = (int)numfiles;
 		numfiles = 0;
 		numchars = 0;
-		for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+		for (resultlistindex = 0;resultlistindex < resultlist.numstrings;resultlistindex++)
 		{
 			size_t textlen;
 			search->filenames[numfiles] = search->filenamesbuffer + numchars;
-			textlen = strlen(listtemp->text) + 1;
-			memcpy(search->filenames[numfiles], listtemp->text, textlen);
+			textlen = strlen(resultlist.strings[resultlistindex]) + 1;
+			memcpy(search->filenames[numfiles], resultlist.strings[resultlistindex], textlen);
 			numfiles++;
 			numchars += (int)textlen;
 		}
-		if (liststart)
-			stringlistfree(liststart);
 	}
+	stringlistfreecontents(&resultlist);
 
 	Mem_Free(basepath);
 	return search;