From: Bartosz Golaszewski Date: Tue, 31 Oct 2017 15:00:21 +0000 (+0100) Subject: iter: use scandir() for chip iterators X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=643538eb560246757d8241ae3ff7d453ad6ff648;p=qemu-gpiodev%2Flibgpiod.git iter: use scandir() for chip iterators 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 --- diff --git a/configure.ac b/configure.ac index 5f808bf..be30b31 100644 --- a/configure.ac +++ b/configure.ac @@ -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])]) diff --git a/src/lib/iter.c b/src/lib/iter.c index abcfaea..1362932 100644 --- a/src/lib/iter.c +++ b/src/lib/iter.c @@ -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)