Use new github account
[oggfilter.git] / oggfilter.c
blobe99e49265bd56815137befb0660f9060bbfb4349
1 /*-
2 * "THE BEER-WARE LICENSE" (Revision 42):
3 * <tobias.rehbein@web.de> wrote this file. As long as you retain this notice
4 * you can do whatever you want with this stuff. If we meet some day, and you
5 * think this stuff is worth it, you can buy me a beer in return.
6 * Tobias Rehbein
7 */
9 #include <assert.h>
10 #include <err.h>
11 #include <limits.h>
12 #include <locale.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <unistd.h>
19 #include <sys/types.h>
20 #include <sys/wait.h>
22 #include "checks.h"
23 #include "list.h"
24 #include "options.h"
26 static void fork_you(struct opt_options *opts, struct chk_context *ctx);
27 static void free_conditions(struct chk_conditions *cond);
28 static struct chk_conditions *get_conditions(struct opt_options *opts);
29 static void process_loop(struct opt_options *opts, struct chk_context *ctx, bool doflush);
30 static void remove_trailing_slashes(char *path);
31 static int use_pipe(int *p);
32 static void wait_for_childs(void);
34 int
35 main(int argc, char **argv)
38 if (setlocale(LC_ALL, "") == NULL)
39 errx(EXIT_FAILURE, "setlocale LC_ALL");
41 /* setup environment */
42 struct opt_options *opts = opt_get_options(argc, argv);
43 if (opts == NULL)
44 err(EXIT_FAILURE, "opt_get_options");
45 struct chk_conditions *cond = get_conditions(opts);
46 if (cond == NULL)
47 err(EXIT_FAILURE, "get_conditions");
48 struct chk_context *ctx = chk_context_open(cond);
49 if (ctx == NULL)
50 err(EXIT_FAILURE, "chk_context_open");
52 /* enter main loop or fork away */
53 if (opts->processes <= 1)
54 process_loop(opts, ctx, false);
55 else
56 fork_you(opts, ctx);
58 /* free all resources */
59 chk_context_close(ctx);
60 free_conditions(cond);
61 opt_free_options(opts);
63 return (0);
66 static struct chk_conditions *
67 get_conditions(struct opt_options *opts)
69 assert(opts != NULL);
71 struct chk_conditions *cond = malloc(sizeof(*cond));
72 if (cond == NULL)
73 return (NULL);
75 chk_init_conditions(cond);
77 cond->min_length = opts->min_length;
78 cond->max_length = opts->max_length;
79 cond->min_bitrate = opts->min_bitrate;
80 cond->max_bitrate = opts->max_bitrate;
81 cond->noignorecase = opts->noignorecase;
83 for (struct element *oe = opts->expressionlist; oe != NULL; oe = oe->next) {
84 struct chk_expression *cx = malloc(sizeof(*cx));
85 if (cx == NULL)
86 err(EXIT_FAILURE, "malloc chk_expression");
88 struct opt_expression *ox = oe->payload;
89 cx->expression = ox->expression;
90 cx->invert = ox->invert;
92 struct element *ce;
93 if ((ce = create_element(cx)) == NULL)
94 err(EXIT_FAILURE, "create_element");
96 cond->regexlist = prepend_element(ce, cond->regexlist);
99 return (cond);
102 static void
103 free_conditions(struct chk_conditions *cond)
105 assert(cond != NULL);
107 for (struct element *e = cond->regexlist; e != NULL; e = destroy_element(e))
108 free(e->payload);
110 free(cond);
113 static void
114 process_loop(struct opt_options *opts, struct chk_context *ctx, bool doflush)
116 assert(opts != NULL);
117 assert(ctx != NULL);
119 char pathread[LINE_MAX];
120 while (fgets(pathread, LINE_MAX, stdin) != NULL) {
121 char *newline = NULL;
122 if ((newline = strchr(pathread, '\n')) != NULL)
123 newline[0] = '\0';
125 char *path = malloc(LINE_MAX);
126 if (path == NULL)
127 err(EXIT_FAILURE, "malloc path");
129 char *pathprefix = NULL;
130 if (opts->pathprefix != NULL) {
131 pathprefix = strdup(opts->pathprefix);
132 if (pathprefix == NULL)
133 err(EXIT_FAILURE, "strdup pathprefix");
134 remove_trailing_slashes(pathprefix);
136 if (pathprefix != NULL && pathread[0] != '/')
137 snprintf(path, LINE_MAX, "%s/%s", pathprefix, pathread);
138 else {
139 strncpy(path, pathread, LINE_MAX - 2);
140 path[LINE_MAX - 1] = '\0';
142 free(pathprefix);
144 bool check_result = chk_check_file(path, ctx);
145 if (check_result ^ opts->invert) {
146 fputs(path, stdout);
147 if (opts->print0)
148 putc('\0', stdout);
149 else
150 putc('\n', stdout);
152 if (doflush)
153 fflush(stdout);
155 free(path);
157 if (ferror(stdin))
158 err(EXIT_FAILURE, "fgets stdin");
161 static void
162 remove_trailing_slashes(char *path)
164 assert(path != NULL);
166 char *n = strchr(path, (int)'\0');
167 assert(n != NULL);
168 while (*n != path[0] && *(--n) == '/')
169 *n = '\0';
172 static void
173 fork_you(struct opt_options *opts, struct chk_context *ctx)
175 assert(opts != NULL);
176 assert(ctx != NULL);
178 int *fds = malloc(opts->processes * sizeof(int));
179 if (fds == NULL)
180 err(EXIT_FAILURE, "malloc fds");
182 for (int i = 0; i < opts->processes; i++) {
183 int p[2];
184 if (pipe(p) == -1)
185 err(EXIT_FAILURE, "pipe %d", i);
187 pid_t pid = fork();
188 switch (pid) {
189 case -1:
190 err(EXIT_FAILURE, "fork %d", i);
191 break;
192 case 0:
193 /* close all write ends opened until now */
194 for (int j = 0; j < i; j++)
195 if (close(fds[j]) == -1)
196 warn("close %d, %d", i, j);
197 free(fds);
199 if (use_pipe(p) == -1)
200 errx(EXIT_FAILURE, "use_pipe %d", i);
202 process_loop(opts, ctx, true);
204 return;
205 default:
207 * close the read end of pipe and store write end for
208 * later use
210 if (close(p[0]) == -1)
211 warn("close %d", i);
212 fds[i] = p[1];
216 char pathread[LINE_MAX];
217 int fd = 0;
218 while (fgets(pathread, LINE_MAX, stdin) != NULL)
219 if (write(fds[fd++ % opts->processes], pathread, strlen(pathread)) == -1)
220 warn("write");
221 if (ferror(stdin))
222 err(EXIT_FAILURE, "fgets stdin");
224 for (int i = 0; i < opts->processes; i++)
225 if (close(fds[i]) == -1)
226 warn("close %d", i);
228 wait_for_childs();
230 free(fds);
233 static int
234 use_pipe(int *p)
236 assert(p != NULL);
238 /* close write end of pipe and stdin of process */
239 if (close(p[1]) == -1)
240 return (-1);
241 if (fclose(stdin) == EOF)
242 return (-1);
244 /* use the read end of pipe as stdin */
245 if ((dup2(p[0], STDIN_FILENO)) == -1)
246 return (-1);
247 if ((stdin = fdopen(STDIN_FILENO, "r")) == NULL)
248 return (-1);
250 return (0);
253 static void
254 wait_for_childs()
256 pid_t pid;
257 int sts;
258 while ((pid = wait(&sts)) != -1)
259 if (WIFEXITED(sts) && WEXITSTATUS(sts) != 0)
260 warn("child process %d exited abnormally: %d", pid, sts);