]> git.saurik.com Git - apple/security.git/blob - lib/SecArgParse.c
Security-58286.41.2.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*) malloc((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 && 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 return false;
189 }
190 }
191 }
192
193 if(optind < argc) {
194 bool command_triggered = false;
195 size_t positional_argument_index = 0;
196
197 for(int parg = optind; parg < argc; parg++) {
198 for(size_t i = 0; i < noptions; i++) {
199 if(realargs.arguments[i].command) {
200 if(strcmp(argv[parg], realargs.arguments[i].command) == 0) {
201 trigger(realargs.arguments[i], NULL);
202 command_triggered = true;
203 break;
204 }
205 }
206 }
207
208 if(command_triggered) {
209 break;
210 }
211
212 while(positional_argument_index < noptions && !realargs.arguments[positional_argument_index].positional_name) {
213 positional_argument_index++;
214 }
215
216 if(positional_argument_index >= noptions) {
217 // no positional argument found to save
218 // explode
219 goto out;
220 } else {
221 if(realargs.arguments[positional_argument_index].argument) {
222 *(realargs.arguments[positional_argument_index].argument) = argv[parg];
223 positional_argument_index++;
224 }
225
226 }
227 }
228 }
229
230 success = true;
231
232 out:
233 free(realargs.arguments);
234 free(long_options);
235 free(short_options);
236
237 return success;
238 }
239
240 void print_usage(struct arguments* args) {
241 if(!args) {
242 return;
243 }
244 printf("usage: %s", args->programname ? args->programname : "command");
245
246 size_t num_args = num_arguments(args);
247
248 // Print all short options
249 for(size_t i = 0; i < num_args; i++) {
250 if(args->arguments[i].shortname) {
251 printf(" [-%c", args->arguments[i].shortname);
252
253 if(argument_status(&args->arguments[i]) != no_argument) {
254 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
255 }
256
257 printf("]");
258 }
259 }
260
261 // Print all long args->arguments that don't have short args->arguments
262 for(size_t i = 0; i < num_args; i++) {
263 if(args->arguments[i].longname && !args->arguments[i].shortname) {
264
265 printf(" [--%s", args->arguments[i].longname);
266
267 if(argument_status(&args->arguments[i]) != no_argument) {
268 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
269 }
270
271 printf("]");
272 }
273 }
274
275 // Print all commands
276 for(size_t i = 0; i < num_args; i++) {
277 if(args->arguments[i].command) {
278 printf(" [%s]", args->arguments[i].command);
279 }
280 }
281
282 // Print all positional arguments
283 for(size_t i = 0; i < num_args; i++) {
284 if(args->arguments[i].positional_name) {
285 if(args->arguments[i].positional_optional) {
286 printf(" [<%s>]", args->arguments[i].positional_name);
287 } else {
288 printf(" <%s>", args->arguments[i].positional_name);
289 }
290 }
291 }
292
293 printf("\n");
294
295 if(args->description) {
296 printf("\n%s\n", args->description);
297 }
298
299 printf("\npositional arguments:\n");
300 for(size_t i = 0; i < num_args; i++) {
301 if(args->arguments[i].positional_name) {
302 printf(" %-31s %s\n", args->arguments[i].positional_name, args->arguments[i].description);
303 }
304 }
305
306 printf("\noptional arguments:\n");
307 // List all short args->arguments
308 for(size_t i = 0; i < num_args; i++) {
309 if(args->arguments[i].shortname) {
310 if(!args->arguments[i].longname) {
311
312 if(argument_status(&args->arguments[i]) != no_argument) {
313 printf(" -%c %-*s", args->arguments[i].shortname, 28, "arg");
314 } else {
315 printf(" -%-30c", args->arguments[i].shortname);
316 }
317
318 } else {
319 printf(" -%c", args->arguments[i].shortname);
320
321 if(argument_status(&args->arguments[i]) != no_argument) {
322 printf(" %s", args->arguments[i].argname ? args->arguments[i].argname : "arg");
323 }
324
325 if(args->arguments[i].longname) {
326 if(argument_status(&args->arguments[i]) == no_argument) {
327 printf(", --%-*s", 28 - (int) strlen(args->arguments[i].argname ? args->arguments[i].argname : "arg"), args->arguments[i].longname);
328 } else {
329 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");
330 }
331 }
332 }
333
334 printf("%s\n", args->arguments[i].description);
335 }
336 }
337
338 // List all long args->arguments
339 for(size_t i = 0; i < num_args; i++) {
340 if(args->arguments[i].longname && !args->arguments[i].shortname) {
341 if(argument_status(&args->arguments[i]) != no_argument) {
342 printf(" --%s %-*s %s\n",
343 args->arguments[i].longname,
344 28 - (int) strlen(args->arguments[i].longname),
345 args->arguments[i].argname ? args->arguments[i].argname : "arg",
346 args->arguments[i].description);
347 } else {
348 printf(" --%-29s %s\n", args->arguments[i].longname, args->arguments[i].description);
349 }
350 }
351 }
352
353 printf("\noptional commands:\n");
354 // Print all commands
355 for(size_t i = 0; i < num_args; i++) {
356 if(args->arguments[i].command) {
357 printf(" %-30s %s\n", args->arguments[i].command, args->arguments[i].description);
358 }
359 }
360
361 printf("\n");
362 }