blind

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

commit ed2cf4c1d66bcdfbf44c34eb94dd94a0535a9334
parent 2bedb844c0b48f7af4e41f2c7d338e2defcf5859
Author: Mattias Andrée <maandree@kth.se>
Date:   Sun,  8 Jan 2017 03:49:20 +0100

Add vu-single-colour

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

Diffstat:
Asrc/arg.h | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util.c | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/util.h | 35+++++++++++++++++++++++++++++++++++
Asrc/vu-single-colour.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 365 insertions(+), 0 deletions(-)

diff --git a/src/arg.h b/src/arg.h @@ -0,0 +1,78 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][0] == '-') {\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM case '0':\ + case '1':\ + case '2':\ + case '3':\ + case '4':\ + case '5':\ + case '6':\ + case '7':\ + case '8':\ + case '9' + +#define ARGALT(SYMBOL) }\ + } else if (argv[0][0] == SYMBOL) {\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) + +#define ARGEND }\ + } else {\ + break;\ + }\ + } + +#define ARGC() argc_ + +#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define LNGARG() &argv[0][0] + +#endif diff --git a/src/util.c b/src/util.c @@ -0,0 +1,171 @@ +/* See LICENSE file for copyright and license details. */ +#include "util.h" + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> + +char *argv0; + +static void +xvprintf(const char *fmt, va_list ap) +{ + if (argv0 && strncmp(fmt, "usage", strlen("usage"))) + fprintf(stderr, "%s: ", argv0); + + vfprintf(stderr, fmt, ap); + + if (fmt[0] && fmt[strlen(fmt)-1] == ':') { + 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); +} + + +int +tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out) +{ + char *end; + errno = 0; + if (*s == '-') { + errno = ERANGE; + return -1; + } + if (tolower(*s) == 'x' || *s == '#') + *out = strtoull(s + 1, &end, 16); + else if (*s == '0' && tolower(s[1]) == 'x') + *out = strtoull(s + 2, &end, 16); + else if (*s == '0' && tolower(s[1]) == 'o') + *out = strtoull(s + 2, &end, 8); + else if (*s == '0' && tolower(s[1]) == 'b') + *out = strtoull(s + 2, &end, 2); + else + *out = strtoull(s, &end, 10); + if (errno) + return -1; + if (*end) { + errno = EINVAL; + return -1; + } + if (*out < min || *out > max) { + errno = ERANGE; + return -1; + } + return 0; +} + +int +tolli(const char *s, long long int min, long long int max, long long int *out) +{ + char *end; + int sign = 1; + unsigned long long int inter; + errno = 0; + if (*s == '-') { + s++; + sign = -1; + } + if (tollu(s, 0, ULLONG_MAX, &inter)) + return -1; + if (sign > 0) { + if (max < 0 || inter > (unsigned long long int)max) + goto erange; + *out = (long long int)inter; + if (*out < min) + goto erange; + } else { +#if LLONG_MIN == -LLONG_MAX + if (inter > -LLONG_MIN) + goto erange; +#else + if (inter > (unsigned long long int)LLONG_MAX + 1ULL) + goto erange; +#endif + *out = -(long long int)inter; + if (*out < min || *out > max) + goto erange; + } + return 0; + +erange: + errno = ERANGE; + return -1; +} + + +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; +} + +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); +} diff --git a/src/util.h b/src/util.h @@ -0,0 +1,35 @@ +/* See LICENSE file for copyright and license details. */ + +#include <stdio.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 + +int fshut(FILE *fp, const char *fname); +void enfshut(int status, FILE *fp, const char *fname); +void efshut(FILE *fp, const char *fname); diff --git a/src/vu-single-colour.c b/src/vu-single-colour.c @@ -0,0 +1,81 @@ +/* See LICENSE file for copyright and license details. */ +#include "arg.h" +#include "util.h" + +#include <inttypes.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static void +usage(void) +{ + eprintf("usage: %s [-f frames] -w width -h height red green blue [alpha]\n", argv0); +} + +int +main(int argc, char *argv[]) +{ + int red, green, blue, alpha = 255; + size_t width = 0, height = 0, frames = 1; + unsigned char pixel[4]; + size_t x, y, n; + int32_t buf[1024]; + ssize_t r; + + ARGBEGIN { + case 'f': + if (tozu(EARGF(usage()), 1, SIZE_MAX, &frames)) + eprintf("argument of -f must be an integer in [1, %zu]\n", SIZE_MAX); + break; + case 'w': + if (tozu(EARGF(usage()), 1, SIZE_MAX, &width)) + eprintf("argument of -w must be an integer in [1, %zu]\n", SIZE_MAX); + break; + case 'h': + if (tozu(EARGF(usage()), 1, SIZE_MAX, &height)) + eprintf("argument of -h must be an integer in [1, %zu]\n", SIZE_MAX); + break; + default: + usage(); + } ARGEND; + + if (!width || !height || argc < 3 || argc > 4) + usage(); + + if (toi(argv[0], 0, 255, &red)) + eprintf("the red value must be an integer in [0, 255]\n"); + if (toi(argv[1], 0, 255, &green)) + eprintf("the green value must be an integer in [0, 255]\n"); + if (toi(argv[2], 0, 255, &blue)) + eprintf("the blue value must be an integer in [0, 255]\n"); + if (argc > 3 && toi(argv[3], 0, 255, &alpha)) + eprintf("the alpha value must be an integer in [0, 255]\n"); + + pixel[0] = (unsigned char)red; + pixel[1] = (unsigned char)green; + pixel[2] = (unsigned char)blue; + pixel[3] = (unsigned char)alpha; + + for (x = 0; x < ELEMENTSOF(buf); x++) + buf[x] = *(int32_t *)(void *)pixel; + while (frames--) { + for (y = height; y--;) { + for (x = width; x;) { + n = ELEMENTSOF(buf) < x ? ELEMENTSOF(buf) : x; + x -= n; + n *= sizeof(*buf); + while (n) { + r = write(STDOUT_FILENO, buf, n); + if (r < 0) + eprintf("write <stdout>:"); + n -= (size_t)r; + } + } + } + } + + efshut(stdout, "<stdout>"); + return 0; +}