util.c - blind - suckless command-line video editing utility
(HTM) git clone git://git.suckless.org/blind
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
util.c (5434B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 char *argv0;
5
6 void
7 weprintf(const char *fmt, ...)
8 {
9 char end;
10 va_list ap;
11 va_start(ap, fmt);
12
13 if (argv0 && strncmp(fmt, "usage", strlen("usage")))
14 fprintf(stderr, "%s: ", argv0);
15
16 vfprintf(stderr, fmt, ap);
17
18 end = *fmt ? strchr(fmt, '\0')[-1] : '\n';
19 if (end == ':') {
20 fputc(' ', stderr);
21 perror(NULL);
22 } else if (end != '\n') {
23 fputc('\n', stderr);
24 }
25
26 va_end(ap);
27 }
28
29
30 int
31 tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out)
32 {
33 char *end;
34 errno = 0;
35 if (*s == '-') {
36 errno = ERANGE;
37 return -1;
38 }
39 if (!isdigit(s[*s == 'x' || *s == 'X' || *s == '#']) ||
40 (*s == '0' && s[1] && !isdigit(s[1 + (*s == 'x' || *s == 'o' || *s == 'b')]))) {
41 errno = EINVAL;
42 return -1;
43 }
44 if (tolower(*s) == 'x' || *s == '#')
45 *out = strtoull(s + 1, &end, 16);
46 else if (*s == '0' && tolower(s[1]) == 'x')
47 *out = strtoull(s + 2, &end, 16);
48 else if (*s == '0' && tolower(s[1]) == 'o')
49 *out = strtoull(s + 2, &end, 8);
50 else if (*s == '0' && tolower(s[1]) == 'b')
51 *out = strtoull(s + 2, &end, 2);
52 else
53 *out = strtoull(s, &end, 10);
54 if (errno)
55 return -1;
56 if (*end) {
57 errno = EINVAL;
58 return -1;
59 }
60 if (*out < min || *out > max) {
61 errno = ERANGE;
62 return -1;
63 }
64 return 0;
65 }
66
67 int
68 tolli(const char *s, long long int min, long long int max, long long int *out)
69 {
70 int sign = 1;
71 unsigned long long int inter;
72 errno = 0;
73 if (*s == '-') {
74 s++;
75 sign = -1;
76 }
77 if (tollu(s, 0, ULLONG_MAX, &inter))
78 return -1;
79 if (sign > 0) {
80 if (max < 0 || inter > (unsigned long long int)max)
81 goto erange;
82 *out = (long long int)inter;
83 if (*out < min)
84 goto erange;
85 } else {
86 #if LLONG_MIN == -LLONG_MAX
87 if (inter > -LLONG_MIN)
88 goto erange;
89 #else
90 if (inter > (unsigned long long int)LLONG_MAX + 1ULL)
91 goto erange;
92 #endif
93 *out = -(long long int)inter;
94 if (*out < min || *out > max)
95 goto erange;
96 }
97 return 0;
98
99 erange:
100 errno = ERANGE;
101 return -1;
102 }
103
104
105 int
106 writeall(int fd, const void *buf, size_t n)
107 {
108 const char *buffer = buf;
109 ssize_t r;
110 while (n) {
111 r = write(fd, buffer, n);
112 if (r < 0)
113 return -1;
114 buffer += (size_t)r;
115 n -= (size_t)r;
116 }
117 return 0;
118 }
119
120 ssize_t
121 readall(int fd, void *buf, size_t n)
122 {
123 char *buffer = buf;
124 size_t ptr = 0;
125 ssize_t r;
126 for (;;) {
127 r = read(fd, buffer + ptr, n - ptr);
128 if (r < 0)
129 return -1;
130 if (r == 0)
131 break;
132 ptr += (size_t)r;
133 }
134 return (ssize_t)ptr;
135 }
136
137 int
138 pwriteall(int fd, const void *buf, size_t n, off_t ptr)
139 {
140 const char *buffer = buf;
141 ssize_t r;
142 while (n) {
143 r = pwrite(fd, buffer, n, (off_t)ptr);
144 if (r < 0)
145 return -1;
146 buffer += (size_t)r;
147 n -= (size_t)r;
148 ptr += (off_t)r;
149 }
150 return 0;
151 }
152
153 int
154 writezeroes(int fd, const void *buf, size_t bufsize, size_t n)
155 {
156 size_t p, m;
157 for (p = 0; p < n; p += m) {
158 m = MIN(bufsize, n - p);
159 if (writeall(fd, buf, m))
160 return -1;
161 }
162 return 0;
163 }
164
165 int
166 getfile(int fd, void *buffer, size_t *restrict ptr, size_t *restrict size)
167 {
168 char *restrict *restrict buf = buffer;
169 void *new;
170 size_t new_size;
171 ssize_t r;
172
173 for (;;) {
174 if (*ptr == *size) {
175 new_size = *size ? *size << 1 : BUFSIZ;
176 if (!(new = realloc(*buf, new_size))) {
177 errno = ENOMEM;
178 return -1;
179 }
180 *buf = new;
181 *size = new_size;
182 }
183 r = read(fd, *buf + *ptr, *size - *ptr);
184 if (r <= 0) {
185 if (r)
186 return -1;
187 break;
188 }
189 *ptr += (size_t)r;
190 }
191
192 return 0;
193 }
194
195
196 static inline pid_t
197 enfork(int status)
198 {
199 pid_t pid = fork();
200 if (pid == -1)
201 enprintf(status, "fork:");
202 return pid;
203 }
204
205
206 /* If <() is used in Bash (possibily other shells), that process becomes
207 * child of the process for each <() is used. Therefore, we cannot simply
208 * wait until the last child has been reaped, or even the expected number
209 * of children has been reaped, we must instead remember the PID of each
210 * child we created and wait for all of them to be reaped. { */
211
212 int
213 enfork_jobs(int status, size_t *start, size_t *end, size_t jobs, pid_t **pids)
214 {
215 size_t j, s = *start, n = *end - *start;
216 pid_t pid;
217 if (jobs < 2) {
218 *pids = NULL;
219 return 1;
220 }
221 *end = n / jobs + s;
222 *pids = enmalloc2(status, jobs, sizeof(**pids));
223 for (j = 1; j < jobs; j++) {
224 pid = enfork(status);
225 if (!pid) {
226 pdeath(SIGKILL);
227 *start = n * (j + 0) / jobs + s;
228 *end = n * (j + 1) / jobs + s;
229 return 0;
230 } else {
231 (*pids)[j - 1] = pid;
232 }
233 }
234 (*pids)[jobs - 1] = -1;
235 return 1;
236 }
237
238 void
239 enjoin_jobs(int status, int is_master, pid_t *pids)
240 {
241 int stat;
242 size_t i;
243 if (!is_master)
244 free(pids), exit(0);
245 if (!pids)
246 return;
247 for (i = 0; pids[i] != -1; i++) {
248 if (waitpid(pids[i], &stat, 0) == -1)
249 enprintf(status, "waitpid:");
250 if (stat)
251 exit(WIFEXITED(stat) ? WEXITSTATUS(stat) : WTERMSIG(stat));
252 }
253 free(pids);
254 }
255
256 /* } */
257
258
259 int
260 xenopen(int status, const char *path, int flags, int mode, ...)
261 {
262 int fd;
263 if (!strncmp(path, "/dev/fd/", STRLEN("/dev/fd/"))) {
264 if (!toi(path + STRLEN("/dev/fd/"), 0, INT_MAX, &fd))
265 return fd;
266 } else if (!strcmp(path, "/dev/stdin")) {
267 return STDIN_FILENO;
268 } else if (!strcmp(path, "/dev/stdout")) {
269 return STDOUT_FILENO;
270 } else if (!strcmp(path, "/dev/stderr")) {
271 return STDERR_FILENO;
272 } else if (!strcmp(path, "-")) {
273 if ((flags & O_ACCMODE) == O_WRONLY)
274 return STDOUT_FILENO;
275 else
276 return STDIN_FILENO;
277 }
278 fd = open(path, flags, mode);
279 if (fd < 0)
280 enprintf(status, "open %s:", path);
281 return fd;
282 }