blind

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

util.c (5434B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "common.h"
      3 
      4 char *argv0;
      5 
      6 void
      7 weprintf(const char *fmt, ...)
      8 {
      9 	char end;
     10 	va_list ap;
     11 	va_start(ap, fmt);
     12 
     13 	if (argv0 && strncmp(fmt, "usage", strlen("usage")))
     14 		fprintf(stderr, "%s: ", argv0);
     15 
     16 	vfprintf(stderr, fmt, ap);
     17 
     18 	end = *fmt ? strchr(fmt, '\0')[-1] : '\n';
     19 	if (end == ':') {
     20 		fputc(' ', stderr);
     21 		perror(NULL);
     22 	} else if (end != '\n') {
     23 		fputc('\n', stderr);
     24 	}
     25 
     26 	va_end(ap);
     27 }
     28 
     29 
     30 int
     31 tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out)
     32 {
     33 	char *end;
     34 	errno = 0;
     35 	if (*s == '-') {
     36 		errno = ERANGE;
     37 		return -1;
     38 	}
     39 	if (!isdigit(s[*s == 'x' || *s == 'X' || *s == '#']) ||
     40 	    (*s == '0' && s[1] && !isdigit(s[1 + (*s == 'x' || *s == 'o' || *s == 'b')]))) {
     41 		errno = EINVAL;
     42 		return -1;
     43 	}
     44 	if (tolower(*s) == 'x' || *s == '#')
     45 		*out = strtoull(s + 1, &end, 16);
     46 	else if (*s == '0' && tolower(s[1]) == 'x')
     47 		*out = strtoull(s + 2, &end, 16);
     48 	else if (*s == '0' && tolower(s[1]) == 'o')
     49 		*out = strtoull(s + 2, &end, 8);
     50 	else if (*s == '0' && tolower(s[1]) == 'b')
     51 		*out = strtoull(s + 2, &end, 2);
     52 	else
     53 		*out = strtoull(s, &end, 10);
     54 	if (errno)
     55 		return -1;
     56 	if (*end) {
     57 		errno = EINVAL;
     58 		return -1;
     59 	}
     60 	if (*out < min || *out > max) {
     61 		errno = ERANGE;
     62 		return -1;
     63 	}
     64 	return 0;
     65 }
     66 
     67 int
     68 tolli(const char *s, long long int min, long long int max, long long int *out)
     69 {
     70 	int sign = 1;
     71 	unsigned long long int inter;
     72 	errno = 0;
     73 	if (*s == '-') {
     74 		s++;
     75 		sign = -1;
     76 	}
     77 	if (tollu(s, 0, ULLONG_MAX, &inter))
     78 		return -1;
     79 	if (sign > 0) {
     80 		if (max < 0 || inter > (unsigned long long int)max)
     81 			goto erange;
     82 		*out = (long long int)inter;
     83 		if (*out < min)
     84 			goto erange;
     85 	} else {
     86 #if LLONG_MIN == -LLONG_MAX
     87 		if (inter > -LLONG_MIN)
     88 			goto erange;
     89 #else
     90 		if (inter > (unsigned long long int)LLONG_MAX + 1ULL)
     91 			goto erange;
     92 #endif
     93 		*out = -(long long int)inter;
     94 		if (*out < min || *out > max)
     95 			goto erange;
     96 	}
     97 	return 0;
     98 
     99 erange:
    100 	errno = ERANGE;
    101 	return -1;
    102 }
    103 
    104 
    105 int
    106 writeall(int fd, const void *buf, size_t n)
    107 {
    108 	const char *buffer = buf;
    109 	ssize_t r;
    110 	while (n) {
    111 		r = write(fd, buffer, n);
    112 		if (r < 0)
    113 			return -1;
    114 		buffer += (size_t)r;
    115 		n -= (size_t)r;
    116 	}
    117 	return 0;
    118 }
    119 
    120 ssize_t
    121 readall(int fd, void *buf, size_t n)
    122 {
    123 	char *buffer = buf;
    124 	size_t ptr = 0;
    125 	ssize_t r;
    126 	for (;;) {
    127 		r = read(fd, buffer + ptr, n - ptr);
    128 		if (r < 0)
    129 			return -1;
    130 		if (r == 0)
    131 			break;
    132 		ptr += (size_t)r;
    133 	}
    134 	return (ssize_t)ptr;
    135 }
    136 
    137 int
    138 pwriteall(int fd, const void *buf, size_t n, off_t ptr)
    139 {
    140 	const char *buffer = buf;
    141 	ssize_t r;
    142 	while (n) {
    143 		r = pwrite(fd, buffer, n, (off_t)ptr);
    144 		if (r < 0)
    145 			return -1;
    146 		buffer += (size_t)r;
    147 		n -= (size_t)r;
    148 		ptr += (off_t)r;
    149 	}
    150 	return 0;
    151 }
    152 
    153 int
    154 writezeroes(int fd, const void *buf, size_t bufsize, size_t n)
    155 {
    156 	size_t p, m;
    157 	for (p = 0; p < n; p += m) {
    158 		m = MIN(bufsize, n - p);
    159 		if (writeall(fd, buf, m))
    160 			return -1;
    161 	}
    162 	return 0;
    163 }
    164 
    165 int
    166 getfile(int fd, void *buffer, size_t *restrict ptr, size_t *restrict size)
    167 {
    168 	char *restrict *restrict buf = buffer;
    169 	void *new;
    170 	size_t new_size;
    171 	ssize_t r;
    172 
    173 	for (;;) {
    174 		if (*ptr == *size) {
    175 			new_size = *size ? *size << 1 : BUFSIZ;
    176 			if (!(new = realloc(*buf, new_size))) {
    177 				errno = ENOMEM;
    178 				return -1;
    179 			}
    180 			*buf = new;
    181 			*size = new_size;
    182 		}
    183 		r = read(fd, *buf + *ptr, *size - *ptr);
    184 		if (r <= 0) {
    185 			if (r)
    186 				return -1;
    187 			break;
    188 		}
    189 		*ptr += (size_t)r;
    190 	}
    191 
    192 	return 0;
    193 }
    194 
    195 
    196 static inline pid_t
    197 enfork(int status)
    198 {
    199 	pid_t pid = fork();
    200 	if (pid == -1)
    201 		enprintf(status, "fork:");
    202 	return pid;
    203 }
    204 
    205 
    206 /* If <() is used in Bash (possibily other shells), that process becomes
    207  * child of the process for each <() is used. Therefore, we cannot simply
    208  * wait until the last child has been reaped, or even the expected number
    209  * of children has been reaped, we must instead remember the PID of each
    210  * child we created and wait for all of them to be reaped. { */
    211 
    212 int
    213 enfork_jobs(int status, size_t *start, size_t *end, size_t jobs, pid_t **pids)
    214 {
    215 	size_t j, s = *start, n = *end - *start;
    216 	pid_t pid;
    217 	if (jobs < 2) {
    218 		*pids = NULL;
    219 		return 1;
    220 	}
    221 	*end = n / jobs + s;
    222 	*pids = enmalloc2(status, jobs, sizeof(**pids));
    223 	for (j = 1; j < jobs; j++) {
    224 		pid = enfork(status);
    225 		if (!pid) {
    226 			pdeath(SIGKILL);
    227 			*start = n * (j + 0) / jobs + s;
    228 			*end   = n * (j + 1) / jobs + s;
    229 			return 0;
    230 		} else {
    231 			(*pids)[j - 1] = pid;
    232 		}
    233 	}
    234 	(*pids)[jobs - 1] = -1;
    235 	return 1;
    236 }
    237 
    238 void
    239 enjoin_jobs(int status, int is_master, pid_t *pids)
    240 {
    241 	int stat;
    242 	size_t i;
    243 	if (!is_master)
    244 		free(pids), exit(0);
    245 	if (!pids)
    246 		return;
    247 	for (i = 0; pids[i] != -1; i++) {
    248 		if (waitpid(pids[i], &stat, 0) == -1)
    249 			enprintf(status, "waitpid:");
    250 		if (stat)
    251 			exit(WIFEXITED(stat) ? WEXITSTATUS(stat) : WTERMSIG(stat));
    252 	}
    253 	free(pids);
    254 }
    255 
    256 /* } */
    257 
    258 
    259 int
    260 xenopen(int status, const char *path, int flags, int mode, ...)
    261 {
    262 	int fd;
    263 	if (!strncmp(path, "/dev/fd/", STRLEN("/dev/fd/"))) {
    264 		if (!toi(path + STRLEN("/dev/fd/"), 0, INT_MAX, &fd))
    265 			return fd;
    266 	} else if (!strcmp(path, "/dev/stdin")) {
    267 		return STDIN_FILENO;
    268 	} else if (!strcmp(path, "/dev/stdout")) {
    269 		return STDOUT_FILENO;
    270 	} else if (!strcmp(path, "/dev/stderr")) {
    271 		return STDERR_FILENO;
    272 	} else if (!strcmp(path, "-")) {
    273 		if ((flags & O_ACCMODE) == O_WRONLY)
    274 			return STDOUT_FILENO;
    275 		else
    276 			return STDIN_FILENO;
    277 	}
    278 	fd = open(path, flags, mode);
    279 	if (fd < 0)
    280 		enprintf(status, "open %s:", path);
    281 	return fd;
    282 }