blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

commit 26837582379eed2a18350a448f51865f3cd86916
parent 29716cb446111a6c0d82df08d18a1eec848d826c
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun, 29 Jan 2017 21:20:55 +0100

blind-repeat: add support for reading from stdin

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
Mman/blind-repeat.1 | 15+++++++++++++--
Msrc/blind-repeat.c | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
2 files changed, 86 insertions(+), 19 deletions(-)

diff --git a/man/blind-repeat.1 b/man/blind-repeat.1 @@ -13,8 +13,6 @@ write the a video to stdout that is a loop of the selected video. The looped video is read from the selected .IR file . -.I file -must be a regular file. The video will be repeated .I count times, or until there is no process the reads from @@ -22,6 +20,19 @@ this process's stdout if .B inf is selected instead of .IR count . +.P +.I file +must be a regular file, or +.RB ' - '. +If +.I file +is +.RB ' - ', +.B blind-repeat +will read stdin into memory; you are highly discouraged +from using this unless stdin is a single frame, or known +to only be a very small number of frames, is it can +potentially use all of the computer's memory. .SH SEE ALSO .BR blind (7), .BR blind-from-image (1) diff --git a/src/blind-repeat.c b/src/blind-repeat.c @@ -10,26 +10,15 @@ USAGE("(count | 'inf') file") -int -main(int argc, char *argv[]) +static void +repeat_regular_file(char *file, size_t count, int inf) { struct stream stream; - size_t count = 0, ptr; - ssize_t r; char buf[BUFSIZ]; - int inf = 0; - - ENOFLAGS(argc != 2); - - if (!strcmp(argv[0], "inf")) - inf = 1; - else - count = etozu_arg("the count", argv[0], 0, SIZE_MAX); - - if (inf) - einf_check_fd(STDOUT_FILENO, "<stdout>"); + size_t ptr; + ssize_t r; - stream.file = argv[1]; + stream.file = file; stream.fd = eopen(stream.file, O_RDONLY); einit_stream(&stream); if (count > SIZE_MAX / stream.frames) @@ -51,11 +40,78 @@ main(int argc, char *argv[]) if (writeall(STDOUT_FILENO, buf, (size_t)r)) { if (!inf || errno != EPIPE) eprintf("write <stdout>:"); - return 0; + return; } } } close(stream.fd); +} + +static void +repeat_stdin(size_t count, int inf) +{ + struct stream stream; + char *buf; + size_t ptr, size; + ssize_t r; + + stream.file = "<stdin>"; + stream.fd = STDIN_FILENO; + einit_stream(&stream); + if (count > SIZE_MAX / stream.frames) + eprintf("%s: video is too long\n", stream.file); + stream.frames *= count; + fprint_stream_head(stdout, &stream); + efflush(stdout, "<stdout>"); + + ptr = stream.ptr; + size = ptr < BUFSIZ ? BUFSIZ : ptr; + buf = emalloc(size); + memcpy(buf, stream.buf, ptr); + + for (;;) { + if (ptr == size) + buf = erealloc(buf, size <<= 1); + r = read(STDIN_FILENO, buf + ptr, size - ptr); + if (r < 0) + eprintf("read <stdout>:"); + if (r == 0) + break; + ptr += (size_t)r; + } + + while (inf || count--) { + if (writeall(STDOUT_FILENO, buf, ptr)) { + if (!inf || errno != EPIPE) + eprintf("write <stdout>:"); + return; + } + } + + free(buf); +} + +int +main(int argc, char *argv[]) +{ + size_t count = 0; + int inf = 0; + + ENOFLAGS(argc != 2); + + if (!strcmp(argv[0], "inf")) + inf = 1; + else + count = etozu_arg("the count", argv[0], 0, SIZE_MAX); + + if (inf) + einf_check_fd(STDOUT_FILENO, "<stdout>"); + + if (!strcmp(argv[1], "-")) + repeat_stdin(count, inf); + else + repeat_regular_file(argv[1], count, inf); + return 0; }