aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBert <ber.t@gmx.com>2011-04-08 10:23:42 +0200
committerBert <ber.t@gmx.com>2011-04-08 10:23:42 +0200
commita90bd1c833b3475e434bd2de95ab9dd0347f1780 (patch)
treea7500bd675b360719eaf0f9e4b3727b864991864
parente9996882cb55c5b6974a3448f29bda32d6aa373d (diff)
Refactored recursive directory util functions
-rw-r--r--Makefile2
-rw-r--r--main.c36
-rw-r--r--util.c178
-rw-r--r--util.h17
4 files changed, 139 insertions, 94 deletions
diff --git a/Makefile b/Makefile
index d814b2a..274ae1e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
all: sxiv
-VERSION=git-20110407
+VERSION=git-20110408
CC?=gcc
PREFIX?=/usr/local
diff --git a/main.c b/main.c
index 76da7fa..51d97d4 100644
--- a/main.c
+++ b/main.c
@@ -92,11 +92,15 @@ int load_image(int new) {
return ret;
}
+int fncmp(const void *a, const void *b) {
+ return strcoll(*((char* const*) a), *((char* const*) b));
+}
+
int main(int argc, char **argv) {
- int i, j;
+ int i, start;
const char *filename;
- char **fnames;
struct stat fstats;
+ r_dir_t dir;
parse_options(argc, argv);
@@ -121,18 +125,26 @@ int main(int argc, char **argv) {
} else {
for (i = 0; i < options->filecnt; ++i) {
filename = options->filenames[i];
- if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
- if (options->recursive && (fnames = read_dir_rec(filename))) {
- for (j = 0; fnames[j]; ++j) {
- if (!check_append(fnames[j]))
- free(fnames[j]);
- }
- free(fnames);
- } else {
+
+ if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) {
+ check_append(filename);
+ } else {
+ if (!options->recursive) {
warn("ignoring directory: %s", filename);
+ continue;
}
- } else {
- check_append(filename);
+ if (r_opendir(&dir, filename)) {
+ warn("could not open directory: %s", filename);
+ continue;
+ }
+ start = fileidx;
+ while ((filename = r_readdir(&dir))) {
+ if (!check_append(filename))
+ free((void*) filename);
+ }
+ r_closedir(&dir);
+ if (fileidx - start > 1)
+ qsort(filenames + start, fileidx - start, sizeof(char*), fncmp);
}
}
}
diff --git a/util.c b/util.c
index a8ebe73..e16de94 100644
--- a/util.c
+++ b/util.c
@@ -18,7 +18,6 @@
#include <stdlib.h>
#include <string.h>
-#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -28,7 +27,6 @@
#include "util.h"
#define DNAME_CNT 512
-#define FNAME_CNT 1024
#define FNAME_LEN 1024
void cleanup();
@@ -161,7 +159,105 @@ end:
return path;
}
-int create_dir_rec(const char *path) {
+int r_opendir(r_dir_t *rdir, const char *dirname) {
+ if (!rdir || !dirname || !*dirname)
+ return -1;
+
+ if (!(rdir->dir = opendir(dirname))) {
+ rdir->name = NULL;
+ rdir->stack = NULL;
+ return -1;
+ }
+
+ rdir->stcap = DNAME_CNT;
+ rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
+ rdir->stlen = 0;
+
+ rdir->name = (char*) dirname;
+ rdir->d = 0;
+
+ return 0;
+}
+
+int r_closedir(r_dir_t *rdir) {
+ int ret = 0;
+
+ if (!rdir)
+ return -1;
+
+ if (rdir->stack) {
+ while (rdir->stlen > 0)
+ free(rdir->stack[--rdir->stlen]);
+ free(rdir->stack);
+ rdir->stack = NULL;
+ }
+
+ if (rdir->dir) {
+ if (!(ret = closedir(rdir->dir)))
+ rdir->dir = NULL;
+ }
+
+ if (rdir->d && rdir->name) {
+ free(rdir->name);
+ rdir->name = NULL;
+ }
+
+ return ret;
+}
+
+char* r_readdir(r_dir_t *rdir) {
+ size_t len;
+ char *filename;
+ struct dirent *dentry;
+ struct stat fstats;
+
+ if (!rdir || !rdir->dir || !rdir->name)
+ return NULL;
+
+ while (1) {
+ if (rdir->dir && (dentry = readdir(rdir->dir))) {
+ if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
+ continue;
+
+ len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
+ filename = (char*) s_malloc(len);
+ snprintf(filename, len, "%s%s%s", rdir->name,
+ rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
+ dentry->d_name);
+
+ if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
+ /* put subdirectory on the stack */
+ if (rdir->stlen == rdir->stcap) {
+ rdir->stcap *= 2;
+ rdir->stack = (char**) s_realloc(rdir->stack,
+ rdir->stcap * sizeof(char*));
+ }
+ rdir->stack[rdir->stlen++] = filename;
+ continue;
+ }
+ return filename;
+ }
+
+ if (rdir->stlen > 0) {
+ /* open next subdirectory */
+ closedir(rdir->dir);
+ if (rdir->d)
+ free(rdir->name);
+ rdir->name = rdir->stack[--rdir->stlen];
+ rdir->d = 1;
+ if (!(rdir->dir = opendir(rdir->name)))
+ warn("could not open directory: %s", rdir->name);
+ continue;
+ }
+
+ /* no more entries */
+ break;
+ }
+
+ return NULL;
+}
+
+int r_mkdir(const char *path) {
char *dir, *d;
struct stat stats;
int err = 0;
@@ -202,82 +298,6 @@ int create_dir_rec(const char *path) {
return err;
}
-int fncmp(const void *a, const void *b) {
- return strcoll(*((char* const*) a), *((char* const*) b));
-}
-
-char** read_dir_rec(const char *dirname) {
- int dcnt, didx, fcnt, fidx;
- char **dnames, **fnames, *filename;
- unsigned char first;
- size_t len;
- DIR *dir;
- struct dirent *dentry;
- struct stat fstats;
-
- if (!dirname)
- return NULL;
-
- dcnt = DNAME_CNT;
- didx = first = 1;
- dnames = (char**) s_malloc(dcnt * sizeof(char*));
- dnames[0] = (char*) dirname;
-
- fcnt = FNAME_CNT;
- fidx = 0;
- fnames = (char**) s_malloc(fcnt * sizeof(char*));
-
- while (didx > 0) {
- dirname = dnames[--didx];
- if (!(dir = opendir(dirname))) {
- warn("could not open directory: %s", dirname);
- } else {
- while ((dentry = readdir(dir))) {
- if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
- continue;
-
- len = strlen(dirname) + strlen(dentry->d_name) + 2;
- filename = (char*) s_malloc(len * sizeof(char));
- snprintf(filename, len, "%s%s%s", dirname,
- dirname[strlen(dirname)-1] == '/' ? "" : "/", dentry->d_name);
-
- if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
- if (didx == dcnt) {
- dcnt *= 2;
- dnames = (char**) s_realloc(dnames, dcnt * sizeof(char*));
- }
- dnames[didx++] = filename;
- } else {
- if (fidx + 1 == fcnt) {
- fcnt *= 2;
- fnames = (char**) s_realloc(fnames, fcnt * sizeof(char*));
- }
- fnames[fidx++] = filename;
- }
- }
- closedir(dir);
- }
-
- if (!first)
- free((void*) dirname);
- else
- first = 0;
- }
-
- if (!fidx) {
- free(fnames);
- fnames = NULL;
- } else {
- if (fidx > 1)
- qsort(fnames, fidx, sizeof(char*), fncmp);
- fnames[fidx] = NULL;
- }
-
- free(dnames);
-
- return fnames;
-}
-
char* readline(FILE *stream) {
size_t len;
char *buf, *s, *end;
diff --git a/util.h b/util.h
index 34e9b18..8e8a20d 100644
--- a/util.h
+++ b/util.h
@@ -21,6 +21,7 @@
#include <stdio.h>
#include <stdarg.h>
+#include <dirent.h>
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
@@ -35,6 +36,16 @@
(tv)->tv_usec = (ts)->tv_nsec / 1000; \
}
+typedef struct {
+ DIR *dir;
+ char *name;
+ int d;
+
+ char **stack;
+ int stcap;
+ int stlen;
+} r_dir_t;
+
void* s_malloc(size_t);
void* s_realloc(void*, size_t);
@@ -45,8 +56,10 @@ void size_readable(float*, const char**);
char* absolute_path(const char*);
-int create_dir_rec(const char*);
-char** read_dir_rec(const char*);
+int r_opendir(r_dir_t*, const char*);
+int r_closedir(r_dir_t*);
+char* r_readdir(r_dir_t*);
+int r_mkdir(const char *);
char* readline(FILE*);