iter: use scandir() for chip iterators
authorBartosz Golaszewski <bartekgola@gmail.com>
Tue, 31 Oct 2017 15:00:21 +0000 (16:00 +0100)
committerBartosz Golaszewski <bartekgola@gmail.com>
Tue, 31 Oct 2017 15:10:05 +0000 (16:10 +0100)
Using scandir() instead of opendir() allows us to scan for all
gpiochip devices already when creating the iterator. This simplifies
the code and doesn't require keeping the directory open when
iterating.

Storing the array of all found GPIO chips will also make it easier if
we ever want to implement a reverse iterator (e.g. for C++ bindings).

Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
configure.ac
src/lib/iter.c

index 5f808bf025c950947689b7f040bd21a4f69e8c2a..be30b319354123038816405dd9589da6b7ed2939 100644 (file)
@@ -49,7 +49,8 @@ AC_HEADER_STDC
 AC_FUNC_MALLOC
 AC_CHECK_FUNC([ioctl], [], [FUNC_NOT_FOUND_LIB([ioctl])])
 AC_CHECK_FUNC([asprintf], [], [FUNC_NOT_FOUND_LIB([asprintf])])
-AC_CHECK_FUNC([readdir], [], [FUNC_NOT_FOUND_LIB([readdir])])
+AC_CHECK_FUNC([scandir], [], [FUNC_NOT_FOUND_LIB([scandir])])
+AC_CHECK_FUNC([alphasort], [], [FUNC_NOT_FOUND_LIB([alphasort])])
 AC_CHECK_FUNC([ppoll], [], [FUNC_NOT_FOUND_LIB([ppoll])])
 AC_CHECK_HEADERS([getopt.h], [], [HEADER_NOT_FOUND_LIB([getopt.h])])
 AC_CHECK_HEADERS([dirent.h], [], [HEADER_NOT_FOUND_LIB([dirent.h])])
index abcfaeae5d6161a242fa1d814af0a9cd167d99f6..1362932b0b28b37af828718a3ea445c87bfc3751 100644 (file)
@@ -22,15 +22,25 @@ enum {
 };
 
 struct gpiod_chip_iter {
-       DIR *dir;
-       struct gpiod_chip *current;
+       struct dirent **dirs;
+       unsigned int num_dirs;
+
+       unsigned int offset;
        int state;
+       struct gpiod_chip *current;
+
        char *failed_chip;
 };
 
+static int dir_filter(const struct dirent *dir)
+{
+       return !strncmp(dir->d_name, "gpiochip", 8);
+}
+
 struct gpiod_chip_iter * gpiod_chip_iter_new(void)
 {
        struct gpiod_chip_iter *new;
+       int rv;
 
        new = malloc(sizeof(*new));
        if (!new)
@@ -38,10 +48,14 @@ struct gpiod_chip_iter * gpiod_chip_iter_new(void)
 
        memset(new, 0, sizeof(*new));
 
-       new->dir = opendir("/dev");
-       if (!new->dir)
+       rv = scandir("/dev", &new->dirs, dir_filter, alphasort);
+       if (rv < 0) {
+               free(new);
                return NULL;
+       }
 
+       new->num_dirs = rv;
+       new->offset = 0;
        new->state = CHIP_ITER_INIT;
 
        return new;
@@ -57,9 +71,15 @@ void gpiod_chip_iter_free(struct gpiod_chip_iter *iter)
 
 void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter)
 {
-       closedir(iter->dir);
+       unsigned int i;
+
        if (iter->failed_chip)
                free(iter->failed_chip);
+
+       for (i = 0; i < iter->num_dirs; i++)
+               free(iter->dirs[i]);
+
+       free(iter->dirs);
        free(iter);
 }
 
@@ -76,34 +96,30 @@ struct gpiod_chip * gpiod_chip_iter_next(struct gpiod_chip_iter *iter)
 struct gpiod_chip * gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter)
 {
        struct gpiod_chip *chip;
-       struct dirent *dentry;
-       int status;
-
-       for (dentry = readdir(iter->dir);
-            dentry;
-            dentry = readdir(iter->dir)) {
-               status = strncmp(dentry->d_name, "gpiochip", 8);
-               if (status == 0) {
-                       iter->state = CHIP_ITER_INIT;
-                       if (iter->failed_chip) {
-                               free(iter->failed_chip);
-                               iter->failed_chip = NULL;
-                       }
-
-                       chip = gpiod_chip_open_by_name(dentry->d_name);
-                       if (!chip) {
-                               iter->state = CHIP_ITER_ERR;
-                               iter->failed_chip = strdup(dentry->d_name);
-                               /* No point in an error check here. */
-                       }
-
-                       iter->current = chip;
-                       return iter->current;
-               }
+       const char *dev;
+
+       if (iter->offset >= iter->num_dirs) {
+               iter->state = CHIP_ITER_DONE;
+               return NULL;
+       }
+
+       iter->state = CHIP_ITER_INIT;
+       if (iter->failed_chip) {
+               free(iter->failed_chip);
+               iter->failed_chip = NULL;
+       }
+
+       dev = iter->dirs[iter->offset++]->d_name;
+
+       chip = gpiod_chip_open_by_name(dev);
+       if (!chip) {
+               iter->state = CHIP_ITER_ERR;
+               iter->failed_chip = strdup(dev);
+               /* No point in an error check here. */
        }
 
-       iter->state = CHIP_ITER_DONE;
-       return NULL;
+       iter->current = chip;
+       return iter->current;
 }
 
 bool gpiod_chip_iter_done(struct gpiod_chip_iter *iter)