util.c - farbfeld - suckless image format with conversion tools
 (HTM) git clone git://git.suckless.org/farbfeld
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       util.c (4197B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <arpa/inet.h>
            3 
            4 #include <errno.h>
            5 #include <limits.h>
            6 #include <stdarg.h>
            7 #include <stdint.h>
            8 #include <stdio.h>
            9 #include <stdlib.h>
           10 #include <string.h>
           11 #include <sys/types.h>
           12 
           13 #include "util.h"
           14 
           15 char *argv0;
           16 
           17 static void
           18 verr(const char *fmt, va_list ap)
           19 {
           20         if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) {
           21                 fprintf(stderr, "%s: ", argv0);
           22         }
           23 
           24         vfprintf(stderr, fmt, ap);
           25 
           26         if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
           27                 fputc(' ', stderr);
           28                 perror(NULL);
           29         } else {
           30                 fputc('\n', stderr);
           31         }
           32 }
           33 
           34 void
           35 warn(const char *fmt, ...)
           36 {
           37         va_list ap;
           38 
           39         va_start(ap, fmt);
           40         verr(fmt, ap);
           41         va_end(ap);
           42 }
           43 
           44 void
           45 die(const char *fmt, ...)
           46 {
           47         va_list ap;
           48 
           49         va_start(ap, fmt);
           50         verr(fmt, ap);
           51         va_end(ap);
           52 
           53         exit(1);
           54 }
           55 
           56 void
           57 ff_read_header(uint32_t *width, uint32_t *height)
           58 {
           59         uint32_t hdr[4];
           60 
           61         efread(hdr, sizeof(*hdr), LEN(hdr), stdin);
           62 
           63         if (memcmp("farbfeld", hdr, sizeof("farbfeld") - 1)) {
           64                 die("Invalid magic value");
           65         }
           66 
           67         *width = ntohl(hdr[2]);
           68         *height = ntohl(hdr[3]);
           69 }
           70 
           71 void
           72 ff_write_header(uint32_t width, uint32_t height)
           73 {
           74         uint32_t tmp;
           75 
           76         fputs("farbfeld", stdout);
           77 
           78         tmp = htonl(width);
           79         efwrite(&tmp, sizeof(tmp), 1, stdout);
           80 
           81         tmp = htonl(height);
           82         efwrite(&tmp, sizeof(tmp), 1, stdout);
           83 }
           84 
           85 int
           86 parse_mask(const char *s, uint16_t mask[3])
           87 {
           88         size_t slen, i;
           89         unsigned int col[3], colfac;
           90         char fmt[] = "%#x%#x%#x";
           91 
           92         slen = strlen(s);
           93         if (slen != 3 && slen != 6 && slen != 12) {
           94                 return 1;
           95         }
           96 
           97         fmt[1] = fmt[4] = fmt[7] = ((slen / 3) + '0');
           98         if (sscanf(s, fmt, col, col + 1, col + 2) != 3) {
           99                 return 1;
          100         }
          101 
          102         colfac = (slen == 3) ? UINT16_MAX / 0xf :
          103                  (slen == 6) ? UINT16_MAX / 0xff :
          104                                UINT16_MAX / 0xffff;
          105 
          106         for (i = 0; i < 3; i++) {
          107                 mask[i] = col[i] * colfac;
          108         }
          109 
          110         return 0;
          111 }
          112 
          113 int
          114 fshut(FILE *fp, const char *fname)
          115 {
          116         int ret = 0;
          117 
          118         /* fflush() is undefined for input streams by ISO C,
          119          * but not POSIX 2008 if you ignore ISO C overrides.
          120          * Leave it unchecked and rely on the following
          121          * functions to detect errors.
          122          */
          123         fflush(fp);
          124 
          125         if (ferror(fp) && !ret) {
          126                 warn("ferror '%s':", fname);
          127                 ret = 1;
          128         }
          129 
          130         if (fclose(fp) && !ret) {
          131                 warn("fclose '%s':", fname);
          132                 ret = 1;
          133         }
          134 
          135         return ret;
          136 }
          137 
          138 void
          139 efread(void *p, size_t s, size_t n, FILE *f)
          140 {
          141         if (fread(p, s, n, f) != n) {
          142                 if (ferror(f)) {
          143                         die("fread:");
          144                 } else {
          145                         die("fread: Unexpected end of file");
          146                 }
          147         }
          148 }
          149 
          150 void
          151 efwrite(const void *p, size_t s, size_t n, FILE *f)
          152 {
          153         if (fwrite(p, s, n, f) != n) {
          154                 die("fwrite:");
          155         }
          156 }
          157 
          158 void *
          159 ereallocarray(void *optr, size_t nmemb, size_t size)
          160 {
          161         void *p;
          162 
          163         if (!(p = reallocarray(optr, nmemb, size))) {
          164                 die("reallocarray: Out of memory");
          165         }
          166 
          167         return p;
          168 }
          169 
          170 long long
          171 estrtonum(const char *numstr, long long minval, long long maxval)
          172 {
          173         const char *errstr;
          174         long long ll;
          175 
          176         ll = strtonum(numstr, minval, maxval, &errstr);
          177         if (errstr) {
          178                 die("strtonum '%s': %s", numstr, errstr);
          179         }
          180 
          181         return ll;
          182 }
          183 
          184 /*
          185  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
          186  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
          187  */
          188 #define MUL_NO_OVERFLOW        (1UL << (sizeof(size_t) * 4))
          189 
          190 void *
          191 reallocarray(void *optr, size_t nmemb, size_t size)
          192 {
          193         if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
          194             nmemb > 0 && SIZE_MAX / nmemb < size) {
          195                 errno = ENOMEM;
          196                 return NULL;
          197         }
          198         return realloc(optr, size * nmemb);
          199 }
          200 
          201 #define        INVALID                1
          202 #define        TOOSMALL        2
          203 #define        TOOLARGE        3
          204 
          205 long long
          206 strtonum(const char *numstr, long long minval, long long maxval,
          207          const char **errstrp)
          208 {
          209         long long ll = 0;
          210         int error = 0;
          211         char *ep;
          212         struct errval {
          213                 const char *errstr;
          214                 int err;
          215         } ev[4] = {
          216                 { NULL,                0 },
          217                 { "invalid",        EINVAL },
          218                 { "too small",        ERANGE },
          219                 { "too large",        ERANGE },
          220         };
          221 
          222         ev[0].err = errno;
          223         errno = 0;
          224         if (minval > maxval) {
          225                 error = INVALID;
          226         } else {
          227                 ll = strtoll(numstr, &ep, 10);
          228                 if (numstr == ep || *ep != '\0')
          229                         error = INVALID;
          230                 else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
          231                         error = TOOSMALL;
          232                 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
          233                         error = TOOLARGE;
          234         }
          235         if (errstrp != NULL)
          236                 *errstrp = ev[error].errstr;
          237         errno = ev[error].err;
          238         if (error)
          239                 ll = 0;
          240 
          241         return (ll);
          242 }