blind

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

commit b7a82c980fe7e0c1f9029b55be97422428d65d5a
parent af28793090a32460a558914d4b5379498b712302
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed, 11 Jan 2017 09:11:51 +0100

Clean up code

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

Diffstat:
MMakefile | 3++-
Msrc/arg.h | 10++++++++++
Msrc/stream.c | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/stream.h | 65++++++++++++++++++++++++++++++++---------------------------------
Msrc/util.c | 84++++++++++++++++---------------------------------------------------------------
Msrc/util.h | 108++++++++++---------------------------------------------------------------------
Asrc/util/colour.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util/efflush.h | 12++++++++++++
Asrc/util/emalloc.h | 23+++++++++++++++++++++++
Asrc/util/eopen.h | 14++++++++++++++
Asrc/util/eprintf.h | 10++++++++++
Asrc/util/fshut.h | 36++++++++++++++++++++++++++++++++++++
Asrc/util/io.h | 12++++++++++++
Asrc/util/to.h | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/vu-arithm.c | 49+++++++++----------------------------------------
Msrc/vu-colour-srgb.c | 32+++++++++-----------------------
Msrc/vu-concat.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/vu-crop.c | 52+++++++++++++++-------------------------------------
Msrc/vu-cut.c | 52+++++++++++++++-------------------------------------
Msrc/vu-dissolve.c | 46++++++++++++----------------------------------
Msrc/vu-extend.c | 51+++++++++++++--------------------------------------
Msrc/vu-flip.c | 71+++++++++++++----------------------------------------------------------
Msrc/vu-flop.c | 71++++++++++++++++++-----------------------------------------------------
Msrc/vu-from-image.c | 26+++++++-------------------
Msrc/vu-invert-luma.c | 42++++++++----------------------------------
Msrc/vu-next-frame.c | 43++++++++++++-------------------------------
Msrc/vu-read-head.c | 29+++++++----------------------
Msrc/vu-repeat.c | 50+++++++++++++-------------------------------------
Msrc/vu-reverse.c | 39++++++++-------------------------------
Msrc/vu-set-alpha.c | 42++++++++----------------------------------
Msrc/vu-set-luma.c | 50+++++++++-----------------------------------------
Msrc/vu-set-saturation.c | 42++++++++----------------------------------
Msrc/vu-single-colour.c | 41++++++++++++++---------------------------
Msrc/vu-split.c | 28++++++----------------------
Msrc/vu-stack.c | 34++++++++--------------------------
Msrc/vu-to-image.c | 34++++++++--------------------------
Msrc/vu-transpose.c | 81++++++++++++++++++++-----------------------------------------------------------
Msrc/vu-write-head.c | 23+++++------------------
38 files changed, 745 insertions(+), 1024 deletions(-)

diff --git a/Makefile b/Makefile @@ -32,10 +32,11 @@ all: $(BIN) %: %.o util.o stream.o $(CC) $(LDFLAGS) -o $@ $^ -%.o: src/%.c src/*.h +%.o: src/%.c src/*.h src/*/*.h $(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $< clean: -rm $(BIN) $(BIN:=.o) util.o stream.o .PHONY: all clean +.PRECIOUS: util.o stream.o diff --git a/src/arg.h b/src/arg.h @@ -75,4 +75,14 @@ extern char *argv0; #define LNGARG() &argv[0][0] +#define EARG() EARGF(usage()) + +#define ENOFLAGS(...) ARGBEGIN {\ + default:\ + usage();\ + } ARGEND;\ + if (__VA_ARGS__)\ + usage() + + #endif diff --git a/src/stream.c b/src/stream.c @@ -4,6 +4,7 @@ #include <sys/stat.h> #include <errno.h> +#include <inttypes.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -133,7 +134,60 @@ eninf_check_fd(int status, int fd, const char *file) { struct stat st; if (fstat(fd, &st)) - eprintf("fstat %s:", file); + enprintf(status, "fstat %s:", file); if (S_ISREG(st.st_mode)) - eprintf("%s is a regular file, refusing infinite write\n"); + enprintf(status, "%s is a regular file, refusing infinite write\n"); +} + + +int +check_frame_size(size_t width, size_t height, size_t pixel_size) +{ + if (!width || !height || !pixel_size) + return 1; + if (width > SIZE_MAX / height) + return 0; + if (width * height > SIZE_MAX / pixel_size) + return 0; + return 1; +} + +void +encheck_frame_size(int status, size_t width, size_t height, size_t pixel_size, const char *prefix, const char *fname) +{ + if (!check_frame_size(width, height, pixel_size)) + enprintf(status, "%s: %s%svideo frame is too large\n", + prefix ? prefix : "", (prefix && *prefix) ? " " : "", fname); +} + + +void +encheck_compat(int status, const struct stream *a, const struct stream *b) +{ + if (a->width != b->width || a->height != b->height) + eprintf("videos do not have the same geometry\n"); + if (strcmp(a->pixfmt, b->pixfmt)) + eprintf("videos use incompatible pixel formats\n"); +} + + +int +enread_frame(int status, struct stream *stream, void *buf, size_t n) +{ + char *buffer = buf; + ssize_t r; + for (; stream->ptr < n; stream->ptr += (size_t)r) { + r = read(stream->fd, buffer + stream->ptr, n - stream->ptr); + if (r < 0) { + eprintf("read %s:", stream->file); + } else if (r == 0) { + if (!stream->ptr) + break; + eprintf("%s: incomplete frame", stream->file); + } + } + if (!stream->ptr) + return 0; + stream->ptr = 0; + return 1; } diff --git a/src/stream.h b/src/stream.h @@ -2,6 +2,17 @@ #include <stddef.h> #include <stdio.h> +#define einit_stream(...) eninit_stream(1, __VA_ARGS__) +#define eset_pixel_size(...) enset_pixel_size(1, __VA_ARGS__) +#define eread_stream(...) enread_stream(1, __VA_ARGS__) +#define einf_check_fd(...) eninf_check_fd(1, __VA_ARGS__) +#define echeck_frame_size(...) encheck_frame_size(1, __VA_ARGS__) +#define echeck_compat(...) encheck_compat(1, __VA_ARGS__) +#define eread_frame(...) enread_frame(1, __VA_ARGS__) + +#define enread_row(...) enread_frame(__VA_ARGS__) +#define eread_row(...) eread_frame(__VA_ARGS__) + struct stream { size_t frames; @@ -15,42 +26,30 @@ struct stream const char *file; }; - void eninit_stream(int status, struct stream *stream); - -static inline void -einit_stream(struct stream *stream) -{ - eninit_stream(1, stream); -} - - int set_pixel_size(struct stream *stream); void enset_pixel_size(int status, struct stream *stream); - -static inline void -eset_pixel_size(struct stream *stream) -{ - enset_pixel_size(1, stream); -} - - void fprint_stream_head(FILE *fp, struct stream *stream); - - size_t enread_stream(int status, struct stream *stream, size_t n); - -static inline size_t -eread_stream(struct stream *stream, size_t n) -{ - return enread_stream(1, stream, n); -} - - void eninf_check_fd(int status, int fd, const char *file); - -static inline void -einf_check_fd(int fd, const char *file) -{ - eninf_check_fd(1, fd, file); -} +int check_frame_size(size_t width, size_t height, size_t pixel_size); +void encheck_frame_size(int status, size_t width, size_t height, size_t pixel_size, const char *prefix, const char *fname); +void encheck_compat(int status, const struct stream *a, const struct stream *b); +int enread_frame(int status, struct stream *stream, void *buf, size_t n); + +#define EACH_FRAME_SEGMENTED(stream, process)\ + do {\ + size_t size__, f__, r__, n__;\ + echeck_frame_size((stream)->width, (stream)->height, (stream)->pixel_size, 0, (stream)->file);\ + size__ = (stream)->height * (stream)->width * (stream)->pixel_size;\ + for (f__ = 0; f__ < (stream)->frames; f__++) {\ + for (n__ = size__; n__; n__ -= r__) {\ + if (!eread_stream((stream), n__))\ + eprintf("%s: file is shorter than expected\n", (stream)->file);\ + r__ = (stream)->ptr - ((stream)->ptr % (stream)->pixel_size);\ + (process)((stream), r__, f__);\ + ewriteall(STDOUT_FILENO, (stream)->buf, r__, "<stdout>");\ + memmove((stream)->buf, (stream)->buf + r__, (stream)->ptr -= r__);\ + }\ + }\ + } while (0) diff --git a/src/util.c b/src/util.c @@ -9,12 +9,16 @@ #include <stdlib.h> #include <string.h> #include <strings.h> +#include <unistd.h> char *argv0; -static void -xvprintf(const char *fmt, va_list ap) +void +weprintf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + if (argv0 && strncmp(fmt, "usage", strlen("usage"))) fprintf(stderr, "%s: ", argv0); @@ -24,39 +28,7 @@ xvprintf(const char *fmt, va_list ap) fputc(' ', stderr); perror(NULL); } -} -void -eprintf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - xvprintf(fmt, ap); - va_end(ap); - - exit(1); -} - -void -enprintf(int status, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - xvprintf(fmt, ap); - va_end(ap); - - exit(status); -} - -void -weprintf(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - xvprintf(fmt, ap); va_end(ap); } @@ -132,39 +104,17 @@ erange: int -fshut(FILE *fp, const char *fname) +writeall(int fd, void *buf, size_t n) { - int ret = 0; - - /* fflush() is undefined for input streams by ISO C, - * but not POSIX 2008 if you ignore ISO C overrides. - * Leave it unchecked and rely on the following - * functions to detect errors. - */ - fflush(fp); - - if (ferror(fp) && !ret) { - weprintf("ferror %s:", fname); - ret = 1; - } - - if (fclose(fp) && !ret) { - weprintf("fclose %s:", fname); - ret = 1; + char *buffer = buf; + size_t ptr = 0; + ssize_t r; + while (ptr < n) { + r = write(STDOUT_FILENO, buffer, n); + if (r < 0) + return -1; + buffer += (size_t)ptr; + n -= (size_t)ptr; } - - return ret; -} - -void -enfshut(int status, FILE *fp, const char *fname) -{ - if (fshut(fp, fname)) - exit(status); -} - -void -efshut(FILE *fp, const char *fname) -{ - enfshut(1, fp, fname); + return 0; } diff --git a/src/util.h b/src/util.h @@ -1,99 +1,17 @@ /* See LICENSE file for copyright and license details. */ -#include <errno.h> -#include <math.h> -#include <stdio.h> -#include <stdlib.h> - -#define D65_XYY_X 0.312726871026564878786047074755 -#define D65_XYY_Y 0.329023206641284038376227272238 +#include "arg.h" #define ELEMENTSOF(ARRAY) (sizeof(ARRAY) / sizeof(*(ARRAY))) -void eprintf(const char *fmt, ...); -void enprintf(int status, const char *fmt, ...); -void weprintf(const char *fmt, ...); - -int tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out); -int tolli(const char *s, long long int min, long long int max, long long int *out); -#define DEF_STR_TO_INT(FNAME, INTTYPE, INTER_FNAME, INTER_INTTYPE)\ - static inline int\ - FNAME(const char *s, INTTYPE min, INTTYPE max, INTTYPE *out)\ - {\ - INTER_INTTYPE inter;\ - if (INTER_FNAME(s, (INTER_INTTYPE)min, (INTER_INTTYPE)max, &inter))\ - return -1;\ - *out = (INTTYPE)inter;\ - return 0;\ - } -DEF_STR_TO_INT(tolu, unsigned long int, tollu, unsigned long long int) -DEF_STR_TO_INT(tou, unsigned int, tollu, unsigned long long int) -DEF_STR_TO_INT(toli, long int, tolli, long long int) -DEF_STR_TO_INT(toi, int, tolli, long long int) -#undef DEF_STR_TO_INT -#define tozu tolu -#define tozi toli -#define toju tollu -#define toji tolli - -static inline int -tolf(const char *s, double *out) -{ - char *end; - errno = 0; - *out = strtod(s, &end); - if (errno) { - return -1; - } else if (*end) { - errno = EINVAL; - return -1; - } - return 0; -} - -int fshut(FILE *fp, const char *fname); -void enfshut(int status, FILE *fp, const char *fname); -void efshut(FILE *fp, const char *fname); - -static inline double -srgb_encode(double t) -{ - double sign = 1; - if (t < 0) { - t = -t; - sign = -1; - } - t = t <= 0.0031306684425217108 ? 12.92 * t : 1.055 * pow(t, 1 / 2.4) - 0.055; - return t * sign; -} - -static inline double -srgb_decode(double t) -{ - double sign = 1; - if (t < 0) { - t = -t; - sign = -1; - } - t = t <= 0.0031306684425217108 * 12.92 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4); - return t * sign; -} - -static inline void -ciexyz_to_srgb(double x, double y, double z, double *r, double *g, double *b) -{ -#define MULTIPLY(CX, CY, CZ) ((CX) * x + (CY) * y + (CZ) * z) - *r = MULTIPLY(3.240446254647737500675930277794, -1.537134761820080575134284117667, -0.498530193022728718155178739835); - *g = MULTIPLY(-0.969266606244679751469561779231, 1.876011959788370209167851498933, 0.041556042214430065351304932619); - *b = MULTIPLY(0.055643503564352832235773149705, -0.204026179735960239147729566866, 1.057226567722703292062647051353); -#undef MULTIPLY -} - -static inline void -srgb_to_ciexyz(double r, double g, double b, double *x, double *y, double *z) -{ -#define MULTIPLY(CR, CG, CB) ((CR) * r + (CG) * g + (CB) * b) - *x = MULTIPLY(0.412457445582367576708548995157, 0.357575865245515878143578447634, 0.180437247826399665973085006954); - *y = MULTIPLY(0.212673370378408277403536885686, 0.715151730491031756287156895269, 0.072174899130559869164791564344); - *z = MULTIPLY(0.019333942761673460208893260415, 0.119191955081838593666354597644, 0.950302838552371742508739771438); -#undef MULTIPLY -} +#define USAGE(SYNOPSIS)\ + static void usage(void)\ + { eprintf("usage: %s%s%s\n", argv0, SYNOPSIS ? " " : "", SYNOPSIS); } + +#include "util/eprintf.h" +#include "util/efflush.h" +#include "util/fshut.h" +#include "util/eopen.h" +#include "util/emalloc.h" +#include "util/to.h" +#include "util/colour.h" +#include "util/io.h" diff --git a/src/util/colour.h b/src/util/colour.h @@ -0,0 +1,49 @@ +/* See LICENSE file for copyright and license details. */ +#include <math.h> + +#define D65_XYY_X 0.312726871026564878786047074755 +#define D65_XYY_Y 0.329023206641284038376227272238 + +static inline double +srgb_encode(double t) +{ + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.0031306684425217108 ? 12.92 * t : 1.055 * pow(t, 1 / 2.4) - 0.055; + return t * sign; +} + +static inline double +srgb_decode(double t) +{ + double sign = 1; + if (t < 0) { + t = -t; + sign = -1; + } + t = t <= 0.0031306684425217108 * 12.92 ? t / 12.92 : pow((t + 0.055) / 1.055, 2.4); + return t * sign; +} + +static inline void +ciexyz_to_srgb(double x, double y, double z, double *r, double *g, double *b) +{ +#define MULTIPLY(CX, CY, CZ) ((CX) * x + (CY) * y + (CZ) * z) + *r = MULTIPLY(3.240446254647737500675930277794, -1.537134761820080575134284117667, -0.498530193022728718155178739835); + *g = MULTIPLY(-0.969266606244679751469561779231, 1.876011959788370209167851498933, 0.041556042214430065351304932619); + *b = MULTIPLY(0.055643503564352832235773149705, -0.204026179735960239147729566866, 1.057226567722703292062647051353); +#undef MULTIPLY +} + +static inline void +srgb_to_ciexyz(double r, double g, double b, double *x, double *y, double *z) +{ +#define MULTIPLY(CR, CG, CB) ((CR) * r + (CG) * g + (CB) * b) + *x = MULTIPLY(0.412457445582367576708548995157, 0.357575865245515878143578447634, 0.180437247826399665973085006954); + *y = MULTIPLY(0.212673370378408277403536885686, 0.715151730491031756287156895269, 0.072174899130559869164791564344); + *z = MULTIPLY(0.019333942761673460208893260415, 0.119191955081838593666354597644, 0.950302838552371742508739771438); +#undef MULTIPLY +} diff --git a/src/util/efflush.h b/src/util/efflush.h @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> + +#define efflush(...) enfflush(1, __VA_ARGS__) + +static inline void +enfflush(int status, FILE *fp, const char *fname) +{ + fflush(fp); + if (ferror(fp)) + enprintf(status, "%s:", fname); +} diff --git a/src/util/emalloc.h b/src/util/emalloc.h @@ -0,0 +1,23 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdlib.h> + +#define emalloc(...) enmalloc(1, __VA_ARGS__) +#define ecalloc(...) encalloc(1, __VA_ARGS__) + +static inline void * +enmalloc(int status, size_t n) +{ + void *ptr = malloc(n); + if (!ptr) + enprintf(status, "malloc: out of memory\n"); + return ptr; +} + +static inline void * +encalloc(int status, size_t n, size_t m) +{ + void *ptr = calloc(n, m); + if (!ptr) + enprintf(status, "malloc: out of memory\n"); + return ptr; +} diff --git a/src/util/eopen.h b/src/util/eopen.h @@ -0,0 +1,14 @@ +/* See LICENSE file for copyright and license details. */ +#include <fcntl.h> + +#define eopen(...) enopen(1, __VA_ARGS__) +#define enopen(...) xenopen(__VA_ARGS__, 0) + +static inline int +xenopen(int status, const char *path, int flags, int mode, ...) +{ + int fd = open(path, flags, mode); + if (fd < 0) + enprintf(status, "open %s:", path); + return fd; +} diff --git a/src/util/eprintf.h b/src/util/eprintf.h @@ -0,0 +1,10 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdlib.h> + +void weprintf(const char *fmt, ...); + +#define eprintf(...)\ + (weprintf(__VA_ARGS__), exit(1)) + +#define enprintf(status, ...)\ + (weprintf(__VA_ARGS__), exit(status)) diff --git a/src/util/fshut.h b/src/util/fshut.h @@ -0,0 +1,36 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdio.h> + +#define efshut(...) enfshut(1, __VA_ARGS__) + +static inline int +fshut(FILE *fp, const char *fname) +{ + int ret = 0; + + /* fflush() is undefined for input streams by ISO C, + * but not POSIX 2008 if you ignore ISO C overrides. + * Leave it unchecked and rely on the following + * functions to detect errors. + */ + fflush(fp); + + if (ferror(fp) && !ret) { + weprintf("ferror %s:", fname); + ret = 1; + } + + if (fclose(fp) && !ret) { + weprintf("fclose %s:", fname); + ret = 1; + } + + return ret; +} + +static inline void +enfshut(int status, FILE *fp, const char *fname) +{ + if (fshut(fp, fname)) + exit(status); +} diff --git a/src/util/io.h b/src/util/io.h @@ -0,0 +1,12 @@ +/* See LICENSE file for copyright and license details. */ + +#define ewriteall(...) enwriteall(1, __VA_ARGS__) + +int writeall(int fd, void *buf, size_t n); + +static inline void +enwriteall(int status, int fd, void *buf, size_t n, const char *fname) +{ + if (writeall(fd, buf, n)) + enprintf(status, "write %s:", fname); +} diff --git a/src/util/to.h b/src/util/to.h @@ -0,0 +1,135 @@ +/* See LICENSE file for copyright and license details. */ +#include <errno.h> +#include <stdlib.h> + +int tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out); +int tolli(const char *s, long long int min, long long int max, long long int *out); +#define DEF_STR_TO_INT(FNAME, INTTYPE, INTER_FNAME, INTER_INTTYPE, PRI)\ + static inline int\ + FNAME(const char *s, INTTYPE min, INTTYPE max, INTTYPE *out)\ + {\ + INTER_INTTYPE inter;\ + if (INTER_FNAME(s, (INTER_INTTYPE)min, (INTER_INTTYPE)max, &inter))\ + return -1;\ + *out = (INTTYPE)inter;\ + return 0;\ + } +DEF_STR_TO_INT(tolu, unsigned long int, tollu, unsigned long long int, "lu") +DEF_STR_TO_INT(tou, unsigned int, tollu, unsigned long long int, "u") +DEF_STR_TO_INT(toli, long int, tolli, long long int, "li") +DEF_STR_TO_INT(toi, int, tolli, long long int, "i") +#undef DEF_STR_TO_INT +#define tozu tolu +#define tozi toli +#define toju tollu +#define toji tolli + +#define DEF_STR_TO_INT(FNAME, TYPE, PRI)\ + static inline TYPE\ + en##FNAME##_flag(int status, int flag, const char *s, TYPE min, TYPE max)\ + {\ + TYPE ret = 0;\ + if (!FNAME(s, min, max, &ret))\ + enprintf(status,\ + "argument of -%c must be an integer in [%"PRI", %"PRI"]\n",\ + flag, min, max);\ + return ret;\ + }\ + \ + static inline TYPE\ + e##FNAME##_flag(int flag, const char *s, TYPE min, TYPE max)\ + {\ + return en##FNAME##_flag(1, flag, s, min, max);\ + }\ + \ + static inline TYPE\ + en##FNAME##_arg(int status, const char *name, const char *s, TYPE min, TYPE max)\ + {\ + TYPE ret = 0;\ + if (!FNAME(s, min, max, &ret))\ + enprintf(status,\ + "%s must be an integer in [%"PRI", %"PRI"]\n",\ + name, min, max);\ + return ret;\ + }\ + \ + static inline TYPE\ + e##FNAME##_arg(const char *name, const char *s, TYPE min, TYPE max)\ + {\ + return en##FNAME##_arg(1, name, s, min, max);\ + } +DEF_STR_TO_INT(tollu, unsigned long long int, "llu") +DEF_STR_TO_INT(tolu, unsigned long int, "lu") +DEF_STR_TO_INT(tou, unsigned int, "u") +DEF_STR_TO_INT(tolli, long long int, "lli") +DEF_STR_TO_INT(toli, long int, "li") +DEF_STR_TO_INT(toi, int, "i") +#undef DEF_STR_TO_INT + +#define etozu_flag etolu_flag +#define etozi_flag etoli_flag +#define etoju_flag etollu_flag +#define etoji_flag etolli_flag +#define entozu_flag entolu_flag +#define entozi_flag entoli_flag +#define entoju_flag entollu_flag +#define entoji_flag entolli_flag + +#define etozu_arg etolu_arg +#define etozi_arg etoli_arg +#define etoju_arg etollu_arg +#define etoji_arg etolli_arg +#define entozu_arg entolu_arg +#define entozi_arg entoli_arg +#define entoju_arg entollu_arg +#define entoji_arg entolli_arg + +#define DEF_STR_TO_FLOAT(FNAME, TYPE, FUN)\ + static inline int\ + FNAME(const char *s, TYPE *out)\ + {\ + char *end;\ + errno = 0;\ + *out = FUN(s, &end);\ + if (errno) {\ + return -1;\ + } else if (*end) {\ + errno = EINVAL;\ + return -1;\ + }\ + return 0;\ + }\ + \ + static inline TYPE\ + en##FNAME##_flag(int status, int flag, const char *s)\ + {\ + TYPE ret = 0;\ + if (!FNAME(s, &ret))\ + enprintf(status, "argument of -%c must be floating-point value\n", flag);\ + return ret;\ + }\ + \ + static inline TYPE\ + e##FNAME##_flag(int flag, const char *s)\ + {\ + return en##FNAME##_flag(1, flag, s);\ + }\ + \ + static inline TYPE\ + en##FNAME##_arg(int status, const char *name, const char *s)\ + {\ + TYPE ret = 0;\ + if (!FNAME(s, &ret))\ + enprintf(status, "%s must be floating-point value\n", name);\ + return ret;\ + }\ + \ + static inline TYPE\ + e##FNAME##_arg(const char *name, const char *s)\ + {\ + return en##FNAME##_arg(1, name, s);\ + } +DEF_STR_TO_FLOAT(tof, float, strtof) +DEF_STR_TO_FLOAT(tolf, double, strtod) +DEF_STR_TO_FLOAT(tollf, long double, strtold) +#undef DEF_STR_TO_FLOAT diff --git a/src/vu-arithm.c b/src/vu-arithm.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -9,15 +8,11 @@ #include <string.h> #include <unistd.h> +USAGE("right-hand-stream") + /* Because the syntax for a function returning a function pointer is disgusting. */ typedef void (*process_func)(struct stream *left, struct stream *right, size_t n); -static void -usage(void) -{ - eprintf("usage: %s operation right-hand-stream\n", argv0); -} - #define LIST_OPERATORS\ X(add, *lh += rh)\ X(sub, *lh -= rh)\ @@ -64,32 +59,20 @@ main(int argc, char *argv[]) { struct stream left; struct stream right; - ssize_t r; - size_t i, n; + size_t n; process_func process = NULL; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 2) - usage(); + ENOFLAGS(argc != 2); left.file = "<stdin>"; left.fd = STDIN_FILENO; einit_stream(&left); right.file = argv[1]; - right.fd = open(right.file, O_RDONLY); - if (right.fd < 0) - eprintf("open %s:", right.file); + right.fd = eopen(right.file, O_RDONLY); einit_stream(&right); - if (left.width != right.width || left.height != right.height) - eprintf("videos do not have the same geometry\n"); - if (left.pixel_size != right.pixel_size) - eprintf("videos use incompatible pixel formats\n"); + echeck_compat(&left, &right); if (!strcmp(left.pixfmt, "xyza")) process = get_lf_process(argv[0]); @@ -115,12 +98,7 @@ main(int argc, char *argv[]) process(&left, &right, n); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, left.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - + ewriteall(STDOUT_FILENO, left.buf, n, "<stdout>"); if ((n & 3) || left.ptr != right.ptr) { memmove(left.buf, left.buf + n, left.ptr); memmove(right.buf, right.buf + n, right.ptr); @@ -130,11 +108,7 @@ main(int argc, char *argv[]) if (right.fd >= 0) close(right.fd); - for (i = 0; i < left.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, left.buf + i, left.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, left.buf, left.ptr, "<stdout>"); if (left.fd >= 0) { for (;;) { @@ -144,12 +118,7 @@ main(int argc, char *argv[]) left.fd = -1; break; } - - for (i = 0; i < left.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, left.buf + i, left.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, left.buf, left.ptr, "<stdout>"); } } diff --git a/src/vu-colour-srgb.c b/src/vu-colour-srgb.c @@ -1,25 +1,18 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "util.h" -static void -usage(void) -{ - eprintf("usage: %s [-d depth] [-l] red green blue\n", argv0); -} +USAGE("[-d depth] [-l] red green blue") int main(int argc, char *argv[]) { unsigned long long int max; double red, green, blue, X, Y, Z; - int depth = 8; - int linear = 0; + int depth = 8, linear = 0; ARGBEGIN { case 'd': - if (toi(EARGF(usage()), 1, 64, &depth)) - eprintf("argument of -d must be an integer in [1, 64]\n"); + depth = etoi_flag('d', EARG(), 1, 64); break; case 'l': linear = 1; @@ -31,18 +24,11 @@ main(int argc, char *argv[]) if (argc != 3) usage(); - if (tolf(argv[0], &red)) - eprintf("the X value must be a floating-point value\n"); - if (tolf(argv[1], &green)) - eprintf("the Y value must be a floating-point value\n"); - if (tolf(argv[2], &blue)) - eprintf("the Z value must be a floating-point value\n"); - - max = 1ULL << (depth - 1); - max |= max - 1; - red /= max; - green /= max; - blue /= max; + max = 1ULL << (depth - 1); + max |= max - 1; + red = etolf_arg("the red value", argv[0]) / max; + green = etolf_arg("the green value", argv[1]) / max; + blue = etolf_arg("the blue value", argv[2]) / max; if (!linear) { red = srgb_decode(red); green = srgb_decode(green); @@ -51,7 +37,7 @@ main(int argc, char *argv[]) srgb_to_ciexyz(red, green, blue, &X, &Y, &Z); printf("%lf %lf %lf\n", X, Y, Z); - efshut(stdout, "<stdout>"); + efshut(stdout, "<stdout>"); return 0; } diff --git a/src/vu-concat.c b/src/vu-concat.c @@ -1,53 +1,30 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" +#include <sys/mman.h> #include <fcntl.h> #include <inttypes.h> #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s first-stream ... last-stream\n", argv0); -} +USAGE("[-o output-file] first-stream ... last-stream") -int -main(int argc, char *argv[]) +static void +concat_to_stdout(int argc, char *argv[]) { struct stream *streams; - size_t ptr, frames = 0; - ssize_t r; + size_t frames = 0; int i; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc < 2) - usage(); - - streams = malloc((size_t)argc * sizeof(*streams)); - if (!streams) - eprintf("malloc:"); + streams = emalloc((size_t)argc * sizeof(*streams)); for (i = 0; i < argc; i++) { streams[i].file = argv[i]; - streams[i].fd = open(streams[i].file, O_RDONLY); - if (streams[i].fd < 0) - eprintf("open %s:", streams[i].file); + streams[i].fd = eopen(streams[i].file, O_RDONLY); einit_stream(streams + i); - - if (i) { - if (streams[i].width != streams->width || streams[i].height != streams->height) - eprintf("videos do not have the same geometry\n"); - if (strcmp(streams[i].pixfmt, streams->pixfmt)) - eprintf("videos use incompatible pixel formats\n"); - } - + if (i) + echeck_compat(streams + i, streams); if (streams[i].frames > SIZE_MAX - frames) eprintf("resulting video is too long\n"); frames += streams[i].frames; @@ -55,20 +32,79 @@ main(int argc, char *argv[]) streams->frames = frames; fprint_stream_head(stdout, streams); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); - for (i = 0; i < argc; i++) { - for (; eread_stream(streams + i, SIZE_MAX); streams[i].ptr = 0) { - for (ptr = 0; ptr < streams[i].ptr; ptr += (size_t)r) { - r = write(STDOUT_FILENO, streams[i].buf + ptr, streams[i].ptr - ptr); - if (r < 0) - eprintf("write <stdout>:"); - } + for (; argc--; streams++) { + for (; eread_stream(streams, SIZE_MAX); streams->ptr = 0) + ewriteall(STDOUT_FILENO, streams->buf, streams->ptr, "<stdout>"); + close(streams->fd); + } +} + +static void +concat_to_file(int argc, char *argv[], char *output_file) +{ + struct stream stream, refstream; + int first = 0; + int fd = eopen(output_file, O_RDWR | O_CREAT | O_TRUNC, 0666); + char head[3 * sizeof(size_t) + 4 + sizeof(stream.pixfmt) + 6]; + ssize_t headlen, size = 0; + char *data; + + for (; argc--; argv++) { + stream.file = *argv; + stream.fd = eopen(stream.file, O_RDONLY); + einit_stream(&stream); + + if (first) { + stream = refstream; + } else { + if (refstream.frames > SIZE_MAX - stream.frames) + eprintf("resulting video is too long\n"); + refstream.frames += stream.frames; + echeck_compat(&stream, &refstream); + } + + for (; eread_stream(&stream, SIZE_MAX); stream.ptr = 0) { + ewriteall(STDOUT_FILENO, stream.buf, stream.ptr, "<stdout>"); + size += stream.ptr; } - close(streams[i].fd); + close(stream.fd); } + sprintf(head, "%zu %zu %zu %s\n%cuivf%zn", + stream.frames, stream.width, stream.height, stream.pixfmt, 0, &headlen); + + ewriteall(STDOUT_FILENO, head, (size_t)headlen, "<stdout>"); + + data = mmap(0, size + (size_t)headlen, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + memmove(data + headlen, data, size); + memcpy(data, head, (size_t)headlen); + munmap(data, size + (size_t)headlen); + + close(fd); +} + +int +main(int argc, char *argv[]) +{ + char *output_file = NULL; + + ARGBEGIN { + case 'o': + output_file = EARG(); + break; + default: + usage(); + } ARGEND; + + if (argc < 2) + usage(); + + if (output_file) + concat_to_file(argc, argv, output_file); + else + concat_to_stdout(argc, argv); + return 0; } diff --git a/src/vu-crop.c b/src/vu-crop.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: [-t] width height left top %s\n", argv0); -} +USAGE("[-t] width height left top") int main(int argc, char *argv[]) @@ -20,7 +15,7 @@ main(int argc, char *argv[]) struct stream stream; char *buf, *image, *p; size_t width = 0, height = 0, left = 0, top = 0; - size_t off, yoff, x, y, irown, orown, ptr, n, m; + size_t off, yoff = 0, x, y, irown, orown, ptr, n, m; ssize_t r; int tile = 0; @@ -35,14 +30,10 @@ main(int argc, char *argv[]) if (argc != 4) usage(); - if (tozu(argv[0], 1, SIZE_MAX, &width)) - eprintf("width be an integer in [1, %zu]\n", SIZE_MAX); - if (tozu(argv[1], 1, SIZE_MAX, &height)) - eprintf("height be an integer in [1, %zu]\n", SIZE_MAX); - if (tozu(argv[2], 0, SIZE_MAX, &left)) - eprintf("left position be an integer in [0, %zu]\n", SIZE_MAX); - if (tozu(argv[3], 0, SIZE_MAX, &top)) - eprintf("top position be an integer in [0, %zu]\n", SIZE_MAX); + width = etozu_arg("the width", argv[0], 1, SIZE_MAX); + height = etozu_arg("the height", argv[1], 1, SIZE_MAX); + left = etozu_arg("the left position", argv[2], 0, SIZE_MAX); + top = etozu_arg("the top position", argv[3], 0, SIZE_MAX); stream.file = "<stdin>"; stream.fd = STDIN_FILENO; @@ -58,29 +49,21 @@ main(int argc, char *argv[]) stream.width = x; stream.height = y; } - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); - if (stream.width > SIZE_MAX / stream.pixel_size) - eprintf("<stdin>: video frame is too large\n"); - n = irown = stream.width * stream.pixel_size; - if (n > SIZE_MAX / stream.height) - eprintf("<stdin>: video frame is too large\n"); - n *= stream.height; - if (!(buf = malloc(n))) - eprintf("malloc:"); + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + n = stream.height * (irown = stream.width * stream.pixel_size); + buf = emalloc(n); orown = width * stream.pixel_size; m = tile ? n : height * orown; - if (!(image = malloc(m))) - eprintf("malloc:"); + image = emalloc(m); left *= stream.pixel_size; - if (tile) { + if (!tile) { + off = top * irown; + } else { off = (orown - (left % orown)) % orown; yoff = (height - (top % height)) % height; - } else { - off = top * irown; } memcpy(buf, stream.buf, ptr = stream.ptr); for (;;) { @@ -106,14 +89,9 @@ main(int argc, char *argv[]) for (x = 0; x < irown; x++, ptr++) image[ptr++] = p[(x + off) % orown]; } - } - for (ptr = 0; ptr < m; ptr += (size_t)r) { - r = write(STDOUT_FILENO, image + ptr, m - ptr); - if (r < 0) - eprintf("write <stdout>"); - } + ewriteall(STDOUT_FILENO, image, m, "<stdout>"); } return 0; diff --git a/src/vu-cut.c b/src/vu-cut.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -9,45 +8,31 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s start-point (end-point | 'end') file\n", argv0); -} +USAGE("start-point (end-point | 'end') file") int main(int argc, char *argv[]) { struct stream stream; - size_t frame_size, start = 0, end = 0, ptr, max, n, ptw; + size_t frame_size, start = 0, end = 0, ptr, max, n; ssize_t r; char buf[BUFSIZ]; int to_end = 0; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 3) - usage(); + ENOFLAGS(argc != 3); - if (!strcmp(argv[0], "end")) { + if (!strcmp(argv[0], "end")) eprintf("refusing to create video with zero frames\n"); - } else if (tozu(argv[0], 0, SIZE_MAX, &start)) { - eprintf("the start point must be an integer in [0, %zu]\n", SIZE_MAX); - } + else + start = etozu_arg("the start point", argv[1], 0, SIZE_MAX); - if (!strcmp(argv[1], "end")) { + if (!strcmp(argv[1], "end")) to_end = 1; - } else if (tozu(argv[1], 0, SIZE_MAX, &end)) { - eprintf("the end point must be an integer in [0, %zu]\n", SIZE_MAX); - } + else + end = etozu_arg("the end point", argv[1], 0, SIZE_MAX); stream.file = argv[2]; - stream.fd = open(stream.file, O_RDONLY); - if (stream.fd < 0) - eprintf("open %s:", stream.file); + stream.fd = eopen(stream.file, O_RDONLY); einit_stream(&stream); if (to_end) end = stream.frames; @@ -55,12 +40,9 @@ main(int argc, char *argv[]) eprintf("end point is after end of video\n"); stream.frames = end - start; fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); - if (stream.width > SIZE_MAX / stream.height) - eprintf("%s: video is too large\n", stream.file); - frame_size = stream.width * stream.height; + efflush(stdout, "<stdout>"); + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + frame_size = stream.width * stream.height * stream.pixel_size; if (stream.frames > SSIZE_MAX / frame_size) eprintf("%s: video is too large\n", stream.file); @@ -68,7 +50,7 @@ main(int argc, char *argv[]) eprintf("%s\n", start > end ? "start point is after end point" : "refusing to create video with zero frames"); - end *= frame_size; + end *= frame_size; start *= frame_size; for (ptr = start; ptr < end;) { @@ -80,11 +62,7 @@ main(int argc, char *argv[]) if (r == 0) eprintf("%s: file is shorter than expected\n", stream.file); ptr += n = (size_t)r; - for (ptw = 0; ptw < n; ptw += (size_t)r) { - r = write(STDOUT_FILENO, buf + ptw, n - ptw); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, buf, n, "<stdout>"); } close(stream.fd); diff --git a/src/vu-dissolve.c b/src/vu-dissolve.c @@ -1,37 +1,35 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s [-r]\n", argv0); -} +USAGE("[-r]") + +static size_t fm; +static double fmd; static void -process_xyza(struct stream *stream, size_t n, size_t f, size_t fm) +process_xyza(struct stream *stream, size_t n, size_t f) { size_t i; double a; for (i = 0; i < n; i += stream->pixel_size) { a = ((double *)(stream->buf + i))[3]; - a = a * (double)f / fm; + a = a * (double)f / fmd; ((double *)(stream->buf + i))[3] = a; } } static void -process_xyza_r(struct stream *stream, size_t n, size_t f, size_t fm) +process_xyza_r(struct stream *stream, size_t n, size_t f) { size_t i; double a; for (i = 0; i < n; i += stream->pixel_size) { a = ((double *)(stream->buf + i))[3]; - a = a * (double)(fm - f) / fm; + a = a * (double)(fm - f) / fmd; ((double *)(stream->buf + i))[3] = a; } } @@ -41,10 +39,7 @@ main(int argc, char *argv[]) { struct stream stream; int reverse = 0; - size_t f, h, w; - size_t n, i, fm; - ssize_t r; - void (*process)(struct stream *stream, size_t n, size_t f, size_t fm) = NULL; + void (*process)(struct stream *stream, size_t n, size_t f) = NULL; ARGBEGIN { case 'r': @@ -61,32 +56,15 @@ main(int argc, char *argv[]) stream.file = "<stdin>"; einit_stream(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); if (!strcmp(stream.pixfmt, "xyza")) process = reverse ? process_xyza_r : process_xyza; else eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt); - fm = stream.frames - 1; - for (f = 0; f < stream.frames; f++) { - for (h = stream.height; h--;) { - for (w = stream.width * stream.pixel_size; w; w -= n) { - if (!eread_stream(&stream, w)) - eprintf("<stdin>: file is shorter than expected\n"); - n = stream.ptr - (stream.ptr % stream.pixel_size); - process(&stream, n, f, fm); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, stream.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - memmove(stream.buf, stream.buf + n, stream.ptr -= n); - } - } - } + fmd = fm = stream.frames - 1; + EACH_FRAME_SEGMENTED(&stream, process); return 0; } diff --git a/src/vu-extend.c b/src/vu-extend.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s [-l left] [-r right] [-a above] [-b below] [-t]\n", argv0); -} +USAGE("[-l left] [-r right] [-a above] [-b below] [-t]") int main(int argc, char *argv[]) @@ -27,20 +22,16 @@ main(int argc, char *argv[]) ARGBEGIN { case 'l': - if (tozu(EARGF(usage()), 0, SIZE_MAX, &left)) - eprintf("argument of -l must be an integer in [0, %zu]\n", SIZE_MAX); + left = etozu_flag('l', EARG(), 0, SIZE_MAX); break; case 'r': - if (tozu(EARGF(usage()), 0, SIZE_MAX, &right)) - eprintf("argument of -r must be an integer in [0, %zu]\n", SIZE_MAX); + right = etozu_flag('r', EARG(), 0, SIZE_MAX); break; case 'a': - if (tozu(EARGF(usage()), 0, SIZE_MAX, &top)) - eprintf("argument of -a must be an integer in [0, %zu]\n", SIZE_MAX); + top = etozu_flag('a', EARG(), 0, SIZE_MAX); break; case 'b': - if (tozu(EARGF(usage()), 0, SIZE_MAX, &bottom)) - eprintf("argument of -b must be an integer in [0, %zu]\n", SIZE_MAX); + bottom = etozu_flag('b', EARG(), 0, SIZE_MAX); break; case 't': tile = 1; @@ -56,14 +47,9 @@ main(int argc, char *argv[]) stream.fd = STDIN_FILENO; einit_stream(&stream); - if (stream.width > SIZE_MAX / stream.pixel_size) - eprintf("<stdin>: video frame is too large\n"); - n = stream.width * stream.pixel_size; - if (n > SIZE_MAX / stream.height) - eprintf("<stdin>: video frame is too large\n"); - n *= stream.height; - if (!(buf = malloc(n))) - eprintf("malloc:"); + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + n = stream.height * stream.width * stream.pixel_size; + buf = emalloc(n); if (stream.width > SIZE_MAX - left) eprintf("<stdout>: output video is too wide\n"); @@ -77,14 +63,9 @@ main(int argc, char *argv[]) if (imgh > SIZE_MAX - bottom) eprintf("<stdout>: output video is too tall\n"); imgh += bottom; - if (imgw > SIZE_MAX / stream.pixel_size) - eprintf("<stdout>: output video frame is too large\n"); - m = imgw *= stream.pixel_size; - if (m > SIZE_MAX / imgh) - eprintf("<stdout>: output video frame is too large\n"); - m *= imgh; - if (!(image = malloc(m))) - eprintf("malloc:"); + echeck_frame_size(imgw, imgh, stream.pixel_size, "output", "<stdout>"); + m = imgh * (imgw *= stream.pixel_size); + image = emalloc(m); if (!tile) memset(image, 0, m); @@ -92,9 +73,7 @@ main(int argc, char *argv[]) stream.width += left + right; h = stream.height += top + bottom; fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); stream.width -= left + right; stream.height -= top + bottom; @@ -133,11 +112,7 @@ main(int argc, char *argv[]) memcpy(image + y * imgw, image + (((y + yoff) % stream.height) + top) * imgw, imgw); } - for (ptr = 0; ptr < m; ptr += (size_t)r) { - r = write(STDOUT_FILENO, image + ptr, m - ptr); - if (r < 0) - eprintf("write <stdout>"); - } + ewriteall(STDOUT_FILENO, image, m, "<stdout>"); } return 0; diff --git a/src/vu-flip.c b/src/vu-flip.c @@ -1,81 +1,36 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" -#include <fcntl.h> -#include <inttypes.h> #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s\n", argv0); -} +USAGE("") int main(int argc, char *argv[]) { struct stream stream; - char *buf, *row; - size_t ptr, n, i, j, hm, row_size; - ssize_t r; - - ARGBEGIN { - default: - usage(); - } ARGEND; + size_t n, ptr, row_size; + char *buf; - if (argc) - usage(); + ENOFLAGS(argc); stream.file = "<stdin>"; stream.fd = STDIN_FILENO; einit_stream(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); - if (stream.width > SIZE_MAX / stream.pixel_size) - eprintf("<stdin>: video is too wide\n"); - row_size = stream.width * stream.pixel_size; - if (!(row = malloc(row_size))) - eprintf("malloc:"); - if (row_size > SIZE_MAX / stream.height) - eprintf("<stdin>: video frame is too large\n"); - n = row_size * stream.height; - if (!(buf = malloc(n))) - eprintf("malloc:"); + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + n = stream.height * (row_size = stream.width * stream.pixel_size); + buf = emalloc(n); - hm = stream.height - 1; - memcpy(buf, stream.buf, ptr = stream.ptr); - for (;;) { - for (; ptr < n; ptr += (size_t)r) { - r = read(stream.fd, buf + ptr, n - ptr); - if (r < 0) { - eprintf("read %s:", stream.file); - } else if (r == 0) { - if (!ptr) - break; - eprintf("%s: incomplete frame", stream.file); - } - } - if (!ptr) - break; - for (i = 0; i < stream.height >> 1; i++) { - j = hm - i; - memcpy(row, buf + i * row_size, row_size); - memcpy(buf + i * row_size, buf + j * row_size, row_size); - memcpy(buf + j * row_size, row, row_size); - } - for (ptr = 0; ptr < n; ptr += (size_t)r) { - r = write(STDOUT_FILENO, buf + ptr, n - ptr); - if (r < 0) - eprintf("write <stdout>"); - } - } + memcpy(buf, stream.buf, stream.ptr); + while (eread_frame(&stream, buf, n)) + for (ptr = n; ptr;) + ewriteall(STDOUT_FILENO, buf + (ptr -= row_size), row_size, "<stdout>"); + free(buf); return 0; } diff --git a/src/vu-flop.c b/src/vu-flop.c @@ -1,79 +1,44 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" -#include <fcntl.h> #include <inttypes.h> #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s\n", argv0); -} +USAGE("") int main(int argc, char *argv[]) { struct stream stream; - char *buf, t1, t2; - size_t ptr, n, i, j, k, wm; - ssize_t r; + char *buf, *image; + size_t i, j, n, m; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc) - usage(); + ENOFLAGS(argc); stream.file = "<stdin>"; stream.fd = STDIN_FILENO; einit_stream(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); if (stream.width > SIZE_MAX / stream.pixel_size) - eprintf("<stdin>: video is too wide\n"); + eprintf("<stdin>: video frame is too wide\n"); n = stream.width * stream.pixel_size; - if (!(buf = malloc(n))) - eprintf("malloc:"); - - wm = stream.width - 1; - memcpy(buf, stream.buf, ptr = stream.ptr); - for (;;) { - for (; ptr < n; ptr += (size_t)r) { - r = read(stream.fd, buf + ptr, n - ptr); - if (r < 0) { - eprintf("read %s:", stream.file); - } else if (r == 0) { - if (!ptr) - break; - eprintf("%s: incomplete frame", stream.file); - } - } - if (!ptr) - break; - for (i = 0; i < stream.pixel_size; i++) { - for (j = 0; j < stream.width >> 1; j++) { - k = wm - j; - t1 = buf[j * stream.pixel_size + i]; - t2 = buf[k * stream.pixel_size + i]; - buf[j * stream.pixel_size + i] = t2; - buf[k * stream.pixel_size + i] = t1; - } - } - for (ptr = 0; ptr < n; ptr += (size_t)r) { - r = write(STDOUT_FILENO, buf + ptr, n - ptr); - if (r < 0) - eprintf("write <stdout>"); - } + buf = emalloc(n); + image = emalloc(n); + + m = n - stream.pixel_size; + memcpy(buf, stream.buf, stream.ptr); + while (eread_row(&stream, buf, n)) { + for (i = 0; i < stream.pixel_size; i++) + for (j = 0; j < n; j += stream.pixel_size) + image[m - j + i] = buf[i + j]; + ewriteall(STDOUT_FILENO, image, n, "<stdout>"); } + free(buf); + free(image); return 0; } diff --git a/src/vu-from-image.c b/src/vu-from-image.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "util.h" #include <arpa/inet.h> @@ -8,6 +7,8 @@ #include <string.h> #include <unistd.h> +USAGE("[-h] [-f | -p]") + static double get_value(void *buffer) { @@ -25,21 +26,15 @@ get_value(void *buffer) return ret; } -static void -usage(void) -{ - eprintf("usage: [-h] [-f | -p] %s\n", argv0); -} - int main(int argc, char *argv[]) { int pipe_rw[2]; int i, old_fd; - pid_t pid; + pid_t pid = 0; int status; char buf[8096]; - size_t ptr, ptw, n; + size_t ptr, n; char *p; ssize_t r; double red, green, blue, pixel[4]; @@ -164,10 +159,8 @@ header_done: eprintf("%s\n", conv_fail_msg); if (!headless) { - printf("%s %s xyza\n%cuivf", width, height, 0); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + printf("1 %s %s xyza\n%cuivf", width, height, 0); + efflush(stdout, "<stdout>"); } for (;;) { @@ -178,12 +171,7 @@ header_done: pixel[3] = get_value(buf + ptr + 12); srgb_to_ciexyz(red, green, blue, pixel + 0, pixel + 1, pixel + 2); - - for (ptw = 0; ptw < sizeof(pixel); ptw += (size_t)r) { - r = write(STDOUT_FILENO, (char *)pixel + ptw, sizeof(pixel) - ptw); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, pixel, sizeof(pixel), "<stdout>"); } r = read(pipe_rw[0], buf, sizeof(buf)); if (r < 0) diff --git a/src/vu-invert-luma.c b/src/vu-invert-luma.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s [-i] mask-stream\n", argv0); -} +USAGE("[-i] mask-stream") static void process_xyza(struct stream *colour, struct stream *mask, size_t n) @@ -46,10 +41,8 @@ int main(int argc, char *argv[]) { int invert = 0; - struct stream colour; - struct stream mask; - ssize_t r; - size_t i, n; + struct stream colour, mask; + size_t n; void (*process)(struct stream *colour, struct stream *mask, size_t n) = NULL; ARGBEGIN { @@ -68,15 +61,10 @@ main(int argc, char *argv[]) einit_stream(&colour); mask.file = argv[0]; - mask.fd = open(mask.file, O_RDONLY); - if (mask.fd < 0) - eprintf("open %s:", mask.file); + mask.fd = eopen(mask.file, O_RDONLY); einit_stream(&mask); - if (colour.width != mask.width || colour.height != mask.height) - eprintf("videos do not have the same geometry\n"); - if (colour.pixel_size != mask.pixel_size) - eprintf("videos use incompatible pixel formats\n"); + echeck_compat(&colour, &mask); if (!strcmp(colour.pixfmt, "xyza")) process = invert ? process_xyza_i : process_xyza; @@ -102,12 +90,7 @@ main(int argc, char *argv[]) process(&colour, &mask, n); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - + ewriteall(STDOUT_FILENO, colour.buf, n, "<stdout>"); if ((n & 3) || colour.ptr != mask.ptr) { memmove(colour.buf, colour.buf + n, colour.ptr); memmove(mask.buf, mask.buf + n, mask.ptr); @@ -117,11 +100,7 @@ main(int argc, char *argv[]) if (mask.fd >= 0) close(mask.fd); - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); if (colour.fd >= 0) { for (;;) { @@ -131,12 +110,7 @@ main(int argc, char *argv[]) colour.fd = -1; break; } - - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); } } diff --git a/src/vu-next-frame.c b/src/vu-next-frame.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -7,40 +6,28 @@ #include <string.h> #include <unistd.h> +#undef eprintf #define eprintf(...) enprintf(2, __VA_ARGS__) -static void -usage(void) -{ - eprintf("usage: %s width height pixel-format ...\n", argv0); -} +USAGE("width height pixel-format ...") int main(int argc, char *argv[]) { struct stream stream; - size_t ptr, n, w; - ssize_t r; + size_t n, w; int i, anything = 0; char *p; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc < 3) - usage(); + ENOFLAGS(argc < 3); stream.frames = 1; stream.fd = STDIN_FILENO; stream.file = "<stdin>"; stream.pixfmt[0] = '\0'; - if (tozu(argv[0], 1, SIZE_MAX, &stream.width)) - eprintf("the width must be an integer in [1, %zu]\n", SIZE_MAX); - if (tozu(argv[1], 1, SIZE_MAX, &stream.height)) - eprintf("the height must be an integer in [1, %zu]\n", SIZE_MAX); + stream.width = etozu_arg("the width", argv[0], 1, SIZE_MAX); + stream.height = etozu_arg("the height", argv[1], 1, SIZE_MAX); argv += 2, argc -= 2; n = (size_t)argc - 1; @@ -57,28 +44,22 @@ main(int argc, char *argv[]) eset_pixel_size(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); + w = stream.width * stream.pixel_size; while (stream.height) { stream.height--; - for (w = stream.width * stream.pixel_size; w; w -= n) { + for (n = w; n; n -= stream.ptr) { stream.ptr = 0; - n = eread_stream(&stream, w); - if (n == 0) + if (!eread_stream(&stream, n)) goto done; anything = 1; - for (ptr = 0; ptr < stream.ptr; ptr += (size_t)r) { - r = write(STDOUT_FILENO, stream.buf + ptr, stream.ptr - ptr); - if (r < 0) - eprintf("write <stdin>:"); - } + ewriteall(STDOUT_FILENO, stream.buf, stream.ptr, "<stdout>"); } } done: - if (stream.height || w) + if (stream.height || n) eprintf("incomplete frame\n"); return !anything; diff --git a/src/vu-read-head.c b/src/vu-read-head.c @@ -1,34 +1,22 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" #include <ctype.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s\n", argv0); -} +USAGE("") int main(int argc, char *argv[]) { char buf[2 + 3 * sizeof(size_t) + sizeof(((struct stream *)0)->pixfmt)]; char magic[] = {'\0', 'u', 'i', 'v', 'f'}; - char b; - char *p; + char b, *p; size_t i, ptr; ssize_t r; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (!argc) - usage(); + ENOFLAGS(!argc); for (ptr = 0; ptr < sizeof(buf);) { r = read(STDIN_FILENO, buf + ptr, 1); @@ -47,11 +35,11 @@ main(int argc, char *argv[]) r = read(STDIN_FILENO, &b, 1); if (r < 0) eprintf("read <stdin>:"); - if (!r || b != magic[i]) + if (r == 0 || b != magic[i]) goto bad_format; } - for (i = 0; i < 2; i++) { + for (i = 0; i < 3; i++) { if (!isdigit(*p)) goto bad_format; while (isdigit(*p)) p++; @@ -66,13 +54,10 @@ main(int argc, char *argv[]) if (p[-1] == ' ' || p[0] != '\n') goto bad_format; - for (i = 0; i < ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, buf + i, ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, buf, ptr, "<stdout>"); return 0; bad_format: eprintf("<stdin>: file format not supported\n"); + return 0; } diff --git a/src/vu-repeat.c b/src/vu-repeat.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -9,59 +8,40 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s (count | 'inf') file\n", argv0); -} +USAGE("(count | 'inf') file") int main(int argc, char *argv[]) { struct stream stream; - size_t count = 0, ptr, n, ptw; + size_t count = 0, ptr, n; ssize_t r; char buf[BUFSIZ]; int inf = 0; - ARGBEGIN { - default: - usage(); - } ARGEND; + ENOFLAGS(argc != 2); - if (argc != 2) - usage(); - - if (!strcmp(argv[0], "inf")) { + if (!strcmp(argv[0], "inf")) inf = 1; - } else if (tozu(argv[0], 0, SIZE_MAX, &count)) { - eprintf("the count must be an integer in [0, %zu]\n", SIZE_MAX); - } + else + count = etozu_arg("the count", argv[0], 0, SIZE_MAX); if (inf) einf_check_fd(STDOUT_FILENO, "<stdout>"); stream.file = argv[1]; - stream.fd = open(stream.file, O_RDONLY); - if (stream.fd < 0) - eprintf("open %s:", stream.file); + stream.fd = eopen(stream.file, O_RDONLY); einit_stream(&stream); if (count > SIZE_MAX / stream.frames) - eprintf("%s: video too long\n", stream.file); + eprintf("%s: video is too long\n", stream.file); stream.frames *= count; fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); while (inf || count--) { posix_fadvise(stream.fd, 0, 0, POSIX_FADV_SEQUENTIAL); - for (ptw = 0; ptw < stream.ptr;) { - r = write(STDOUT_FILENO, stream.buf + ptw, stream.ptr - ptw); - if (r < 0) - goto writeerr; - ptw += (size_t)r; - } + if (writeall(STDOUT_FILENO, stream.buf, stream.ptr)) + goto writeerr; for (ptr = 0;;) { r = pread(stream.fd, buf, sizeof(buf), ptr); if (r < 0) @@ -69,12 +49,8 @@ main(int argc, char *argv[]) else if (r == 0) break; ptr += n = (size_t)r; - for (ptw = 0; ptw < n;) { - r = write(STDOUT_FILENO, buf + ptw, n - ptw); - if (r < 0) - goto writeerr; - ptw += (size_t)r; - } + if (writeall(STDOUT_FILENO, buf, n)) + goto writeerr; } } diff --git a/src/vu-reverse.c b/src/vu-reverse.c @@ -1,47 +1,29 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" -#include <fcntl.h> #include <limits.h> -#include <stdint.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s file\n", argv0); -} +USAGE("file") int main(int argc, char *argv[]) { struct stream stream; - size_t frame_size, ptr, end, n, ptw; + size_t frame_size, ptr, end, n; ssize_t r; char buf[BUFSIZ]; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 1) - usage(); + ENOFLAGS(argc != 1); stream.file = argv[0]; - stream.fd = open(stream.file, O_RDONLY); - if (stream.fd < 0) - eprintf("open %s:", stream.file); + stream.fd = eopen(stream.file, O_RDONLY); einit_stream(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); - if (stream.width > SIZE_MAX / stream.height) - eprintf("%s: video is too large\n", stream.file); - frame_size = stream.width * stream.height; + efflush(stdout, "<stdout>"); + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + frame_size = stream.width * stream.height * stream.pixel_size; if (stream.frames > SSIZE_MAX / frame_size) eprintf("%s: video is too large\n", stream.file); @@ -56,12 +38,7 @@ main(int argc, char *argv[]) else if (r == 0) eprintf("%s: file is shorter than expected\n", stream.file); ptr += n = (size_t)r; - for (ptw = 0; ptw < n;) { - r = write(STDOUT_FILENO, buf + ptw, n - ptw); - if (r < 0) - eprintf("write <stdout>:"); - ptw += (size_t)r; - } + ewriteall(STDOUT_FILENO, buf, n, "<stdout>"); } } diff --git a/src/vu-set-alpha.c b/src/vu-set-alpha.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s [-i] alpha-stream\n", argv0); -} +USAGE("[-i] alpha-stream") static void process_xyza(struct stream *colour, struct stream *alpha, size_t n) @@ -42,10 +37,8 @@ int main(int argc, char *argv[]) { int invert = 0; - struct stream colour; - struct stream alpha; - ssize_t r; - size_t i, n; + struct stream colour, alpha; + size_t n; void (*process)(struct stream *colour, struct stream *alpha, size_t n) = NULL; ARGBEGIN { @@ -64,15 +57,10 @@ main(int argc, char *argv[]) einit_stream(&colour); alpha.file = argv[0]; - alpha.fd = open(alpha.file, O_RDONLY); - if (alpha.fd < 0) - eprintf("open %s:", alpha.file); + alpha.fd = eopen(alpha.file, O_RDONLY); einit_stream(&alpha); - if (colour.width != alpha.width || colour.height != alpha.height) - eprintf("videos do not have the same geometry\n"); - if (colour.pixel_size != alpha.pixel_size) - eprintf("videos use incompatible pixel formats\n"); + echeck_compat(&colour, &alpha); if (!strcmp(colour.pixfmt, "xyza")) process = invert ? process_xyza_i : process_xyza; @@ -98,12 +86,7 @@ main(int argc, char *argv[]) process(&colour, &alpha, n); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - + ewriteall(STDOUT_FILENO, colour.buf, n, "<stdout>"); if ((n & 3) || colour.ptr != alpha.ptr) { memmove(colour.buf, colour.buf + n, colour.ptr); memmove(alpha.buf, alpha.buf + n, alpha.ptr); @@ -113,11 +96,7 @@ main(int argc, char *argv[]) if (alpha.fd >= 0) close(alpha.fd); - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); if (colour.fd >= 0) { for (;;) { @@ -127,12 +106,7 @@ main(int argc, char *argv[]) colour.fd = -1; break; } - - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); } } diff --git a/src/vu-set-luma.c b/src/vu-set-luma.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s luma-stream\n", argv0); -} +USAGE("luma-stream") static void process_xyza(struct stream *colour, struct stream *luma, size_t n) @@ -29,34 +24,21 @@ process_xyza(struct stream *colour, struct stream *luma, size_t n) int main(int argc, char *argv[]) { - struct stream colour; - struct stream luma; - ssize_t r; - size_t i, n; + struct stream colour, luma; + size_t n; void (*process)(struct stream *colour, struct stream *luma, size_t n); - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc != 1) - usage(); + ENOFLAGS(argc != 1); colour.file = "<stdin>"; colour.fd = STDIN_FILENO; einit_stream(&colour); luma.file = argv[0]; - luma.fd = open(luma.file, O_RDONLY); - if (luma.fd < 0) - eprintf("open %s:", luma.file); + luma.fd = eopen(luma.file, O_RDONLY); einit_stream(&luma); - if (colour.width != luma.width || colour.height != luma.height) - eprintf("videos do not have the same geometry\n"); - if (colour.pixel_size != luma.pixel_size) - eprintf("videos use incompatible pixel formats\n"); + echeck_compat(&colour, &luma); if (!strcmp(colour.pixfmt, "xyza")) process = process_xyza; @@ -82,12 +64,7 @@ main(int argc, char *argv[]) process(&colour, &luma, n); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - + ewriteall(STDOUT_FILENO, colour.buf, n, "<stdout>"); if ((n & 3) || colour.ptr != luma.ptr) { memmove(colour.buf, colour.buf + n, colour.ptr); memmove(luma.buf, luma.buf + n, luma.ptr); @@ -97,11 +74,7 @@ main(int argc, char *argv[]) if (luma.fd >= 0) close(luma.fd); - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); if (colour.fd >= 0) { for (;;) { @@ -111,12 +84,7 @@ main(int argc, char *argv[]) colour.fd = -1; break; } - - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); } } diff --git a/src/vu-set-saturation.c b/src/vu-set-saturation.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,11 +7,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s [-w] saturation-stream\n", argv0); -} +USAGE("[-w] saturation-stream") static void process_xyza(struct stream *colour, struct stream *satur, size_t n) @@ -51,11 +46,9 @@ process_xyza_w(struct stream *colour, struct stream *satur, size_t n) int main(int argc, char *argv[]) { - struct stream colour; - struct stream satur; + struct stream colour, satur; int whitepoint = 0; - ssize_t r; - size_t i, n; + size_t n; void (*process)(struct stream *colour, struct stream *satur, size_t n) = NULL; ARGBEGIN { @@ -74,15 +67,10 @@ main(int argc, char *argv[]) einit_stream(&colour); satur.file = argv[0]; - satur.fd = open(satur.file, O_RDONLY); - if (satur.fd < 0) - eprintf("open %s:", satur.file); + satur.fd = eopen(satur.file, O_RDONLY); einit_stream(&satur); - if (colour.width != satur.width || colour.height != satur.height) - eprintf("videos do not have the same geometry\n"); - if (colour.pixel_size != satur.pixel_size) - eprintf("videos use incompatible pixel formats\n"); + echeck_compat(&colour, &satur); if (!strcmp(colour.pixfmt, "xyza")) process = whitepoint ? process_xyza_w : process_xyza; @@ -108,12 +96,7 @@ main(int argc, char *argv[]) process(&colour, &satur, n); - for (i = 0; i < n; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, n - i); - if (r < 0) - eprintf("write <stdout>:"); - } - + ewriteall(STDOUT_FILENO, colour.buf, n, "<stdout>"); if ((n & 3) || colour.ptr != satur.ptr) { memmove(colour.buf, colour.buf + n, colour.ptr); memmove(satur.buf, satur.buf + n, satur.ptr); @@ -123,11 +106,7 @@ main(int argc, char *argv[]) if (satur.fd >= 0) close(satur.fd); - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); if (colour.fd >= 0) { for (;;) { @@ -137,12 +116,7 @@ main(int argc, char *argv[]) colour.fd = -1; break; } - - for (i = 0; i < colour.ptr; i += (size_t)r) { - r = write(STDOUT_FILENO, colour.buf + i, colour.ptr - i); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, colour.buf, colour.ptr, "<stdout>"); } } diff --git a/src/vu-single-colour.c b/src/vu-single-colour.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -7,13 +6,9 @@ #include <string.h> #include <unistd.h> -typedef double pixel_t[4]; +USAGE("[-f frames | -f 'inf'] -w width -h height (X Y Z | Y) [alpha]") -static void -usage(void) -{ - eprintf("usage: %s [-f frames | -f 'inf'] -w width -h height (X Y Z | Y) [alpha]\n", argv0); -} +typedef double pixel_t[4]; int main(int argc, char *argv[]) @@ -32,19 +27,17 @@ main(int argc, char *argv[]) ARGBEGIN { case 'f': - arg = EARGF(usage()); + arg = EARG(); if (!strcmp(arg, "inf")) inf = 1, stream.frames = 0; - else if (tozu(arg, 1, SIZE_MAX, &stream.frames)) - eprintf("argument of -f must be an integer in [1, %zu] or 'inf'\n", SIZE_MAX); + else + stream.frames = etozu_flag('f', arg, 1, SIZE_MAX); break; case 'w': - if (tozu(EARGF(usage()), 1, SIZE_MAX, &stream.width)) - eprintf("argument of -w must be an integer in [1, %zu]\n", SIZE_MAX); + stream.width = etozu_flag('w', EARG(), 1, SIZE_MAX); break; case 'h': - if (tozu(EARGF(usage()), 1, SIZE_MAX, &stream.height)) - eprintf("argument of -h must be an integer in [1, %zu]\n", SIZE_MAX); + stream.height = etozu_flag('h', EARG(), 1, SIZE_MAX); break; default: usage(); @@ -56,27 +49,21 @@ main(int argc, char *argv[]) if (argc < 3) { X = D65_XYY_X / D65_XYY_Y; Z = 1 / D65_XYY_Y - 1 - X; - if (tolf(argv[1], &Y)) - eprintf("the Y value must be a floating-point value\n"); + Y = etolf_arg("the Y value", argv[1]); } else { - if (tolf(argv[0], &X)) - eprintf("the X value must be a floating-point value\n"); - if (tolf(argv[1], &Y)) - eprintf("the Y value must be a floating-point value\n"); - if (tolf(argv[2], &Z)) - eprintf("the Z value must be a floating-point value\n"); + X = etolf_arg("the X value", argv[0]); + Y = etolf_arg("the Y value", argv[1]); + Z = etolf_arg("the Z value", argv[2]); } - if (!(argc & 1) && tolf(argv[argc - 1], &alpha)) - eprintf("the alpha value must be a floating-point value\n"); + if (~argc & 1) + alpha = etolf_arg("the alpha value", argv[argc - 1]); if (inf) einf_check_fd(STDOUT_FILENO, "<stdout>"); strcpy(stream.pixfmt, "xyza"); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); for (x = 0; x < ELEMENTSOF(buf); x++) { buf[x][0] = X; diff --git a/src/vu-split.c b/src/vu-split.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -10,11 +9,7 @@ #include <string.h> #include <unistd.h> -static void -usage(void) -{ - eprintf("usage: %s (file end-point) ...\n", argv0); -} +USAGE("(file (end-point | 'end')) ...") int main(int argc, char *argv[]) @@ -25,20 +20,13 @@ main(int argc, char *argv[]) int fd; ssize_t r; - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (argc < 2 || argc % 2) - usage(); + ENOFLAGS(argc < 2 || argc % 2); stream.file = "<stdin>"; stream.fd = STDIN_FILENO; einit_stream(&stream); - if (stream.width > SIZE_MAX / stream.height) - eprintf("%s: video is too large\n", stream.file); - frame_size = stream.width * stream.height; + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, stream.file); + frame_size = stream.width * stream.height * stream.pixel_size; if (stream.frames > SSIZE_MAX / frame_size) eprintf("%s: video is too large\n", stream.file); @@ -58,16 +46,12 @@ main(int argc, char *argv[]) ptr = 0; for (i = 0; i < parts; i++) { - fd = open(argv[i * 2], O_WRONLY); - if (fd < 0) - eprintf("open %s:", argv[i * 2]); + fd = eopen(argv[i * 2], O_WRONLY | O_CREAT | O_TRUNC, 0666); fp = fdopen(fd, "wb"); stream.frames = ends[i] - (i ? ends[i - 1] : 0); fprint_stream_head(fp, &stream); - fflush(fp); - if (ferror(fp)) - eprintf("%s:", argv[i * 2]); + efflush(fp, argv[i * 2]); for (end = ends[i] * frame_size; ptr < end; ptr += n) { for (ptw = ptr; stream.ptr && ptw < end;) { diff --git a/src/vu-stack.c b/src/vu-stack.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,6 +7,8 @@ #include <string.h> #include <unistd.h> +USAGE("[-b] bottom-stream ... top-stream") + static void process_xyza(struct stream *streams, size_t n_streams, size_t n) { @@ -65,12 +66,6 @@ process_xyza_b(struct stream *streams, size_t n_streams, size_t n) } } -static void -usage(void) -{ - eprintf("usage: %s [-b] bottom-stream ... top-stream\n", argv0); -} - int main(int argc, char *argv[]) { @@ -78,7 +73,6 @@ main(int argc, char *argv[]) size_t n_streams; int blend = 0; size_t i, j, n; - ssize_t r; size_t closed; void (*process)(struct stream *streams, size_t n_streams, size_t n) = NULL; @@ -94,21 +88,13 @@ main(int argc, char *argv[]) usage(); n_streams = (size_t)argc; - streams = calloc(n_streams, sizeof(*streams)); - if (!streams) - eprintf("calloc:"); + streams = ecalloc(n_streams, sizeof(*streams)); for (i = 0; i < n_streams; i++) { streams[i].file = argv[i]; - streams[i].fd = open(streams[i].file, O_RDONLY); - if (streams[i].fd < 0) - eprintf("open %s:", streams[i].file); - if (i) { - if (streams[i].width != streams->width || streams[i].height != streams->height) - eprintf("videos do not have the same geometry\n"); - if (strcmp(streams[i].pixfmt, streams->pixfmt)) - eprintf("videos use incompatible pixel formats\n"); - } + streams[i].fd = eopen(streams[i].file, O_RDONLY); + if (i) + echeck_compat(streams + i, streams); } if (!strcmp(streams->pixfmt, "xyza")) @@ -129,12 +115,8 @@ main(int argc, char *argv[]) n -= n % streams->pixel_size; process(streams, n_streams, n); - for (j = 0; j < n;) { - r = write(STDOUT_FILENO, streams->buf + j, n - j); - if (r < 0) - eprintf("write <stdout>:"); - j += (size_t)r; - } + + ewriteall(STDOUT_FILENO, streams->buf, n, "<stdout>"); closed = SIZE_MAX; for (i = 0; i < n_streams; i++) { diff --git a/src/vu-to-image.c b/src/vu-to-image.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -10,24 +9,18 @@ #include <string.h> #include <unistd.h> +USAGE("[-d depth | -f]") + static int luma_warning_triggered = 0; static int gamut_warning_triggered = 0; static int alpha_warning_triggered = 0; static void -usage(void) -{ - eprintf("usage: %s [-d depth | -f]\n", argv0); -} - -static void write_pixel(double R, double G, double B, double A, int bytes, unsigned long long int max) { unsigned long long int colours[4]; unsigned char buf[4 * 8]; int i, j, k, bm = bytes - 1; - size_t ptr, n; - ssize_t r; if (R < 0 || G < 0 || B < 0 || R > 1 || G > 1 || B > 1) { if (gamut_warning_triggered) { @@ -60,12 +53,7 @@ write_pixel(double R, double G, double B, double A, int bytes, unsigned long lon } } - n = (size_t)bytes * 4; - for (ptr = 0; ptr < n; ptr += (size_t)r) { - r = write(STDOUT_FILENO, buf + ptr, n - ptr); - if (r < 0) - eprintf("write <stdout>:"); - } + ewriteall(STDOUT_FILENO, buf, (size_t)bytes * 4, "<stdout>"); } static void @@ -103,8 +91,7 @@ main(int argc, char *argv[]) ARGBEGIN { case 'd': - if (toi(EARGF(usage()), 1, 64, &depth)) - eprintf("argument of -d must be an integer in [1, 64]\n"); + depth = etoi_flag('d', EARG(), 1, 64); break; case 'f': farbfeld = 1; @@ -151,18 +138,13 @@ main(int argc, char *argv[]) "TUPLTYPE RGB_ALPHA\n" "ENDHDR\n", stream.width, stream.height, max); } - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); + efflush(stdout, "<stdout>"); - for (;;) { - n = stream.ptr; - n -= n % stream.pixel_size; + do { + n = stream.ptr - (stream.ptr % stream.pixel_size); process(&stream, n, bytes, max); memmove(stream.buf, stream.buf + n, stream.ptr -= n); - if (!eread_stream(&stream, SIZE_MAX)) - break; - } + } while (eread_stream(&stream, SIZE_MAX)); return 0; } diff --git a/src/vu-transpose.c b/src/vu-transpose.c @@ -1,5 +1,4 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "stream.h" #include "util.h" @@ -8,79 +7,39 @@ #include <string.h> #include <unistd.h> -static void -transpose(const struct stream *stream, const char *restrict buf, char *restrict image) -{ - size_t x, y, i, b = 0, h, w; - w = stream->width * (h = stream->height * stream->pixel_size); - for (y = 0; y < h; y += stream->pixel_size) - for (x = 0; x < w; x += h) - for (i = 0; i < stream->pixel_size; i++) - image[x + y + i] = buf[b++]; -} - -static void -usage(void) -{ - eprintf("usage: %s\n", argv0); -} +USAGE("") int main(int argc, char *argv[]) { struct stream stream; char *buf, *image; - size_t ptr, n; - ssize_t r; - - ARGBEGIN { - default: - usage(); - } ARGEND; + size_t n, imgw, imgh, x, y, i, b; - if (argc) - usage(); + ENOFLAGS(argc); stream.file = "<stdin>"; stream.fd = STDIN_FILENO; einit_stream(&stream); fprint_stream_head(stdout, &stream); - fflush(stdout); - if (ferror(stdout)) - eprintf("<stdout>:"); - - if (stream.width > SIZE_MAX / stream.pixel_size) - eprintf("<stdin>: video frame is too large\n"); - n = stream.width * stream.pixel_size; - if (n > SIZE_MAX / stream.height) - eprintf("<stdin>: video frame is too large\n"); - n *= stream.height; - if (!(buf = malloc(n))) - eprintf("malloc:"); - if (!(image = malloc(n))) - eprintf("malloc:"); - - memcpy(buf, stream.buf, ptr = stream.ptr); - for (;;) { - for (; ptr < n; ptr += (size_t)r) { - r = read(stream.fd, buf + ptr, n - ptr); - if (r < 0) { - eprintf("read %s:", stream.file); - } else if (r == 0) { - if (!ptr) - break; - eprintf("%s: incomplete frame", stream.file); - } - } - if (!ptr) - break; - transpose(&stream, buf, image); - for (ptr = 0; ptr < n; ptr += (size_t)r) { - r = write(STDOUT_FILENO, image + ptr, n - ptr); - if (r < 0) - eprintf("write <stdout>"); - } + efflush(stdout, "<stdout>"); + + echeck_frame_size(stream.width, stream.height, stream.pixel_size, 0, "<stdin>"); + n = stream.width * stream.height * stream.pixel_size; + buf = emalloc(n); + image = emalloc(n); + + imgw = stream.width * (imgh = stream.height * stream.pixel_size); + memcpy(buf, stream.buf, stream.ptr); + while (eread_frame(&stream, buf, n)) { + for (b = y = 0; y < imgh; y += stream.pixel_size) + for (x = 0; x < imgw; x += imgh) + for (i = 0; i < stream.pixel_size; i++) + image[x + y + i] = buf[b++]; + ewriteall(STDOUT_FILENO, image, n, "<stdout>"); } + free(buf); + free(image); return 0; } diff --git a/src/vu-write-head.c b/src/vu-write-head.c @@ -1,29 +1,16 @@ /* See LICENSE file for copyright and license details. */ -#include "arg.h" #include "util.h" -static void -usage(void) -{ - eprintf("usage: %s parameters ...\n", argv0); -} +USAGE("parameters ...") int main(int argc, char *argv[]) { - int i; - - ARGBEGIN { - default: - usage(); - } ARGEND; - - if (!argc) - usage(); + ENOFLAGS(!argc); - printf("%s", argv[0]); - for (i = 0; i < argc; i++) - printf(" %s", argv[i]); + printf("%s", *argv++); + while (*argv) + printf(" %s", *argv++); printf("\n%cuivf", 0); efshut(stdout, "<stdout>");