From c21a3e3f28a5c45497d09ab27d71538b983ca535 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 7 Apr 2011 14:33:57 +0200 Subject: Write thumbnail cache files on exit --- util.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) (limited to 'util.c') diff --git a/util.c b/util.c index 5c5737b..f2302fd 100644 --- a/util.c +++ b/util.c @@ -18,11 +18,13 @@ #include #include +#include +#include #include "options.h" #include "util.h" -#define FNAME_LEN 512 +#define FNAME_LEN 1024 void cleanup(); @@ -78,6 +80,82 @@ void size_readable(float *size, const char **unit) { *unit = units[MIN(i, LEN(units) - 1)]; } +char* absolute_path(const char *filename) { + size_t len; + char *path = NULL; + const char *basename; + char *dirname = NULL; + char *cwd = NULL; + char *twd = NULL; + char *dir; + char *s; + + if (!filename || *filename == '\0' || *filename == '/') + return NULL; + + len = FNAME_LEN; + cwd = (char*) s_malloc(len); + while (!(s = getcwd(cwd, len)) && errno == ERANGE) { + len *= 2; + cwd = (char*) s_realloc(cwd, len); + } + if (!s) + goto error; + + s = strrchr(filename, '/'); + if (s) { + len = s - filename; + dirname = (char*) s_malloc(len + 1); + strncpy(dirname, filename, len); + dirname[len] = '\0'; + basename = s + 1; + + if (chdir(cwd)) + /* we're not able to come back afterwards */ + goto error; + if (chdir(dirname)) + goto error; + + len = FNAME_LEN; + twd = (char*) s_malloc(len); + while (!(s = getcwd(twd, len)) && errno == ERANGE) { + len *= 2; + twd = (char*) s_realloc(twd, len); + } + if (chdir(cwd)) + die("could not revert to working directory"); + if (!s) + goto error; + dir = twd; + } else { + /* only a single filename given */ + basename = filename; + dir = cwd; + } + + len = strlen(dir) + strlen(basename) + 2; + path = (char*) s_malloc(len); + snprintf(path, len, "%s/%s", dir, basename); + +goto end; + +error: + if (path) { + free(path); + path = NULL; + } + +end: + if (dirname) + free(dirname); + if (cwd) + free(cwd); + if (twd) + free(twd); + + return path; +} + char* readline(FILE *stream) { size_t len; char *buf, *s, *end; -- cgit v1.2.3-70-g09d2 From f93f4d887cb17fe4d7e702cbf71a4f10b851b32f Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 7 Apr 2011 16:17:10 +0200 Subject: Write cache file for thumbnail directly after creating it --- thumbs.c | 20 +++++++++++--------- util.c | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'util.c') diff --git a/thumbs.c b/thumbs.c index 80c2361..bbfda7b 100644 --- a/thumbs.c +++ b/thumbs.c @@ -47,17 +47,12 @@ void tns_init(tns_t *tns, int cnt) { void tns_free(tns_t *tns, win_t *win) { int i; - Bool cache; if (!tns || !tns->thumbs) return; - cache = tns_cache_enabled(); - for (i = 0; i < tns->cnt; ++i) { if (tns->thumbs[i].im) { - if (cache) - tns_cache_write(&tns->thumbs[i], False); imlib_context_set_image(tns->thumbs[i].im); imlib_free_image(); } @@ -69,6 +64,7 @@ void tns_free(tns_t *tns, win_t *win) { void tns_load(tns_t *tns, win_t *win, int n, const char *filename) { int w, h; + int use_cache, cached = 0; float z, zw, zh; thumb_t *t; Imlib_Image *im; @@ -88,8 +84,12 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) { imlib_free_image(); } - if ((tns_cache_enabled() && (im = tns_cache_load(filename))) || - (im = imlib_load_image(filename))) + if ((use_cache = tns_cache_enabled())) { + if ((im = tns_cache_load(filename))) + cached = 1; + } + + if (cached || (im = imlib_load_image(filename))) imlib_context_set_image(im); else imlib_context_set_image(im_invalid); @@ -115,6 +115,8 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) { die("could not allocate memory"); if (im) imlib_free_image_and_decache(); + if (use_cache && !cached) + tns_cache_write(t, False); tns->dirty = 1; } @@ -334,7 +336,7 @@ char* tns_cache_filename(const char *filename) { } len = strlen(abspath); - for (i = 1; i < len; ++i) { + for (i = 0; i < len; ++i) { if (abspath[i] == '/') abspath[i] = '%'; } @@ -392,7 +394,7 @@ void tns_cache_write(thumb_t *t, Bool force) { imlib_save_image_with_error_return(cfile, &err); if (err) { - warn("could not cache thumbnail:", t->filename); + warn("could not cache thumbnail: %s", t->filename); } else { TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim); TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim); diff --git a/util.c b/util.c index f2302fd..517b4ba 100644 --- a/util.c +++ b/util.c @@ -123,7 +123,7 @@ char* absolute_path(const char *filename) { twd = (char*) s_realloc(twd, len); } if (chdir(cwd)) - die("could not revert to working directory"); + die("could not revert to prior working directory"); if (!s) goto error; dir = twd; -- cgit v1.2.3-70-g09d2 From 92709b2b2f579300b1c007e5a3ba869e78fcc922 Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 7 Apr 2011 17:29:59 +0200 Subject: Use directory structure in cache dir --- thumbs.c | 27 ++++++++++++++------------- util.c | 43 +++++++++++++++++++++++++++++++++++++++++++ util.h | 1 + 3 files changed, 58 insertions(+), 13 deletions(-) (limited to 'util.c') diff --git a/thumbs.c b/thumbs.c index 6b37526..820fd4b 100644 --- a/thumbs.c +++ b/thumbs.c @@ -327,7 +327,6 @@ int tns_cache_enabled() { char* tns_cache_filename(const char *filename) { size_t len; - int i; char *cfile, *abspath; if (!cache_dir || !filename) @@ -341,13 +340,7 @@ char* tns_cache_filename(const char *filename) { strcpy(abspath, filename); } - len = strlen(abspath); - for (i = 0; i < len; ++i) { - if (abspath[i] == '/') - abspath[i] = '%'; - } - - len += strlen(cache_dir) + 6; + len = strlen(cache_dir) + strlen(abspath) + 6; cfile = (char*) s_malloc(len); snprintf(cfile, len, "%s/%s.png", cache_dir, abspath + 1); @@ -380,10 +373,10 @@ Imlib_Image* tns_cache_load(const char *filename) { } void tns_cache_write(thumb_t *t, Bool force) { - char *cfile; + char *cfile, *dirend; struct stat cstats, fstats; struct timeval times[2]; - Imlib_Load_Error err; + Imlib_Load_Error err = 0; if (!t || !t->im || !t->filename) return; @@ -395,9 +388,17 @@ void tns_cache_write(thumb_t *t, Bool force) { cstats.st_mtim.tv_sec != fstats.st_mtim.tv_sec || cstats.st_mtim.tv_nsec != fstats.st_mtim.tv_nsec) { - imlib_context_set_image(t->im); - imlib_image_set_format("png"); - imlib_save_image_with_error_return(cfile, &err); + if ((dirend = strrchr(cfile, '/'))) { + *dirend = '\0'; + err = create_dir_rec(cfile); + *dirend = '/'; + } + + if (!err) { + imlib_context_set_image(t->im); + imlib_image_set_format("png"); + imlib_save_image_with_error_return(cfile, &err); + } if (err) { warn("could not cache thumbnail: %s", t->filename); diff --git a/util.c b/util.c index 517b4ba..42d1384 100644 --- a/util.c +++ b/util.c @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include @@ -156,6 +158,47 @@ end: return path; } +int create_dir_rec(const char *path) { + char *dir, *d; + struct stat stats; + int err = 0; + + if (!path || !*path) + return -1; + + if (!stat(path, &stats)) { + if (S_ISDIR(stats.st_mode)) { + return 0; + } else { + warn("not a directory: %s", path); + return -1; + } + } + + d = dir = (char*) s_malloc(strlen(path) + 1); + strcpy(dir, path); + + while (d != NULL && !err) { + d = strchr(d + 1, '/'); + if (d != NULL) + *d = '\0'; + if (access(dir, F_OK) && errno == ENOENT) { + if (mkdir(dir, 0755)) { + warn("could not create directory: %s", dir); + err = -1; + } + } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) { + warn("not a directory: %s", dir); + err = -1; + } + if (d != NULL) + *d = '/'; + } + free(dir); + + return err; +} + char* readline(FILE *stream) { size_t len; char *buf, *s, *end; diff --git a/util.h b/util.h index e3cdef9..b6efd5a 100644 --- a/util.h +++ b/util.h @@ -44,6 +44,7 @@ void die(const char*, ...); void size_readable(float*, const char**); char* absolute_path(const char*); +int create_dir_rec(const char*); char* readline(FILE*); -- cgit v1.2.3-70-g09d2 From e9996882cb55c5b6974a3448f29bda32d6aa373d Mon Sep 17 00:00:00 2001 From: Bert Date: Thu, 7 Apr 2011 19:15:00 +0200 Subject: Moved read_dir_rec into util.c --- main.c | 86 ++++++++---------------------------------------------------------- util.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 2 ++ 3 files changed, 91 insertions(+), 76 deletions(-) (limited to 'util.c') diff --git a/main.c b/main.c index 7d9a8a5..76da7fa 100644 --- a/main.c +++ b/main.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -48,7 +47,6 @@ typedef enum { void update_title(); int check_append(const char*); -void read_dir_rec(const char*); void run(); appmode_t mode; @@ -56,7 +54,6 @@ img_t img; tns_t tns; win_t win; -#define DNAME_CNT 512 #define FNAME_CNT 1024 const char **filenames; int filecnt, fileidx; @@ -96,8 +93,9 @@ int load_image(int new) { } int main(int argc, char **argv) { - int i; + int i, j; const char *filename; + char **fnames; struct stat fstats; parse_options(argc, argv); @@ -124,10 +122,15 @@ int main(int argc, char **argv) { for (i = 0; i < options->filecnt; ++i) { filename = options->filenames[i]; if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) { - if (options->recursive) - read_dir_rec(filename); - else + 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 { warn("ignoring directory: %s", filename); + } } else { check_append(filename); } @@ -215,75 +218,6 @@ int check_append(const char *filename) { } } -int fncmp(const void *a, const void *b) { - return strcoll(*((char* const*) a), *((char* const*) b)); -} - -void read_dir_rec(const char *dirname) { - char *filename; - const char **dirnames; - int dircnt, diridx; - int fcnt, fstart; - unsigned char first; - size_t len; - DIR *dir; - struct dirent *dentry; - struct stat fstats; - - if (!dirname) - return; - - dircnt = DNAME_CNT; - diridx = first = 1; - dirnames = (const char**) s_malloc(dircnt * sizeof(const char*)); - dirnames[0] = dirname; - - fcnt = 0; - fstart = fileidx; - - while (diridx > 0) { - dirname = dirnames[--diridx]; - 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 (diridx == dircnt) { - dircnt *= 2; - dirnames = (const char**) s_realloc(dirnames, - dircnt * sizeof(const char*)); - } - dirnames[diridx++] = filename; - } else { - if (check_append(filename)) - ++fcnt; - else - free(filename); - } - } - closedir(dir); - } - - if (!first) - free((void*) dirname); - else - first = 0; - } - - if (fcnt > 1) - qsort(filenames + fstart, fcnt, sizeof(char*), fncmp); - - free(dirnames); -} - #ifdef EXT_COMMANDS int run_command(const char *cline, Bool reload) { int fncnt, fnlen; diff --git a/util.c b/util.c index 42d1384..a8ebe73 100644 --- a/util.c +++ b/util.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -26,6 +27,8 @@ #include "options.h" #include "util.h" +#define DNAME_CNT 512 +#define FNAME_CNT 1024 #define FNAME_LEN 1024 void cleanup(); @@ -199,6 +202,82 @@ 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 b6efd5a..34e9b18 100644 --- a/util.h +++ b/util.h @@ -44,7 +44,9 @@ void die(const char*, ...); void size_readable(float*, const char**); char* absolute_path(const char*); + int create_dir_rec(const char*); +char** read_dir_rec(const char*); char* readline(FILE*); -- cgit v1.2.3-70-g09d2 From a90bd1c833b3475e434bd2de95ab9dd0347f1780 Mon Sep 17 00:00:00 2001 From: Bert Date: Fri, 8 Apr 2011 10:23:42 +0200 Subject: Refactored recursive directory util functions --- Makefile | 2 +- main.c | 36 ++++++++----- util.c | 178 +++++++++++++++++++++++++++++++++++---------------------------- util.h | 17 +++++- 4 files changed, 139 insertions(+), 94 deletions(-) (limited to 'util.c') 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 #include -#include #include #include #include @@ -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 #include +#include #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*); -- cgit v1.2.3-70-g09d2