From 46df9ae5d8dee32cf5bfc8fda2d014266847e1b9 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 16:41:35 +0100 Subject: In 'void *' functions return NULL instead of 0 --- src/loader.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index 883e857..2c9d002 100644 --- a/src/loader.c +++ b/src/loader.c @@ -166,7 +166,7 @@ static void *imv_loader_bg_new_img(void *data) if(fmt == FIF_UNKNOWN) { imv_loader_error_occurred(ldr); free(path); - return 0; + return NULL; } int num_frames = 1; @@ -184,7 +184,7 @@ static void *imv_loader_bg_new_img(void *data) free(path); if(!mbmp) { imv_loader_error_occurred(ldr); - return 0; + return NULL; } num_frames = FreeImage_GetPageCount(mbmp); @@ -209,13 +209,13 @@ static void *imv_loader_bg_new_img(void *data) free(path); if(!image) { imv_loader_error_occurred(ldr); - return 0; + return NULL; } /* Check for cancellation before we convert pixel format */ if(is_thread_cancelled()) { FreeImage_Unload(image); - return 0; + return NULL; } width = FreeImage_GetWidth(bmp); @@ -236,7 +236,7 @@ static void *imv_loader_bg_new_img(void *data) FreeImage_Unload(bmp); } pthread_mutex_unlock(&ldr->lock); - return 0; + return NULL; } if(ldr->mbmp) { @@ -262,7 +262,7 @@ static void *imv_loader_bg_new_img(void *data) ldr->frame_time = (double)raw_frame_time * 0.0001; pthread_mutex_unlock(&ldr->lock); - return 0; + return NULL; } static void *imv_loader_bg_next_frame(void *data) @@ -273,7 +273,7 @@ static void *imv_loader_bg_next_frame(void *data) int num_frames = ldr->num_frames; if(num_frames < 2) { pthread_mutex_unlock(&ldr->lock); - return 0; + return NULL; } FITAG *tag = NULL; @@ -371,5 +371,5 @@ static void *imv_loader_bg_next_frame(void *data) ldr->out_is_new_image = 0; pthread_mutex_unlock(&ldr->lock); - return 0; + return NULL; } -- cgit v1.2.3 From f18c26412486598f309535f8b993d171a65375c0 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 16:52:12 +0100 Subject: Remove "imv_loader_" prefix from static functions --- src/loader.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index 2c9d002..9afeeb2 100644 --- a/src/loader.c +++ b/src/loader.c @@ -61,8 +61,8 @@ void imv_destroy_loader(struct imv_loader *ldr) } } -static void *imv_loader_bg_new_img(void *data); -static void *imv_loader_bg_next_frame(void *data); +static void *bg_new_img(void *data); +static void *bg_next_frame(void *data); void imv_loader_load_path(struct imv_loader *ldr, const char *path) { @@ -77,7 +77,7 @@ void imv_loader_load_path(struct imv_loader *ldr, const char *path) free(ldr->path); } ldr->path = strdup(path); - pthread_create(&ldr->bg_thread, NULL, &imv_loader_bg_new_img, ldr); + pthread_create(&ldr->bg_thread, NULL, &bg_new_img, ldr); pthread_mutex_unlock(&ldr->lock); } @@ -120,7 +120,7 @@ void imv_loader_load_next_frame(struct imv_loader *ldr) } /* kick off a new thread */ - pthread_create(&ldr->bg_thread, NULL, &imv_loader_bg_next_frame, ldr); + pthread_create(&ldr->bg_thread, NULL, &bg_next_frame, ldr); } void imv_loader_time_passed(struct imv_loader *ldr, double dt) @@ -140,7 +140,7 @@ void imv_loader_time_passed(struct imv_loader *ldr, double dt) } } -static void imv_loader_error_occurred(struct imv_loader *ldr) +static void error_occurred(struct imv_loader *ldr) { pthread_mutex_lock(&ldr->lock); if(ldr->out_err) { @@ -150,7 +150,7 @@ static void imv_loader_error_occurred(struct imv_loader *ldr) pthread_mutex_unlock(&ldr->lock); } -static void *imv_loader_bg_new_img(void *data) +static void *bg_new_img(void *data) { /* so we can poll for it */ block_usr1_signal(); @@ -164,7 +164,7 @@ static void *imv_loader_bg_new_img(void *data) FREE_IMAGE_FORMAT fmt = FreeImage_GetFileType(path, 0); if(fmt == FIF_UNKNOWN) { - imv_loader_error_occurred(ldr); + error_occurred(ldr); free(path); return NULL; } @@ -183,7 +183,7 @@ static void *imv_loader_bg_new_img(void *data) /* flags */ GIF_LOAD256); free(path); if(!mbmp) { - imv_loader_error_occurred(ldr); + error_occurred(ldr); return NULL; } @@ -208,7 +208,7 @@ static void *imv_loader_bg_new_img(void *data) FIBITMAP *image = FreeImage_Load(fmt, path, 0); free(path); if(!image) { - imv_loader_error_occurred(ldr); + error_occurred(ldr); return NULL; } @@ -265,7 +265,7 @@ static void *imv_loader_bg_new_img(void *data) return NULL; } -static void *imv_loader_bg_next_frame(void *data) +static void *bg_next_frame(void *data) { struct imv_loader *ldr = data; -- cgit v1.2.3 From 9ca6a56de39f4156ec0f289099513e6d57cbddbb Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 16:54:53 +0100 Subject: Declare static functions above all code --- src/loader.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index 9afeeb2..40f3802 100644 --- a/src/loader.c +++ b/src/loader.c @@ -21,6 +21,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +static void block_usr1_signal(void); +static int is_thread_cancelled(void); +static void *bg_new_img(void *data); +static void *bg_next_frame(void *data); +static void error_occurred(struct imv_loader *ldr); + static void block_usr1_signal(void) { sigset_t sigmask; @@ -61,9 +67,6 @@ void imv_destroy_loader(struct imv_loader *ldr) } } -static void *bg_new_img(void *data); -static void *bg_next_frame(void *data); - void imv_loader_load_path(struct imv_loader *ldr, const char *path) { /* cancel existing thread if already running */ -- cgit v1.2.3 From 1665390ee94a160618b2bfdeeb1d7b993ee8a264 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 17:29:05 +0100 Subject: Sort static functions --- src/loader.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/loader.c b/src/loader.c index 40f3802..71c0e84 100644 --- a/src/loader.c +++ b/src/loader.c @@ -143,16 +143,6 @@ void imv_loader_time_passed(struct imv_loader *ldr, double dt) } } -static void error_occurred(struct imv_loader *ldr) -{ - pthread_mutex_lock(&ldr->lock); - if(ldr->out_err) { - free(ldr->out_err); - } - ldr->out_err = strdup(ldr->path); - pthread_mutex_unlock(&ldr->lock); -} - static void *bg_new_img(void *data) { /* so we can poll for it */ @@ -376,3 +366,13 @@ static void *bg_next_frame(void *data) pthread_mutex_unlock(&ldr->lock); return NULL; } + +static void error_occurred(struct imv_loader *ldr) +{ + pthread_mutex_lock(&ldr->lock); + if(ldr->out_err) { + free(ldr->out_err); + } + ldr->out_err = strdup(ldr->path); + pthread_mutex_unlock(&ldr->lock); +} -- cgit v1.2.3 From de41f9854ec827c5cfe89cc44c644e4c38a6faa0 Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 18:49:43 +0100 Subject: Use PATH_MAX for buffers holding paths --- src/main.c | 2 +- src/navigator.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/main.c b/src/main.c index 25ffce1..f3c197b 100644 --- a/src/main.c +++ b/src/main.c @@ -217,7 +217,7 @@ int main(int argc, char** argv) /* if the user asked us to load paths from stdin, now is the time */ if(g_options.sin) { - char buf[512]; + char buf[PATH_MAX]; while(fgets(buf, sizeof(buf), stdin)) { size_t len = strlen(buf); if(buf[len-1] == '\n') { diff --git a/src/navigator.c b/src/navigator.c index fb2a3cd..dd5124d 100644 --- a/src/navigator.c +++ b/src/navigator.c @@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "navigator.h" +#include #include #include #include @@ -84,7 +85,7 @@ static void add_item(struct imv_navigator *nav, const char *path, void imv_navigator_add(struct imv_navigator *nav, const char *path, int recursive) { - char path_buf[512]; + char path_buf[PATH_MAX]; struct stat path_info; stat(path, &path_info); if(S_ISDIR(path_info.st_mode)) { -- cgit v1.2.3 From ecca345f3ea63dfe85759311cea90227bdc4384a Mon Sep 17 00:00:00 2001 From: "Dmitrij D. Czarkoff" Date: Tue, 12 Jan 2016 21:01:30 +0100 Subject: Loading image data from standard input This commit changes processing of arguments: * When called without arguments (with or without flags), imv reads list of files from standard input. * When called with "-" among arguments, read image data from standard input. --- doc/imv.1 | 24 ++++++++++++++++----- src/loader.c | 57 ++++++++++++++++++++++++++++++++++++++++++-------- src/loader.h | 6 +++++- src/main.c | 68 +++++++++++++++++++++++++++++++++++++++++------------------- src/util.c | 29 +++++++++++++++++++++++++- src/util.h | 3 +++ 6 files changed, 150 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/doc/imv.1 b/doc/imv.1 index cbd5c68..d883611 100644 --- a/doc/imv.1 +++ b/doc/imv.1 @@ -21,12 +21,8 @@ It supports a wide variety of image file formats, including animated gif files. .Nm reloads the current image if it detects changes to the file. .Pp -When run with argument -.Sq - , .Nm -reads the list of images from standard input. -.Pp -The options are as follows: +accepts following flags: .Bl -tag -width Ds .It Fl a Default to showing images at actual size. @@ -66,6 +62,17 @@ Setting this to zero disables slideshow mode, which is the default. .It Fl u Use nearest neighbour resampling. Recommended for pixel art. .El +.Ss Reading from standard input +When run with argument +.Sq - , +.Nm +reads image from standard input. +Argument +.Sq - +may occur among other arguments, but only once. +.Pp +If no arguments supplied, reads list of files from standard input. +.Pp .Sh CONTROLS .Bl -tag -width Ds .It Aq Cm left mouse button @@ -111,6 +118,13 @@ Increase slideshow delay by one second .It Cm T Decrease slideshow delay by one second. When delay is zero, slideshow mode is disabled. +.Sh EXAMPLES +Load all files from directory +.Pa dir : +.Pp +.Dl $ ls dir | imv +or +.Dl $ ls dir | xargs imv .Sh LEGAL This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software diff --git a/src/loader.c b/src/loader.c index 71c0e84..1250289 100644 --- a/src/loader.c +++ b/src/loader.c @@ -17,6 +17,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "loader.h" #include "texture.h" +#include #include #include #include @@ -67,7 +68,8 @@ void imv_destroy_loader(struct imv_loader *ldr) } } -void imv_loader_load_path(struct imv_loader *ldr, const char *path) +void imv_loader_load(struct imv_loader *ldr, const char *path, + const void *buffer, const size_t buffer_size) { /* cancel existing thread if already running */ if(ldr->bg_thread) { @@ -80,6 +82,12 @@ void imv_loader_load_path(struct imv_loader *ldr, const char *path) free(ldr->path); } ldr->path = strdup(path); + if (strncmp(path, "-", 2) == 0) { + ldr->buffer = (BYTE *)buffer; + ldr->buffer_size = buffer_size; + } else if (ldr->fi_buffer != NULL) { + FreeImage_CloseMemory(ldr->fi_buffer); + } pthread_create(&ldr->bg_thread, NULL, &bg_new_img, ldr); pthread_mutex_unlock(&ldr->lock); } @@ -149,16 +157,31 @@ static void *bg_new_img(void *data) block_usr1_signal(); struct imv_loader *ldr = data; + char path[PATH_MAX] = "-"; pthread_mutex_lock(&ldr->lock); - char *path = strdup(ldr->path); + int from_stdin = !strncmp(path, ldr->path, 2); + if(!from_stdin) { + (void)snprintf(path, PATH_MAX, "%s", ldr->path); + } pthread_mutex_unlock(&ldr->lock); - FREE_IMAGE_FORMAT fmt = FreeImage_GetFileType(path, 0); - + FREE_IMAGE_FORMAT fmt; + if (from_stdin) { + pthread_mutex_lock(&ldr->lock); + ldr->fi_buffer = FreeImage_OpenMemory(ldr->buffer, ldr->buffer_size); + fmt = FreeImage_GetFileTypeFromMemory(ldr->fi_buffer, 0); + pthread_mutex_unlock(&ldr->lock); + } else { + fmt = FreeImage_GetFileType(path, 0); + } if(fmt == FIF_UNKNOWN) { + if (from_stdin) { + pthread_mutex_lock(&ldr->lock); + FreeImage_CloseMemory(ldr->fi_buffer); + pthread_mutex_unlock(&ldr->lock); + } error_occurred(ldr); - free(path); return NULL; } @@ -169,12 +192,18 @@ static void *bg_new_img(void *data) int raw_frame_time = 100; /* default to 100 */ if(fmt == FIF_GIF) { - mbmp = FreeImage_OpenMultiBitmap(FIF_GIF, path, + if(from_stdin) { + pthread_mutex_lock(&ldr->lock); + mbmp = FreeImage_LoadMultiBitmapFromMemory(FIF_GIF, ldr->fi_buffer, + GIF_LOAD256); + pthread_mutex_unlock(&ldr->lock); + } else { + mbmp = FreeImage_OpenMultiBitmap(FIF_GIF, path, /* don't create file */ 0, /* read only */ 1, /* keep in memory */ 1, /* flags */ GIF_LOAD256); - free(path); + } if(!mbmp) { error_occurred(ldr); return NULL; @@ -198,10 +227,20 @@ static void *bg_new_img(void *data) } else { /* Future TODO: If we load image line-by-line we could stop loading large * ones before wasting much more time/memory on them. */ - FIBITMAP *image = FreeImage_Load(fmt, path, 0); - free(path); + FIBITMAP *image; + if(from_stdin) { + pthread_mutex_lock(&ldr->lock); + image = FreeImage_LoadFromMemory(fmt, ldr->fi_buffer, 0); + pthread_mutex_unlock(&ldr->lock); + } else { + image = FreeImage_Load(fmt, path, 0); + } if(!image) { error_occurred(ldr); + pthread_mutex_lock(&ldr->lock); + FreeImage_CloseMemory(ldr->fi_buffer); + ldr->fi_buffer = NULL; + pthread_mutex_unlock(&ldr->lock); return NULL; } diff --git a/src/loader.h b/src/loader.h index 65c8689..6e20349 100644 --- a/src/loader.h +++ b/src/loader.h @@ -28,6 +28,9 @@ struct imv_loader { pthread_mutex_t lock; pthread_t bg_thread; char *path; + BYTE *buffer; + size_t buffer_size; + FIMEMORY *fi_buffer; FIBITMAP *out_bmp; int out_is_new_image; char *out_err; @@ -48,7 +51,8 @@ void imv_init_loader(struct imv_loader *img); void imv_destroy_loader(struct imv_loader *img); /* Asynchronously load the given file */ -void imv_loader_load_path(struct imv_loader *ldr, const char *path); +void imv_loader_load(struct imv_loader *ldr, const char *path, + const void *buffer, const size_t buffer_size); /* Returns 1 if image data is available. 0 if not. Caller is responsible for * cleaning up the data returned. Each image is only returned once. diff --git a/src/main.c b/src/main.c index f3c197b..7ba55ec 100644 --- a/src/main.c +++ b/src/main.c @@ -24,6 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include +#include #include "loader.h" #include "texture.h" @@ -33,7 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. struct { int fullscreen; - int sin; + int stdin_list; int recursive; int actual; int nearest_neighbour; @@ -49,7 +50,7 @@ struct { const char *font; } g_options = { .fullscreen = 0, - .sin = 0, + .stdin_list = 0, .recursive = 0, .actual = 0, .nearest_neighbour = 0, @@ -72,7 +73,7 @@ static void print_usage(const char* name) "Usage: %s [-rfaudlh] [-n ] [-b BG] [-e FONT:SIZE] [-t SECONDS] [-] [images...]\n" "\n" "Flags:\n" - " -: Read paths from stdin. One path per line.\n" + " -: Read image from stdin. One path per line.\n" " -r: Recursively search input paths.\n" " -f: Start in fullscreen mode\n" " -a: Default to images' actual size\n" @@ -137,8 +138,8 @@ static void parse_args(int argc, char** argv) switch(o) { case 'f': g_options.fullscreen = 1; break; case 'i': - g_options.sin = 1; - fprintf(stderr, "Warning: '-i' is deprecated. Just use '-' instead.\n"); + g_options.stdin_list = 1; + fprintf(stderr, "Warning: '-i' is deprecated. No flag is needed.\n"); break; case 'r': g_options.recursive = 1; break; case 'a': g_options.actual = 1; break; @@ -193,30 +194,22 @@ static void parse_args(int argc, char** argv) int main(int argc, char** argv) { - if(argc < 2) { - print_usage(argv[0]); - exit(1); - } - struct imv_navigator nav; imv_navigator_init(&nav); /* parse any command line options given */ parse_args(argc, argv); - /* handle any image paths given as arguments */ - for(int i = optind; i < argc; ++i) { - /* special case: '-' is actually an option */ - if(!strcmp("-",argv[i])) { - g_options.sin = 1; - continue; - } - /* add the given path to the list to load */ - imv_navigator_add(&nav, argv[i], g_options.recursive); + argc -= optind; + argv += optind; + + /* if no names are given, expect them on stdin */ + if(argc == 0) { + g_options.stdin_list = 1; } /* if the user asked us to load paths from stdin, now is the time */ - if(g_options.sin) { + if(g_options.stdin_list) { char buf[PATH_MAX]; while(fgets(buf, sizeof(buf), stdin)) { size_t len = strlen(buf); @@ -229,6 +222,30 @@ int main(int argc, char** argv) } } + void *stdin_buffer = NULL; + size_t stdin_buffer_size = 0; + int stdin_error = 0; + + /* handle any image paths given as arguments */ + for(int i = 0; i < argc; ++i) { + /* special case: '-' is actually an option */ + if(!strcmp("-",argv[i])) { + if (stdin_buffer) { + fprintf(stderr, "Can't read from stdin twice\n"); + exit(1); + } + stdin_buffer_size = read_from_stdin(&stdin_buffer); + if (stdin_buffer_size == 0) { + perror(NULL); + continue; /* we can't recover from the freed buffer, just ignore it */ + } + stdin_error = errno; + errno = 0; /* clear errno */ + } + /* add the given path to the list to load */ + imv_navigator_add(&nav, argv[i], g_options.recursive); + } + /* if we weren't given any paths we have nothing to view. exit */ if(!imv_navigator_selection(&nav)) { fprintf(stderr, "No input files. Exiting.\n"); @@ -435,6 +452,15 @@ int main(int argc, char** argv) char *err_path = imv_loader_get_error(&ldr); if(err_path) { imv_navigator_remove(&nav, err_path); + if (strncmp(err_path, "-", 2) == 0) { + free(stdin_buffer); + stdin_buffer_size = 0; + if (stdin_error != 0) { + errno = stdin_error; + perror("Failed to load image from standard input"); + errno = 0; + } + } free(err_path); } @@ -451,7 +477,7 @@ int main(int argc, char** argv) nav.cur_path + 1, nav.num_paths, current_path); imv_viewport_set_title(&view, title); - imv_loader_load_path(&ldr, current_path); + imv_loader_load(&ldr, current_path, stdin_buffer, stdin_buffer_size); view.playing = 1; } diff --git a/src/util.c b/src/util.c index dac23d4..0a15238 100644 --- a/src/util.c +++ b/src/util.c @@ -16,9 +16,36 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "util.h" - +#include +#include +#include #include +size_t read_from_stdin(void **buffer) { + size_t len = 0; + ssize_t r; + size_t step = 1024; /* Arbitrary value of 1 KiB */ + void *p; + + errno = 0; /* clear errno */ + + for(*buffer = NULL; (*buffer = realloc((p = *buffer), len + step)); + len += (size_t)r) { + if((r = read(STDIN_FILENO, (uint8_t *)*buffer + len, step)) <= 0) { + break; + } + } + + /* realloc(3) leaves old buffer allocated in case of error */ + if(*buffer == NULL && p != NULL) { + int save = errno; + free(p); + errno = save; + len = 0; + } + return len; +} + TTF_Font *load_font(const char *font_spec) { int font_size; diff --git a/src/util.h b/src/util.h index 3625a6c..09d5554 100644 --- a/src/util.h +++ b/src/util.h @@ -21,6 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +/* Read binary data from stdin into buffer */ +size_t read_from_stdin(void **buffer); + /* Creates a new SDL_Texture* containing a chequeboard texture */ SDL_Texture *create_chequered(SDL_Renderer *renderer); -- cgit v1.2.3