[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