]> git.saurik.com Git - apple/security.git/blob - lib/SecArgParse.c
Security-59754.41.1.tar.gz
[apple/security.git] / lib / SecArgParse.c
1 /*
2 * Copyright (c) 2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #define __STDC_WANT_LIB_EXT1__ 1
25 #include <string.h>
26
27 #include "SecArgParse.h"
28
29 // Trinary:
30 // If flag is set and argument is not, it has no_argument
31 // If flag is set and argument is set, it is optional_argument
32 // If flag is not set and argument is set, it is required_argument
33 // If flag is not set and argument is not set, what are you doing? There's no output.
34
35 static int argument_status(struct argument* option) {
36 if(option == NULL) {
37 return no_argument;
38 }
39 return (!!(option->flag) && !(option->argument) ? no_argument :
40 (!!(option->flag) && !!(option->argument) ? optional_argument :
41 ( !(option->flag) && !!(option->argument) ? required_argument :
42 no_argument)));
43 }
44
45 static bool fill_long_option_array(struct argument* options, size_t noptions, struct option long_options[], size_t nloptions) {
46 size_t i = 0;
47 size_t longi = 0;
48
49 for(i = 0; i <= noptions; i++) {
50 if(longi >= nloptions) {
51 return false;
52 }
53
54 if(options[i].longname) {
55 long_options[longi].name = options[i].longname;
56 long_options[longi].has_arg = argument_status(&options[i]);
57 long_options[longi].flag = options[i].flag;
58 long_options[longi].val = options[i].flagval;
59 longi++;
60 }
61 }
62
63 if(longi >= nloptions) {
64 return false;
65 }
66
67 long_options[longi].name = NULL;
68 long_options[longi].has_arg = 0;
69 long_options[longi].flag = 0;
70 long_options[longi].val = 0;
71
72 return true;
73 }
74
75 static bool fill_short_option_array(struct argument* options, size_t noptions, char* short_options, size_t nshort_options) {
76 size_t index = 0;
77 for(size_t i = 0; i < noptions; i++) {
78 if(options[i].shortname != '\0') {
79 if(index >= nshort_options) {
80 return false;
81 }
82 short_options[index] = options[i].shortname;
83 index += 1;
84
85 if(argument_status(&options[i]) == required_argument) {
86 if(index >= nshort_options) {
87 return false;
88 }
89 short_options[index] = ':';
90 index += 1;
91 }
92 }
93 }
94 short_options[index] = '\0';
95 return true;
96 }
97
98 static void trigger(struct argument option, char* argument) {
99 if(option.flag) {
100 *(option.flag) = option.flagval;
101 }
102 if(option.argument) {
103 asprintf(option.argument, "%.1048576s", argument);
104 }
105 }
106
107 static size_t num_arguments(struct arguments* args) {
108 size_t n = 0;
109
110 if(!args) {
111 return 0;
112 }
113
114 struct argument* a = args->arguments;
115 // Make an all-zero struct
116 struct argument final = {};
117
118 // Only 1024 arguments allowed.
119 while(a && n < 1024 && (memcmp(a, &final, sizeof(struct argument)) != 0)) {
120 n++;
121 a++;
122 }
123
124 return n;
125 }
126
127 bool options_parse(int argc, char * const *argv, struct arguments* args) {
128 if(!args) {
129 return false;
130 }
131 bool success = false;
132
133 struct arguments realargs;
134 realargs.programname = args->programname;
135 realargs.description = args->description;
136 size_t num_args = num_arguments(args);
137 size_t noptions = num_args + 1;
138 realargs.arguments = (struct argument*) malloc((noptions +1) * sizeof(struct argument)); // extra array slot for null array
139
140 struct argument help = {.shortname = 'h', .longname="help", .description="show this help message and exit"};
141
142 realargs.arguments[0] = help;
143 // Adds one to include the null terminator struct!
144 for(size_t i = 0; i < num_args + 1; i++) {
145 realargs.arguments[i+1] = args->arguments[i];
146 }
147
148 struct option* long_options = (struct option*) calloc((noptions+1), sizeof(struct option));
149 size_t short_options_length = 2* noptions * sizeof(char) + 2; // 2: one for -h, one for the null terminator
150 char* short_options = (char*) malloc(short_options_length);
151
152 fill_long_option_array(realargs.arguments, noptions, long_options, noptions);
153 fill_short_option_array(realargs.arguments, noptions, short_options, short_options_length);
154
155 int c;
156 int option_index = 0;
157 while((c = getopt_long(argc, argv, short_options, long_options, &option_index)) != -1) {
158 // We have a short arg or an arg with an argument. Parse it.
159 if(c==0) {
160 if(option_index == 0) {
161 // This is the --help option
162 print_usage(&realargs);
163 exit(1);
164 } else {
165 struct option* long_option = &long_options[option_index];
166
167 for(size_t i = 0; i < noptions; i++) {
168 if(realargs.arguments[i].longname && long_option->name && strncmp(long_option->name, realargs.arguments[i].longname, strlen(realargs.arguments[i].longname)) == 0) {
169 trigger(realargs.arguments[i], optarg);
170 }
171 }
172 }
173 } else {
174 // Handle short name
175 if(c == 'h') {
176 // This is the --help option
177 print_usage(&realargs);
178 exit(1);
179 }
180 size_t i = 0;
181 for(i = 0; i < noptions; i++) {
182 if(realargs.arguments[i].shortname == c) {
183 trigger(realargs.arguments[i], optarg);
184 break;
185 }
186 }
187 if(i == noptions) {
188 success = false;
189 goto out;
190 }
191 }
192 }
193
194 if(optind < argc) {
195 bool command_triggered = false;
196 size_t positional_argument_index = 0;
197
198 for(int parg = optind; parg < argc; parg++) {
199 for(size_t i = 0; i < noptions; i++) {
200 if(realargs.arguments[i].command) {
201 if(strcmp(argv[parg], realargs.arguments[i].command) == 0) {
202 trigger(realargs.arguments[i], NULL);
203 command_triggered = true;
204 break;
205 }
206 }
207 }
208
209 if(command_triggered) {
210 break;
211 }
212
213 while(positional_argument_index < noptions && !realargs.arguments[positional_argument_index].positional_name) {
214 positional_argument_index++;
215 }
216
217 if(positional_argument_index >= noptions) {
218 // no positional argument found to save
219 // explode
220 goto out;
221 } else {
222 if(realargs.arguments[positional_argument_index].argument) {
223 *(realargs.arguments[positional_argument_index].argument) = argv[parg];
224 positional_argument_index++;
225 }
226
227 }
228 }
229 }
230
231 success = true;
232
233 out:
234 free(realargs.arguments);
235 free(long_options);
236 free(short_options);
237
238 return success;
239 }
240
241 void print_usage(struct arguments* args) {
242 if(!args) {
243 return;
244 }
245 printf("usage: %s", args->programname ? args->programname : "command");
246
247 size_t num_args = num_arguments(args);
248
249 // Print all short options
250 for(size_t i = 0; i < num_args; i++) {
251 if(args->arguments[i].shortname) {
252 printf(" [-%c", args->arguments[i].shortname);
253
254 if(argument_status(&args->arguments[i]) != no_argument) {
255 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
256 }
257
258 printf("]");
259 }
260 }
261
262 // Print all long args->arguments that don't have short args->arguments
263 for(size_t i = 0; i < num_args; i++) {
264 if(args->arguments[i].longname && !args->arguments[i].shortname) {
265
266 printf(" [--%s", args->arguments[i].longname);
267
268 if(argument_status(&args->arguments[i]) != no_argument) {
269 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
270 }
271
272 printf("]");
273 }
274 }
275
276 // Print all commands
277 for(size_t i = 0; i < num_args; i++) {
278 if(args->arguments[i].command) {
279 printf(" [%s]", args->arguments[i].command);
280 }
281 }
282
283 // Print all positional arguments
284 for(size_t i = 0; i < num_args; i++) {
285 if(args->arguments[i].positional_name) {
286 if(args->arguments[i].positional_optional) {
287 printf(" [<%s>]", args->arguments[i].positional_name);
288 } else {
289 printf(" <%s>", args->arguments[i].positional_name);
290 }
291 }
292 }
293
294 printf("\n");
295
296 if(args->description) {
297 printf("\n%s\n", args->description);
298 }
299
300 printf("\npositional arguments:\n");
301 for(size_t i = 0; i < num_args; i++) {
302 if(args->arguments[i].positional_name) {
303 printf(" %-31s %s\n", args->arguments[i].positional_name, args->arguments[i].description);
304 }
305 }
306
307 printf("\noptional arguments:\n");
308 // List all short args->arguments
309 for(size_t i = 0; i < num_args; i++) {
310 if(args->arguments[i].shortname) {
311 if(!args->arguments[i].longname) {
312
313 if(argument_status(&args->arguments[i]) != no_argument) {
314 printf(" -%c %-*s", args->arguments[i].shortname, 28, "arg");
315 } else {
316 printf(" -%-30c", args->arguments[i].shortname);
317 }
318
319 } else {
320 printf(" -%c", args->arguments[i].shortname);
321
322 if(argument_status(&args->arguments[i]) != no_argument) {
323 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
324 }
325
326 if(args->arguments[i].longname) {
327 if(argument_status(&args->arguments[i]) == no_argument) {
328 printf(", --%-*s", 28 - (int) strlen(args->arguments[i].argname ? args->arguments[i].argname : "arg"), args->arguments[i].longname);
329 } else {
330 printf(", --%s %-*s", args->arguments[i].longname, 28 -5 - (int) strlen(args->arguments[i].longname) - (int) strlen(args->arguments[i].argname ? args->arguments[i].argname : "arg"), "arg");
331 }
332 }
333 }
334
335 printf("%s\n", args->arguments[i].description);
336 }
337 }
338
339 // List all long args->arguments
340 for(size_t i = 0; i < num_args; i++) {
341 if(args->arguments[i].longname && !args->arguments[i].shortname) {
342 if(argument_status(&args->arguments[i]) != no_argument) {
343 printf(" --%s %-*s %s\n",
344 args->arguments[i].longname,
345 28 - (int) strlen(args->arguments[i].longname),
346 args->arguments[i].argname ? args->arguments[i].argname : "arg",
347 args->arguments[i].description);
348 } else {
349 printf(" --%-29s %s\n", args->arguments[i].longname, args->arguments[i].description);
350 }
351 }
352 }
353
354 printf("\noptional commands:\n");
355 // Print all commands
356 for(size_t i = 0; i < num_args; i++) {
357 if(args->arguments[i].command) {
358 printf(" %-30s %s\n", args->arguments[i].command, args->arguments[i].description);
359 }
360 }
361
362 printf("\n");
363 }