1 /**
2 * This file is part of the Detox package.
3 *
4 * Copyright (c) Doug Harple <detox.dharple@gmail.com>
5 *
6 * For the full copyright and license information, please view the LICENSE
7 * file that was distributed with this source code.
8 */
9
10 #include "config.h"
11
12 #include <sys/stat.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <libgen.h>
19
20 #include "detox.h"
21 #include "config.h"
22 #include "parse_options.h"
23
24 #ifdef HAVE_GETOPT_LONG
25 #include <getopt.h>
26 #endif
27
28 enum {
29 LONG_OPTION_DRY_RUN = 1,
30 LONG_OPTION_INLINE,
31 LONG_OPTION_REMOVE_TRAILING,
32 LONG_OPTION_SPECIAL
33 };
34
35 #define INLINE_DETOX_BIN "inline-detox"
36
37 /* expect this to be overwritten! */
38 static int long_option = 0;
39
40 #ifdef HAVE_GETOPT_LONG
41 static struct option longopts[] = {
42
43 /* long options with equivalents */
44 {"help", no_argument, 0, 'h'},
45 {"dry-run", no_argument, 0, 'n'},
46
47 /* long options without */
48 {"inline", no_argument, &long_option, LONG_OPTION_INLINE},
49 {"special", no_argument, &long_option, LONG_OPTION_SPECIAL},
50
51 /* deprecated long opts without */
52 {"remove-trailing", no_argument, &long_option, LONG_OPTION_REMOVE_TRAILING},
53
54 /* done */
55 {0, 0, 0, 0}
56 };
57
58 #endif
59
60 /* *INDENT-OFF* */
61
62 char usage_message[] = {
63 "usage: detox [-hLnrvV] [-f configfile] [-s sequence]"
64 #ifdef HAVE_GETOPT_LONG
65 " [--dry-run] [--inline] [--special]"
66 "\n\t "
67 #endif
68 " file [file ...]\n"
69 };
70
71 char help_message[] = {
72 " -f configfile choose which config file to use\n"
73 #ifdef HAVE_GETOPT_LONG
74 " -h --help this message\n"
75 #else
76 " -h this message\n"
77 #endif
78 #ifdef HAVE_GETOPT_LONG
79 " --inline run inline mode\n"
80 #endif
81 " -L list available sequences and exit\n"
82 " with -v ... dump sequence contents\n"
83 #ifdef HAVE_GETOPT_LONG
84 " -n --dry-run do a dry run (don't actually do anything)\n"
85 #else
86 " -n do a dry run (don't actually do anything)\n"
87 #endif
88 " -r be recursive (descend into subdirectories)\n"
89 #ifdef HAVE_GETOPT_LONG
90 " --remove-trailing (deprecated)\n"
91 " remove trailing _ and - before a period\n"
92 #endif
93 " -s sequence choose which sequence to detox with\n"
94 #ifdef HAVE_GETOPT_LONG
95 " --special work on links and special files\n"
96 #endif
97 " -v be verbose\n"
98 " -V show the current version\n"
99 };
100
101 char usage_message_inline[] = {
102 "usage: inline-detox [-hLvV] [-f configfile] [-s sequence] [file]\n"
103 };
104
105 char help_message_inline[] = {
106 " -f configfile choose which config file to use\n"
107 #ifdef HAVE_GETOPT_LONG
108 " -h --help this message\n"
109 #else
110 " -h this message\n"
111 #endif
112 " -L list available sequences and exit\n"
113 " with -v ... dump sequence contents\n"
114 #ifdef HAVE_GETOPT_LONG
115 " --remove-trailing (deprecated)\n"
116 " remove trailing _ and - before a period\n"
117 #endif
118 " -s sequence choose which sequence to detox with\n"
119 " -v be verbose\n"
120 " -V show the current version\n"
121 };
122
123 /* *INDENT-ON* */
124
initialize_main_options(void)125 struct detox_options *initialize_main_options(void)
126 {
127 struct detox_options *main_options;
128
129 main_options = malloc(sizeof(struct detox_options));
130 if (main_options == NULL) {
131 fprintf(stderr, "out of memory: %s\n", strerror(errno));
132 return NULL;
133 }
134
135 memset(main_options, 0, sizeof(struct detox_options));
136
137 /*
138 * XXX - handle blank strings better
139 */
140 main_options->sequence_name = getenv("DETOX_SEQUENCE");
141
142 return main_options;
143 }
144
parse_options_getopt(int argc,char ** argv)145 struct detox_options *parse_options_getopt(int argc, char **argv)
146 {
147 int optcode;
148
149 struct detox_options *main_options;
150
151 int i;
152 int max = 10;
153 char *binname;
154
155 main_options = initialize_main_options();
156 if (main_options == NULL) {
157 return NULL;
158 }
159
160 binname = basename(argv[0]);
161 main_options->is_inline_bin = main_options->is_inline_mode =
162 (strcmp(binname, INLINE_DETOX_BIN) == 0);
163
164 #ifdef HAVE_GETOPT_LONG
165 while ((optcode = getopt_long(argc, argv, "hrvV?Ls:f:n", longopts, NULL)) != -1) {
166 #else
167 while ((optcode = getopt(argc, argv, "hrvV?Ls:f:n")) != -1) {
168 #endif
169 switch (optcode) {
170 case 'h':
171 printf("%s", !main_options->is_inline_bin ? usage_message :
172 usage_message_inline);
173 printf("\n");
174 printf("%s", !main_options->is_inline_bin ? help_message :
175 help_message_inline);
176 exit(EXIT_SUCCESS);
177
178 case 'f':
179 /*
180 * XXX - free multiple check_config_files
181 */
182 main_options->check_config_file = strdup(optarg);
183 break;
184
185 case 'L':
186 main_options->list_sequences = 1;
187 break;
188
189 case 'n':
190 main_options->dry_run = 1;
191 break;
192
193 case 'r':
194 main_options->recurse = 1;
195 break;
196
197 case 's':
198 /*
199 * XXX - free multiple sequence name opts
200 */
201 main_options->sequence_name = strdup(optarg);
202 break;
203
204 case 'v':
205 main_options->verbose++;
206 break;
207
208 case 'V':
209 printf("%s\n", PACKAGE_STRING);
210 exit(EXIT_SUCCESS);
211
212 case '?':
213 printf("%s", !main_options->is_inline_bin ? usage_message :
214 usage_message_inline);
215 exit(EXIT_SUCCESS);
216
217 case 0:
218 switch (long_option) {
219 case LONG_OPTION_INLINE:
220 main_options->is_inline_mode = 1;
221 break;
222
223 case LONG_OPTION_REMOVE_TRAILING:
224 main_options->remove_trailing = 1;
225 break;
226
227 case LONG_OPTION_SPECIAL:
228 main_options->special = 1;
229 break;
230
231 default:
232 /*
233 * getopt_long shouldn't let us get here...
234 * verify?
235 */
236 printf("unknown option: %s\n", optarg);
237 break;
238 }
239 long_option = 0; /* clean up! */
240 break;
241
242 default:
243 fprintf(stderr, "unknown option: %c\n", optcode);
244 exit(EXIT_FAILURE);
245 }
246 }
247
248 if (main_options->list_sequences) {
249 /*
250 * Early Retirement
251 */
252 return main_options;
253 }
254
255 main_options->files = malloc(sizeof(char *) * 10);
256
257 i = 0;
258 max = 10;
259
260 if (optind < argc) {
261 while (optind < argc) {
262 /* not enough space for the next file and
263 possible ending NULL -> realloc */
264 if (i + 2 > max) {
265 main_options->files = realloc(main_options->files, sizeof(char *) * (10 + max));
266 max += 10;
267 }
268 main_options->files[i++] = strdup(argv[optind]);
269
270 optind++;
271 }
272
273 main_options->files[i] = NULL;
274 }
275 else if (!main_options->is_inline_mode) {
276 printf("%s", !main_options->is_inline_bin ? usage_message :
277 usage_message_inline);
278 exit(EXIT_FAILURE);
279 }
280
281 return main_options;
282 }
283