Merge branch 'tcache'
Conflicts: main.c
This commit is contained in:
		
						commit
						bac610ddc4
					
				
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| all: sxiv | ||||
| 
 | ||||
| VERSION=git-20110407 | ||||
| VERSION=git-20110408 | ||||
| 
 | ||||
| CC?=gcc | ||||
| PREFIX?=/usr/local | ||||
|  | ||||
| @ -36,6 +36,7 @@ sxiv supports the following command-line options: | ||||
| 
 | ||||
|     -a           Display all given files, do not filter out unsupported files | ||||
|                  (shorter startup time for long file list or slow file types) | ||||
|     -C           Remove all orphaned cache files from thumbnail cache and exit | ||||
|     -d           Scale all images to 100%, but fit large images into window | ||||
|     -F           Use size-hints to make the window fixed/floating | ||||
|     -f           Start in fullscreen mode | ||||
|  | ||||
							
								
								
									
										110
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										110
									
								
								main.c
									
									
									
									
									
								
							| @ -19,7 +19,6 @@ | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <dirent.h> | ||||
| #include <sys/select.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/time.h> | ||||
| @ -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; | ||||
| @ -95,13 +92,24 @@ 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; | ||||
| 	int i, start; | ||||
| 	const char *filename; | ||||
| 	struct stat fstats; | ||||
| 	r_dir_t dir; | ||||
| 
 | ||||
| 	parse_options(argc, argv); | ||||
| 
 | ||||
| 	if (options->clean_cache) { | ||||
| 		tns_init(&tns, 0); | ||||
| 		tns_clear_cache(&tns); | ||||
| 		exit(0); | ||||
| 	} | ||||
| 
 | ||||
| 	if (!options->filecnt) { | ||||
| 		print_usage(); | ||||
| 		exit(1); | ||||
| @ -123,13 +131,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) | ||||
| 					read_dir_rec(filename); | ||||
| 				else | ||||
| 					warn("ignoring directory: %s", filename); | ||||
| 			} else { | ||||
| 
 | ||||
| 			if (stat(filename, &fstats) || !S_ISDIR(fstats.st_mode)) { | ||||
| 				check_append(filename); | ||||
| 			} else { | ||||
| 				if (!options->recursive) { | ||||
| 					warn("ignoring directory: %s", filename); | ||||
| 					continue; | ||||
| 				} | ||||
| 				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); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -215,75 +236,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); | ||||
| } | ||||
| 
 | ||||
| #if EXT_COMMANDS | ||||
| int run_command(const char *cline, Bool reload) { | ||||
| 	int fncnt, fnlen; | ||||
|  | ||||
| @ -31,7 +31,7 @@ options_t _options; | ||||
| const options_t *options = (const options_t*) &_options; | ||||
| 
 | ||||
| void print_usage() { | ||||
| 	printf("usage: sxiv [-adFfhpqrstvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n"); | ||||
| 	printf("usage: sxiv [-aCdFfhpqrstvZ] [-g GEOMETRY] [-z ZOOM] FILES...\n"); | ||||
| } | ||||
| 
 | ||||
| void print_version() { | ||||
| @ -53,9 +53,10 @@ void parse_options(int argc, char **argv) { | ||||
| 
 | ||||
| 	_options.all = 0; | ||||
| 	_options.quiet = 0; | ||||
| 	_options.clean_cache = 0; | ||||
| 	_options.recursive = 0; | ||||
| 
 | ||||
| 	while ((opt = getopt(argc, argv, "adFfg:hpqrstvZz:")) != -1) { | ||||
| 	while ((opt = getopt(argc, argv, "aCdFfg:hpqrstvZz:")) != -1) { | ||||
| 		switch (opt) { | ||||
| 			case '?': | ||||
| 				print_usage(); | ||||
| @ -63,6 +64,9 @@ void parse_options(int argc, char **argv) { | ||||
| 			case 'a': | ||||
| 				_options.all = 1; | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 				_options.clean_cache = 1; | ||||
| 				break; | ||||
| 			case 'd': | ||||
| 				_options.scalemode = SCALE_DOWN; | ||||
| 				break; | ||||
|  | ||||
| @ -37,6 +37,7 @@ typedef struct { | ||||
| 
 | ||||
| 	unsigned char all; | ||||
| 	unsigned char quiet; | ||||
| 	unsigned char clean_cache; | ||||
| 	unsigned char recursive; | ||||
| } options_t; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										25
									
								
								sxiv.1
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								sxiv.1
									
									
									
									
									
								
							| @ -3,7 +3,7 @@ | ||||
| sxiv \- Simple (or small or suckless) X Image Viewer | ||||
| .SH SYNOPSIS | ||||
| .B sxiv | ||||
| .RB [ \-adFfhpqrstvZ ] | ||||
| .RB [ \-aCdFfhpqrstvZ ] | ||||
| .RB [ \-g | ||||
| .IR GEOMETRY ] | ||||
| .RB [ \-z | ||||
| @ -24,6 +24,9 @@ sxiv has two modes of operation: image and thumbnail mode. The default is image | ||||
| mode, in which only the current image is shown. In thumbnail mode a grid of  | ||||
| small previews is displayed, making it easy to choose an image to open. | ||||
| .P | ||||
| sxiv can also cache its thumbnails. Please see the section THUMBNAIL CACHING | ||||
| for information on how to enable this feature. | ||||
| .P | ||||
| Please note, that the fullscreen mode requires an EWMH/NetWM compliant window | ||||
| manager. | ||||
| .SH OPTIONS | ||||
| @ -33,6 +36,9 @@ Display all given files, do not filter out unsupported files. This might result | ||||
| in a much shorter startup time, when the file list is very long or contains | ||||
| large files of slow loadable types, e.g. gif and progressive jpg. | ||||
| .TP | ||||
| .B \-C | ||||
| Remove all orphaned cache files from the thumbnail cache directory and exit. | ||||
| .TP | ||||
| .B \-d | ||||
| Scale all images to 100%, but fit large images into window. | ||||
| .TP | ||||
| @ -191,6 +197,23 @@ Pan image left. | ||||
| .TP | ||||
| .B Shift+ScrollDown | ||||
| Pan image right. | ||||
| .SH THUMBNAIL CACHING | ||||
| To enable thumbnail caching, please make sure to create the directory | ||||
| .I ~/.sxiv/ | ||||
| with write permissions. sxiv will then store all thumbnails inside this | ||||
| directory, but it will not create this directory by itself. It rather uses the | ||||
| existance of this directory as an affirmation, that the user wants thumbnails | ||||
| to be cached. | ||||
| .P | ||||
| Use the command line option | ||||
| .I \-C | ||||
| to keep the cache directory clean by removing all orphaned cache files. | ||||
| Additionally, run the following command afterwards inside the cache directory | ||||
| to remove empty subdirectories: | ||||
| .P | ||||
| .RS | ||||
| find -type d -empty -delete | ||||
| .RE | ||||
| .SH AUTHORS | ||||
| .EX | ||||
| Bert Muennich <ber.t at gmx.com> | ||||
|  | ||||
							
								
								
									
										198
									
								
								thumbs.c
									
									
									
									
									
								
							
							
						
						
									
										198
									
								
								thumbs.c
									
									
									
									
									
								
							| @ -18,49 +18,214 @@ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| 
 | ||||
| #include "config.h" | ||||
| #include "thumbs.h" | ||||
| #include "util.h" | ||||
| 
 | ||||
| extern Imlib_Image *im_invalid; | ||||
| 
 | ||||
| const int thumb_dim = THUMB_SIZE + 10; | ||||
| char *cache_dir = NULL; | ||||
| 
 | ||||
| int tns_cache_enabled() { | ||||
| 	struct stat stats; | ||||
| 
 | ||||
| 	return cache_dir && !stat(cache_dir, &stats) && S_ISDIR(stats.st_mode) && | ||||
| 	       !access(cache_dir, W_OK); | ||||
| } | ||||
| 
 | ||||
| char* tns_cache_filename(const char *filename) { | ||||
| 	size_t len; | ||||
| 	char *cfile = NULL; | ||||
| 	const char *abspath; | ||||
| 
 | ||||
| 	if (!cache_dir || !filename) | ||||
| 		return NULL; | ||||
| 	 | ||||
| 	if (*filename != '/') { | ||||
| 		if (!(abspath = absolute_path(filename))) | ||||
| 			return NULL; | ||||
| 	} else { | ||||
| 		abspath = filename; | ||||
| 	} | ||||
| 
 | ||||
| 	if (strncmp(abspath, cache_dir, strlen(cache_dir))) { | ||||
| 		len = strlen(cache_dir) + strlen(abspath) + 6; | ||||
| 		cfile = (char*) s_malloc(len); | ||||
| 		snprintf(cfile, len, "%s/%s.png", cache_dir, abspath + 1); | ||||
| 	} | ||||
| 	 | ||||
| 	if (abspath != filename) | ||||
| 		free((void*) abspath); | ||||
| 
 | ||||
| 	return cfile; | ||||
| } | ||||
| 
 | ||||
| Imlib_Image* tns_cache_load(const char *filename) { | ||||
| 	char *cfile; | ||||
| 	struct stat cstats, fstats; | ||||
| 	Imlib_Image *im = NULL; | ||||
| 
 | ||||
| 	if (!filename) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if (stat(filename, &fstats)) | ||||
| 		return NULL; | ||||
| 
 | ||||
| 	if ((cfile = tns_cache_filename(filename))) { | ||||
| 		if (!stat(cfile, &cstats) && | ||||
| 		    cstats.st_mtim.tv_sec == fstats.st_mtim.tv_sec && | ||||
| 				cstats.st_mtim.tv_nsec == fstats.st_mtim.tv_nsec) | ||||
| 		{ | ||||
| 			im = imlib_load_image(cfile); | ||||
| 		} | ||||
| 		free(cfile); | ||||
| 	} | ||||
| 
 | ||||
| 	return im; | ||||
| } | ||||
| 
 | ||||
| void tns_cache_write(thumb_t *t, Bool force) { | ||||
| 	char *cfile, *dirend; | ||||
| 	struct stat cstats, fstats; | ||||
| 	struct timeval times[2]; | ||||
| 	Imlib_Load_Error err = 0; | ||||
| 
 | ||||
| 	if (!t || !t->im || !t->filename) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (stat(t->filename, &fstats)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if ((cfile = tns_cache_filename(t->filename))) { | ||||
| 		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) | ||||
| 		{ | ||||
| 			if ((dirend = strrchr(cfile, '/'))) { | ||||
| 				*dirend = '\0'; | ||||
| 				err = r_mkdir(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); | ||||
| 			} else { | ||||
| 				TIMESPEC_TO_TIMEVAL(×[0], &fstats.st_atim); | ||||
| 				TIMESPEC_TO_TIMEVAL(×[1], &fstats.st_mtim); | ||||
| 				utimes(cfile, times); | ||||
| 			} | ||||
| 		} | ||||
| 		free(cfile); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void tns_clear_cache(tns_t *tns) { | ||||
| 	int dirlen, delete; | ||||
| 	char *cfile, *filename, *tpos; | ||||
| 	r_dir_t dir; | ||||
| 
 | ||||
| 	if (!cache_dir) | ||||
| 		return; | ||||
| 	 | ||||
| 	if (r_opendir(&dir, cache_dir)) { | ||||
| 		warn("could not open thumbnail cache directory: %s", cache_dir); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	dirlen = strlen(cache_dir); | ||||
| 
 | ||||
| 	while ((cfile = r_readdir(&dir))) { | ||||
| 		filename = cfile + dirlen; | ||||
| 		delete = 0; | ||||
| 
 | ||||
| 		if ((tpos = strrchr(filename, '.'))) { | ||||
| 			*tpos = '\0'; | ||||
| 			delete = access(filename, F_OK); | ||||
| 			*tpos = '.'; | ||||
| 		} | ||||
| 
 | ||||
| 		if (delete && unlink(cfile)) | ||||
| 			warn("could not delete cache file: %s", cfile); | ||||
| 
 | ||||
| 		free(cfile); | ||||
| 	} | ||||
| 
 | ||||
| 	r_closedir(&dir); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void tns_init(tns_t *tns, int cnt) { | ||||
| 	int len; | ||||
| 	char *homedir; | ||||
| 
 | ||||
| 	if (!tns) | ||||
| 		return; | ||||
| 
 | ||||
| 	tns->cnt = tns->first = tns->sel = 0; | ||||
| 	if (cnt) { | ||||
| 		tns->thumbs = (thumb_t*) s_malloc(cnt * sizeof(thumb_t)); | ||||
| 		memset(tns->thumbs, 0, cnt * sizeof(thumb_t)); | ||||
| 	} else { | ||||
| 		tns->thumbs = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	tns->cnt = tns->first = tns->sel = 0; | ||||
| 	tns->cap = cnt; | ||||
| 	tns->dirty = 0; | ||||
| 
 | ||||
| 	if ((homedir = getenv("HOME"))) { | ||||
| 		if (cache_dir) | ||||
| 			free(cache_dir); | ||||
| 		len = strlen(homedir) + 10; | ||||
| 		cache_dir = (char*) s_malloc(len * sizeof(char)); | ||||
| 		snprintf(cache_dir, len, "%s/.sxiv", homedir); | ||||
| 	} else { | ||||
| 		warn("could not locate thumbnail cache directory"); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void tns_free(tns_t *tns, win_t *win) { | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (!tns || !tns->thumbs) | ||||
| 	if (!tns) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (tns->thumbs) { | ||||
| 		for (i = 0; i < tns->cnt; ++i) { | ||||
| 			if (tns->thumbs[i].im) { | ||||
| 				imlib_context_set_image(tns->thumbs[i].im); | ||||
| 				imlib_free_image(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		free(tns->thumbs); | ||||
| 		tns->thumbs = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cache_dir) { | ||||
| 		free(cache_dir); | ||||
| 		cache_dir = NULL; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| 	if (!tns || !win || !filename) | ||||
| 	if (!tns || !tns->thumbs || !win || !filename) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (n >= tns->cap) | ||||
| @ -75,7 +240,12 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) { | ||||
| 		imlib_free_image(); | ||||
| 	} | ||||
| 
 | ||||
| 	if ((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); | ||||
| @ -84,10 +254,12 @@ void tns_load(tns_t *tns, win_t *win, int n, const char *filename) { | ||||
| 	h = imlib_image_get_height(); | ||||
| 
 | ||||
| 	if (im) { | ||||
| 		t->filename = filename; | ||||
| 		zw = (float) THUMB_SIZE / (float) w; | ||||
| 		zh = (float) THUMB_SIZE / (float) h; | ||||
| 		z = MIN(zw, zh); | ||||
| 	} else { | ||||
| 		t->filename = NULL; | ||||
| 		z = 1.0; | ||||
| 	} | ||||
| 
 | ||||
| @ -99,6 +271,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; | ||||
| } | ||||
| @ -134,7 +308,10 @@ void tns_render(tns_t *tns, win_t *win) { | ||||
| 	int i, cnt, r, x, y; | ||||
| 	thumb_t *t; | ||||
| 
 | ||||
| 	if (!tns || !tns->dirty || !win) | ||||
| 	if (!tns || !tns->thumbs || !win) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!tns->dirty) | ||||
| 		return; | ||||
| 
 | ||||
| 	win_clear(win); | ||||
| @ -182,7 +359,7 @@ void tns_highlight(tns_t *tns, win_t *win, int n, Bool hl) { | ||||
| 	thumb_t *t; | ||||
| 	unsigned long col; | ||||
| 
 | ||||
| 	if (!tns || !win) | ||||
| 	if (!tns || !tns->thumbs || !win) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (n >= 0 && n < tns->cnt) { | ||||
| @ -205,7 +382,7 @@ void tns_highlight(tns_t *tns, win_t *win, int n, Bool hl) { | ||||
| int tns_move_selection(tns_t *tns, win_t *win, tnsdir_t dir) { | ||||
| 	int old; | ||||
| 
 | ||||
| 	if (!tns || !win) | ||||
| 	if (!tns || !tns->thumbs || !win) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	old = tns->sel; | ||||
| @ -264,7 +441,10 @@ int tns_translate(tns_t *tns, int x, int y) { | ||||
| 	int n; | ||||
| 	thumb_t *t; | ||||
| 
 | ||||
| 	if (!tns || x < tns->x || y < tns->y) | ||||
| 	if (!tns || !tns->thumbs) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	if (x < tns->x || y < tns->y) | ||||
| 		return -1; | ||||
| 
 | ||||
| 	n = tns->first + (y - tns->y) / thumb_dim * tns->cols + | ||||
|  | ||||
							
								
								
									
										3
									
								
								thumbs.h
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								thumbs.h
									
									
									
									
									
								
							| @ -32,6 +32,7 @@ typedef enum { | ||||
| 
 | ||||
| typedef struct { | ||||
| 	Imlib_Image *im; | ||||
| 	const char *filename; | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	int w; | ||||
| @ -51,6 +52,8 @@ typedef struct { | ||||
| 	unsigned char dirty; | ||||
| } tns_t; | ||||
| 
 | ||||
| void tns_clear_cache(tns_t*); | ||||
| 
 | ||||
| void tns_init(tns_t*, int); | ||||
| void tns_free(tns_t*, win_t*); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										222
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										222
									
								
								util.c
									
									
									
									
									
								
							| @ -18,11 +18,16 @@ | ||||
| 
 | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| 
 | ||||
| #include "options.h" | ||||
| #include "util.h" | ||||
| 
 | ||||
| #define FNAME_LEN 512 | ||||
| #define DNAME_CNT 512 | ||||
| #define FNAME_LEN 1024 | ||||
| 
 | ||||
| void cleanup(); | ||||
| 
 | ||||
| @ -78,6 +83,221 @@ 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 prior 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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 
 | ||||
| 	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; | ||||
|  | ||||
							
								
								
									
										23
									
								
								util.h
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								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)) | ||||
| @ -30,6 +31,21 @@ | ||||
| #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;  \ | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 
 | ||||
| @ -38,6 +54,13 @@ void die(const char*, ...); | ||||
| 
 | ||||
| void size_readable(float*, const char**); | ||||
| 
 | ||||
| char* absolute_path(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*); | ||||
| 
 | ||||
| #endif /* UTIL_H */ | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Bert
						Bert