util.c - blind - suckless command-line video editing utility | |
git clone git://git.suckless.org/blind | |
Log | |
Files | |
Refs | |
README | |
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 … | |
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'… | |
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… | |
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 siz… | |
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 *… | |
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) : WTERM… | |
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 } |