Use new github account
[oggfilter.git] / options.c
blobbfe64d62353ccd0f0674dac9a88f1c8a5c04db85
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 <getopt.h>
12 #include <limits.h>
13 #include <regex.h>
14 #include <stdbool.h>
15 #include <stdio.h>
16 #include <stdlib.h>
18 #include "options.h"
19 #include "list.h"
21 static const char *VERSION = "v1.4.0";
22 static const char *PERIOD_EXPRESSION = "^([[:digit:]]{1,})(:([0-5][[:digit:]]))?$";
23 enum {
24 PERIOD_GROUPS = 4
27 static struct option longopts[] = {
28 {"directory", required_argument, NULL, 'd'},
29 {"min-length", required_argument, NULL, 'l'},
30 {"max-length", required_argument, NULL, 'L'},
31 {"expression", required_argument, NULL, 'x'},
32 {"exclude-expression", required_argument, NULL, 'X'},
33 {"invert", no_argument, NULL, 'v'},
34 {"help", no_argument, NULL, 'h'},
35 {"min-bitrate", required_argument, NULL, 'b'},
36 {"max-bitrate", required_argument, NULL, 'B'},
37 {"processes", required_argument, NULL, 'P'},
38 {"no-ignorecase", no_argument, NULL, 'I'},
39 {"print0", no_argument, NULL, '0'}
42 static void init_options(struct opt_options *opts);
43 static long parse_long(char *option);
44 static double parse_period(char *period);
45 static void prepend_expression(struct opt_options *opts, char *expression, int invert);
46 static void print_usage(void);
48 struct opt_options *
49 opt_get_options(int argc, char *argv[])
51 assert(argc >= 0);
52 assert(argv != NULL);
54 struct opt_options *opts = malloc(sizeof(struct opt_options));
55 if (opts == NULL)
56 err(EXIT_FAILURE, "malloc struct opt_options");
58 init_options(opts);
60 int opt;
61 while ((opt = getopt_long(argc, argv, "hd:l:L:x:X:vb:B:P:I0", longopts, NULL)) != -1)
62 switch (opt) {
63 case 'd':
64 opts->pathprefix = optarg;
65 break;
66 case 'l':
67 opts->min_length = parse_period(optarg);
68 break;
69 case 'L':
70 opts->max_length = parse_period(optarg);
71 break;
72 case 'x':
73 prepend_expression(opts, optarg, 0);
74 break;
75 case 'X':
76 prepend_expression(opts, optarg, 1);
77 break;
78 case 'b':
79 opts->min_bitrate = parse_long(optarg) * 1000;
80 break;
81 case 'B':
82 opts->max_bitrate = parse_long(optarg) * 1000;
83 break;
84 case 'P':
85 opts->processes = (int)parse_long(optarg);
86 break;
87 case 'v':
88 opts->invert = true;
89 break;
90 case 'I':
91 opts->noignorecase = true;
92 break;
93 case '0':
94 opts->print0 = true;
95 break;
96 case 'h':
97 print_usage();
98 exit(EXIT_FAILURE);
99 default:
100 print_usage();
101 exit(EXIT_SUCCESS);
104 return (opts);
108 opt_free_options(struct opt_options *opts)
110 assert(opts != NULL);
112 struct element *e = opts->expressionlist;
113 while (e != NULL) {
114 free(e->payload);
115 e = destroy_element(e);
118 free(opts);
120 return (0);
123 static void
124 print_usage()
126 printf("This is oggfilter %s\n\n", VERSION);
127 puts("oggfilter [-l|--min-length period] [-L|--max-length period]");
128 puts(" [-b|--min-bitrate bitrate] [-B|--max-bitrate bitrate]");
129 puts(" [-x|--expression regexp] [-X|--exclude-expression regexp]");
130 puts(" [-d|--directory directory] [-P|--processes count]");
131 puts(" [-v|--invert] [-I|--no-ignorecase] [-0|--print0]\n");
132 puts("oggfilter {-h|--help}");
135 static void
136 init_options(struct opt_options *opts)
138 assert(opts != NULL);
140 opts->min_length = -1;
141 opts->max_length = -1;
142 opts->min_bitrate = -1;
143 opts->max_bitrate = -1;
144 opts->expressionlist = NULL;
145 opts->pathprefix = NULL;
146 opts->invert = false;
147 opts->processes = 1;
148 opts->noignorecase = false;
149 opts->print0 = false;
152 static double
153 parse_period(char *option)
155 assert(option != NULL);
157 regex_t regex;
159 int e = regcomp(&regex, PERIOD_EXPRESSION, REG_EXTENDED);
160 if (e != 0) {
161 char errstr[128];
162 regerror(e, &regex, errstr, sizeof(errstr));
163 errx(EXIT_FAILURE, "regcomp \"%s\": %s", PERIOD_EXPRESSION, errstr);
166 double period = 0;
167 regmatch_t groups[PERIOD_GROUPS];
168 if (regexec(&regex, option, PERIOD_GROUPS, groups, 0) == 0) {
169 char *minutes = NULL;
170 char *seconds = NULL;
171 if (groups[2].rm_so == -1)
172 seconds = option;
173 else {
174 minutes = option;
175 option[groups[2].rm_so] = '\0';
176 seconds = &option[groups[3].rm_so];
179 if (minutes != NULL)
180 period = parse_long(minutes) * 60;
181 period += parse_long(seconds);
182 } else
183 errx(EXIT_FAILURE, "invalid period \"%s\"", option);
185 regfree(&regex);
187 return (period);
190 static long
191 parse_long(char *option)
193 assert(option != NULL);
195 char *endptr;
196 long parsed = strtol(option, &endptr, 10);
197 if (endptr[0] != '\0')
198 errx(EXIT_FAILURE, "illegal number \"%s\"", option);
200 return (parsed);
203 static void
204 prepend_expression(struct opt_options *opts, char *expression, int invert)
206 assert(opts != NULL);
207 assert(expression != NULL);
208 assert(invert == 0 || invert == 1);
210 struct opt_expression *x = malloc(sizeof(*x));
211 if (x == NULL)
212 err(EXIT_FAILURE, "malloc opt_expression");
214 x->expression = expression;
215 x->invert = invert;
217 struct element *e = create_element(x);
218 if (e == NULL)
219 err(EXIT_FAILURE, "create_element");
221 opts->expressionlist = prepend_element(e, opts->expressionlist);