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 < 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 }