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
verr(const char * fmt,va_list ap)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
warn(const char * fmt,...)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
die(const char * fmt,...)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
ff_read_header(uint32_t * width,uint32_t * height)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
ff_write_header(uint32_t width,uint32_t height)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
parse_mask(const char * s,uint16_t mask[3])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
fshut(FILE * fp,const char * fname)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
efread(void * p,size_t s,size_t n,FILE * f)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
efwrite(const void * p,size_t s,size_t n,FILE * f)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 *
ereallocarray(void * optr,size_t nmemb,size_t size)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
estrtonum(const char * numstr,long long minval,long long maxval)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 *
reallocarray(void * optr,size_t nmemb,size_t size)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
strtonum(const char * numstr,long long minval,long long maxval,const char ** errstrp)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 }
243