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:
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;
}