commit 0deed8c756e9aa4647ab36218b24c1fbc4497953
parent 7b3409f49121468140e0bd348ccd06912042883f
Author: hhvn <dev@hhvn.uk>
Date: Sun, 5 Jun 2022 13:08:03 +0100
Filterable dblist* functions
Diffstat:
M | db/db.c | | | 49 | ++++++++++++++++++++++++++++++++++++------------- |
M | db/db.h | | | 8 | ++++++++ |
2 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/db/db.c b/db/db.c
@@ -45,10 +45,10 @@ static int track(dbGroup *group);
static int untrack(dbGroup *group);
static dbGroup *gettracked(char *dir, char *group);
-static int dirlist(struct Dirlist **list, char *dir);
+static int dirlist(struct Dirlist **list, char *dir, int (*filter)(void *data, char *path), void *fdata);
static dbGroup *dbinitgroup_p(char *dir, char *group);
-static size_t dblistkeys_p(char ***ret, dbGroup *group);
+static size_t dblistkeys_p(char ***ret, dbGroup *group, int (*filter)(void *data, char *path), void *fdata);
static dbGroup *dbgetgroup_p(char *dir, char *group, int init);
static dbPair *dbgetpair_p(dbGroup *group, char *key);
static int dbset_p(dbPair *pair, char *val);
@@ -257,13 +257,18 @@ dbloadgroup_p(char *dir, char *group) {
* List
*/
static int
-dirlist(struct Dirlist **list, char *dir) {
+dirlist(struct Dirlist **list, char *dir, int (*filter)(void *data, char *path), void *fdata) {
struct dirent **dirent;
struct stat st;
struct Dirlist *p, *prev;
char path[PATH_MAX];
int n, i;
+ /* Theoretically, a function could wrap around filter() so that it
+ * could be passed to scandir(), however, it would be difficult for that
+ * function to access filter() without global variables. Therefore,
+ * this function calls the filter on data returned by scandir(). */
+
n = scandir(dir, &dirent, 0, alphasort);
if (n < 0) {
return -1; /* scandir sets errno */
@@ -274,8 +279,8 @@ dirlist(struct Dirlist **list, char *dir) {
strcmp(dirent[i]->d_name, ".") != 0 &&
stat(path, &st) != -1) {
if (S_ISDIR(st.st_mode)) {
- dirlist(list, path);
- } else {
+ dirlist(list, path, filter, fdata);
+ } else if (!filter || filter(fdata, path)) {
if (!(p = malloc(sizeof(struct Dirlist))) || !(p->path = strdup(path))) {
free(p);
for (prev = NULL; p; p = p->next) {
@@ -294,12 +299,18 @@ dirlist(struct Dirlist **list, char *dir) {
}
free(dirent);
}
+
+ if (!*list) {
+ errno = ENOENT;
+ return -1;
+ }
+
return 0;
}
size_t
-dblistgroups(char ***ret, char *dir) {
- struct Dirlist *res, *p, *prev;
+dblistgroups_f(char ***ret, char *dir, int (*filter)(void *data, char *path), void *fdata) {
+ struct Dirlist *res = NULL, *p, *prev;
size_t len, i;
if (!ret || !dir) {
@@ -307,7 +318,7 @@ dblistgroups(char ***ret, char *dir) {
if (ret) *ret = NULL;
return 0;
}
- if (dirlist(&res, dir) == -1) {
+ if (dirlist(&res, dir, filter, fdata) == -1) {
*ret = NULL;
return 0;
}
@@ -327,8 +338,13 @@ dblistgroups(char ***ret, char *dir) {
return len;
}
+size_t
+dblistgroups(char ***ret, char *dir) {
+ return dblistgroups_f(ret, dir, NULL, NULL);
+}
+
static size_t
-dblistkeys_p(char ***ret, dbGroup *group) {
+dblistkeys_p(char ***ret, dbGroup *group, int (*filter)(void *data, char *path), void *fdata) {
size_t i = 0;
size_t len;
dbPair *p;
@@ -340,7 +356,8 @@ dblistkeys_p(char ***ret, dbGroup *group) {
}
for (p = group->pairs, len = 0; p; p = p->next)
- len++;
+ if (!filter || filter(fdata, p->key))
+ len++;
*ret = malloc(len * sizeof(char *));
if (!*ret) {
@@ -348,18 +365,24 @@ dblistkeys_p(char ***ret, dbGroup *group) {
return 0;
}
for (p = group->pairs; p && i < len; p = p->next)
- *((*ret) + i++) = p->key ? strdup(p->key) : NULL;
+ if (!filter || filter(fdata, p->key))
+ *((*ret) + i++) = p->key ? strdup(p->key) : NULL;
return len;
}
size_t
-dblistkeys(char ***ret, char *dir, char *group) {
+dblistkeys_f(char ***ret, char *dir, char *group, int (*filter)(void *data, char *path), void *fdata) {
dbGroup *p;
if (!(p = dbgetgroup_p(dir, group, 0))) {
*ret = NULL;
return 0;
}
- return dblistkeys_p(ret, p);
+ return dblistkeys_p(ret, p, filter, fdata);
+}
+
+size_t
+dblistkeys(char ***ret, char *dir, char *group) {
+ return dblistkeys_f(ret, dir, group, NULL, NULL);
}
/*
diff --git a/db/db.h b/db/db.h
@@ -8,6 +8,9 @@
*/
/* Set *ret to a list of groups, and return the length of the list.
+ * The _f variant accepts a filter function (zero = ignore entry):
+ * dblistgroups(..., ...) is equivalent to dblistgroups_f(..., ..., NULL, NULL)
+ * The pointer fdata is passed to the filter function.
* On failure, set *ret to NULL, and return 0;
* The data returned by this function must be free'd using dblistfree()
* Errors may be those of scandir(3) or:
@@ -15,8 +18,12 @@
* ENOMEM allocation function failed
*/
size_t dblistgroups(char ***ret, char *dir);
+size_t dblistgroups_f(char ***ret, char *dir, int (*filter)(void *data, char *path), void *fdata);
/* Set *ret to a list of keys, and return the length of the list.
+ * The _f variant accepts a filter function (zero = ignore entry):
+ * dblistkeys(..., ...) is equivalent to dblistkeys_f(..., ..., NULL, NULL)
+ * The pointer fdata is passed to the filter function.
* On failure, set *ret to NULL, and return 0;
* The data returned by this function must be free'd using dblistfree()
* Errors:
@@ -25,6 +32,7 @@ size_t dblistgroups(char ***ret, char *dir);
* ENOMEM allocation function failed
*/
size_t dblistkeys(char ***ret, char *dir, char *group);
+size_t dblistkeys_f(char ***ret, char *dir, char *group, int (*filter)(void *data, char *path), void *fdata);
/* Returns a duplicated list, or NULL for failure.
* The data returned by this function must be free'd using dblistfree()