changeset 8288:25fd5c47e31a

Add a scandir() implementation for systems that do not have it in libc.
author jkeil
date Tue, 26 Nov 2002 18:31:30 +0000
parents c3eb28f300d0
children 2a69a884206a
files linux/Makefile linux/scandir.c
diffstat 2 files changed, 135 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/linux/Makefile	Mon Nov 25 20:37:12 2002 +0000
+++ b/linux/Makefile	Tue Nov 26 18:31:30 2002 +0000
@@ -3,7 +3,7 @@
 
 LIBNAME = libosdep.a
 
-SRCS=getch2.c timer-lx.c shmem.c strsep.c # timer.c
+SRCS=getch2.c timer-lx.c shmem.c strsep.c scandir.c # timer.c
 OBJS=$(SRCS:.c=.o)
 
 ifeq ($(TARGET_ARCH_X86),yes)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/linux/scandir.c	Tue Nov 26 18:31:30 2002 +0000
@@ -0,0 +1,134 @@
+/*
+ * scandir, alphasort - scan a directory
+ *
+ * implementation for systems that do not have it in libc
+ */
+
+#include "../config.h"
+
+#ifndef	HAVE_SCANDIR
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+/*
+ * convenience helper function for scandir's |compar()| function: 
+ * sort directory entries using strcoll(3)
+ */
+int
+alphasort(const void *_a, const void *_b)
+{
+    struct dirent **a = (struct dirent **)_a;
+    struct dirent **b = (struct dirent **)_b;
+    return strcoll((*a)->d_name, (*b)->d_name);
+}
+
+
+#define strverscmp(a,b) strcoll(a,b) /* for now */
+
+/*
+ * convenience helper function for scandir's |compar()| function: 
+ * sort directory entries using GNU |strverscmp()|
+ */
+int
+versionsort(const void *_a, const void *_b)
+{
+    struct dirent **a = (struct dirent **)_a;
+    struct dirent **b = (struct dirent **)_b;
+    return strverscmp((*a)->d_name, (*b)->d_name);
+}
+
+/*
+ * The scandir() function reads the directory dirname and builds an
+ * array of pointers to directory entries using malloc(3).  It returns
+ * the number of entries in the array.  A pointer to the array of
+ * directory entries is stored in the location referenced by namelist.
+ *
+ * The select parameter is a pointer to a user supplied subroutine
+ * which is called by scandir() to select which entries are to be
+ * included in the array.  The select routine is passed a pointer to
+ * a directory entry and should return a non-zero value if the
+ * directory entry is to be included in the array.  If select is null,
+ * then all the directory entries will be included.
+ *
+ * The compar parameter is a pointer to a user supplied subroutine
+ * which is passed to qsort(3) to sort the completed array.  If this
+ * pointer is null, the array is not sorted.
+ */
+int
+scandir(const char *dirname,
+	struct dirent ***ret_namelist,
+	int (*select)(const struct dirent *),
+	int (*compar)(const struct dirent **, const struct dirent **))
+{
+    int i, len;
+    int used, allocated;
+    DIR *dir;
+    struct dirent *ent, *ent2;
+    struct dirent **namelist = NULL;
+
+    if ((dir = opendir(dirname)) == NULL)
+	return -1;
+
+    used = 0;
+    allocated = 2;
+    namelist = malloc(allocated * sizeof(struct dirent *));
+    if (!namelist)
+	goto error;
+
+    while ((ent = readdir(dir)) != NULL) {
+
+	if (select != NULL && !select(ent))
+	    continue;
+
+	/* duplicate struct direct for this entry */
+	len = offsetof(struct dirent, d_name) + strlen(ent->d_name) + 1;
+	if ((ent2 = malloc(len)) == NULL)
+	    return -1;
+	
+	if (used >= allocated) {
+	    allocated *= 2;
+	    namelist = realloc(namelist, allocated * sizeof(struct dirent *));
+	    if (!namelist)
+		goto error;
+	}
+	memcpy(ent2, ent, len);
+	namelist[used++] = ent2;
+    }
+    closedir(dir);
+
+    if (compar)
+	qsort(namelist, used, sizeof(struct dirent *),
+	      (int (*)(const void *, const void *)) compar);
+
+    *ret_namelist = namelist;
+    return used;
+
+
+error:
+    if (namelist) {
+	for (i = 0; i < used; i++) 
+	    free(namelist[i]);
+	free(namelist);
+    }
+    return -1;
+}
+#endif
+
+
+#if	STANDALONE_MAIN
+int
+main(int argc, char **argv)
+{
+	struct dirent **namelist;
+	int i, n;
+
+	n = scandir("/etc", &namelist, NULL, alphasort);
+
+	for (i = 0; i < n; i++)
+		printf("%s\n", namelist[i]->d_name);
+}
+#endif