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 }