| util.c - 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 … | |
| 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'… | |
| 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… | |
| 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 siz… | |
| 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 *… | |
| 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) : WTERM… | |
| 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 } |