@@ -18,6 +18,7 @@ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/time.h> | |||
#include <sys/types.h> | |||
#include <sys/stat.h> | |||
#include <unistd.h> | |||
@@ -292,6 +293,9 @@ int tns_translate(tns_t *tns, int x, int y) { | |||
return -1; | |||
} | |||
/* thumbnail caching */ | |||
int tns_cache_enabled() { | |||
int len, ret = 0; | |||
char *cpath, *homedir; | |||
@@ -309,5 +313,70 @@ int tns_cache_enabled() { | |||
return ret; | |||
} | |||
char* tns_cache_filename(const char *filename) { | |||
size_t len; | |||
int i; | |||
char *cfile, *abspath, *homedir; | |||
if (!filename) | |||
return NULL; | |||
if (!(homedir = getenv("HOME"))) | |||
return NULL; | |||
if (*filename != '/') { | |||
if (!(abspath = absolute_path(filename))) | |||
return NULL; | |||
} else { | |||
abspath = (char*) s_malloc(strlen(filename) + 1); | |||
strcpy(abspath, filename); | |||
} | |||
len = strlen(abspath); | |||
for (i = 1; i < len; ++i) { | |||
if (abspath[i] == '/') | |||
abspath[i] = '%'; | |||
} | |||
len += strlen(homedir) + 15; | |||
cfile = (char*) s_malloc(len); | |||
snprintf(cfile, len, "%s/.sxiv/%s.png", homedir, abspath + 1); | |||
free(abspath); | |||
return cfile; | |||
} | |||
void tns_cache_write(thumb_t *t, Bool force) { | |||
char *cfile; | |||
struct stat cstats, fstats; | |||
struct timeval times[2]; | |||
Imlib_Load_Error err; | |||
if (!t || !t->im || !t->filename) | |||
return; | |||
if ((cfile = tns_cache_filename(t->filename))) { | |||
if (stat(t->filename, &fstats)) | |||
goto end; | |||
if (force || stat(cfile, &cstats) || | |||
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 (err) { | |||
warn("could not cache thumbnail:", t->filename); | |||
} else { | |||
TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim); | |||
TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim); | |||
utimes(cfile, times); | |||
} | |||
} | |||
} | |||
end: | |||
free(cfile); | |||
} |
@@ -18,11 +18,13 @@ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <unistd.h> | |||
#include <errno.h> | |||
#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; | |||
@@ -30,6 +30,11 @@ | |||
#define TV_TO_DOUBLE(x) ((double) ((x).tv_sec) + 0.000001 * \ | |||
(double) ((x).tv_usec)) | |||
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \ | |||
(tv)->tv_sec = (ts)->tv_sec; \ | |||
(tv)->tv_usec = (ts)->tv_nsec / 1000; \ | |||
} | |||
void* s_malloc(size_t); | |||
void* s_realloc(void*, size_t); | |||
@@ -38,6 +43,8 @@ void die(const char*, ...); | |||
void size_readable(float*, const char**); | |||
char* absolute_path(const char*); | |||
char* readline(FILE*); | |||
#endif /* UTIL_H */ |