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