util.c - blind - suckless command-line video editing utility
 (HTM) git clone git://git.suckless.org/blind
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) 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 }