| util.c - farbfeld - suckless image format with conversion tools | |
| git clone git://git.suckless.org/farbfeld | |
| Log | |
| Files | |
| Refs | |
| README | |
| 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 < mi… | |
| 231 error = TOOSMALL; | |
| 232 else if ((ll == LLONG_MAX && errno == ERANGE) || ll > ma… | |
| 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 } |