[RFC PATCH 3/5] util: add a homebrew scandir implementation

Jani Nikula jani at nikula.org
Fri Apr 15 12:29:17 PDT 2016


Add support for a filter callback with a context parameter, propagate
errors from the filter callback, generate a list of filenames instead
of dirents.
---
 util/Makefile.local |  2 +-
 util/scandir.c      | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 util/scandir.h      | 11 +++++++
 3 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 util/scandir.c
 create mode 100644 util/scandir.h

diff --git a/util/Makefile.local b/util/Makefile.local
index 905f23763468..8893209f320e 100644
--- a/util/Makefile.local
+++ b/util/Makefile.local
@@ -5,7 +5,7 @@ extra_cflags += -I$(srcdir)/$(dir)
 
 libutil_c_srcs := $(dir)/xutil.c $(dir)/error_util.c $(dir)/hex-escape.c \
 		  $(dir)/string-util.c $(dir)/talloc-extra.c $(dir)/zlib-extra.c \
-		$(dir)/util.c
+		$(dir)/util.c $(dir)/scandir.c
 
 libutil_modules := $(libutil_c_srcs:.c=.o)
 
diff --git a/util/scandir.c b/util/scandir.c
new file mode 100644
index 000000000000..c69717724235
--- /dev/null
+++ b/util/scandir.c
@@ -0,0 +1,87 @@
+/* scandir.c - Dedicated scandir implementation.
+ *
+ * Copyright (c) 2016 Jani Nikula
+ *
+ * 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 3 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, see http://www.gnu.org/licenses/ .
+ *
+ * Author: Jani Nikula <jani at nikula.org>
+ */
+
+#include "scandir.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+int scandirx (const char *path, char ***namelist,
+	      int (*filter)(const struct dirent *dirent, void *context),
+	      int (*compar)(const void *a, const void *b),
+	      void *context)
+{
+    DIR *dir;
+    struct dirent *d;
+    char **array = NULL;
+    int i, count = 0, array_size = 0;
+    char *d_name;
+
+    dir = opendir (path);
+    if (!dir)
+	return -1;
+
+    while ((d = readdir (dir)) != NULL) {
+	if (filter) {
+	    int selected = filter (d, context);
+	    if (selected < 0)
+		goto err;
+	    else if (! selected)
+		continue;
+	}
+
+	if (count == array_size) {
+	    char **new_array;
+
+	    array_size = array_size ? 2 * array_size : 16;
+
+	    new_array = realloc (array, array_size * sizeof (*array));
+	    if (! new_array)
+		goto err;
+
+	    array = new_array;
+	}
+
+	d_name = strdup (d->d_name);
+	if (! d_name)
+	    goto err;
+
+	array[count++] = d_name;
+    }
+
+    closedir (dir);
+
+    if (compar)
+	qsort (array, count, sizeof (*array), compar);
+
+    *namelist = array;
+
+    return count;
+
+err:
+    for (i = 0; i < count; i++) {
+	free (array[i]);
+    }
+    free (array);
+
+    return -1;
+}
diff --git a/util/scandir.h b/util/scandir.h
new file mode 100644
index 000000000000..cc5ed95a8b1b
--- /dev/null
+++ b/util/scandir.h
@@ -0,0 +1,11 @@
+#ifndef _SCANDIR_H
+#define _SCANDIR_H
+
+#include <dirent.h>
+
+int scandirx (const char *path, char ***namelist,
+	      int (*filter)(const struct dirent *dirent, void *context),
+	      int (*compar)(const void *a, const void *b),
+	      void *context);
+
+#endif /* _SCANDIR_H */
-- 
2.1.4



More information about the notmuch mailing list