]> git.ipfire.org Git - thirdparty/openssl.git/blame - apps/opt.c
Use the shlib wrapper when running nptest
[thirdparty/openssl.git] / apps / opt.c
CommitLineData
7e1b7485
RS
1/* ====================================================================
2 * Copyright (c) 2015 The OpenSSL Project. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. All advertising materials mentioning features or use of this
17 * software must display the following acknowledgment:
18 * "This product includes software developed by the OpenSSL Project
19 * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
20 *
21 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
22 * endorse or promote products derived from this software without
23 * prior written permission. For written permission, please contact
24 * licensing@OpenSSL.org.
25 *
26 * 5. Products derived from this software may not be called "OpenSSL"
27 * nor may "OpenSSL" appear in their names without prior written
28 * permission of the OpenSSL Project.
29 *
30 * 6. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by the OpenSSL Project
33 * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
36 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
38 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
41 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
44 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
46 * OF THE POSSIBILITY OF SUCH DAMAGE.
47 * ====================================================================
48 */
49
50/* #define COMPILE_STANDALONE_TEST_DRIVER */
51#include "apps.h"
7e1b7485
RS
52#include <string.h>
53#if !defined(OPENSSL_SYS_MSDOS)
54# include OPENSSL_UNISTD
55#endif
a3ed492f 56
7e1b7485
RS
57#include <stdlib.h>
58#include <errno.h>
59#include <ctype.h>
60#include <openssl/bio.h>
61
62#define MAX_OPT_HELP_WIDTH 30
63const char OPT_HELP_STR[] = "--";
64const char OPT_MORE_STR[] = "---";
65
66/* Our state */
67static char **argv;
68static int argc;
69static int opt_index;
70static char *arg;
71static char *flag;
72static char *dunno;
73static const OPTIONS *unknown;
74static const OPTIONS *opts;
75static char prog[40];
76
77/*
78 * Return the simple name of the program; removing various platform gunk.
79 */
80#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_NETWARE)
81char *opt_progname(const char *argv0)
82{
83 int i;
84 int n;
85 const char *p;
86 char *q;
87
88 /* find the last '/', '\' or ':' */
89 for (p = argv0 + strlen(argv0); --p > argv0;)
90 if (*p == '/' || *p == '\\' || *p == ':') {
91 p++;
92 break;
93 }
94
95 /* Strip off trailing nonsense. */
96 n = strlen(p);
97 if (n > 4 &&
a3ed492f 98 (strcmp(&p[n - 4], ".exe") == 0 || strcmp(&p[n - 4], ".EXE") == 0))
7e1b7485
RS
99 n -= 4;
100#if defined(OPENSSL_SYS_NETWARE)
101 if (n > 4 &&
a3ed492f 102 (strcmp(&p[n - 4], ".nlm") == 0 || strcmp(&p[n - 4], ".NLM") == 0))
7e1b7485
RS
103 n -= 4;
104#endif
105
106 /* Copy over the name, in lowercase. */
107 if (n > sizeof prog - 1)
108 n = sizeof prog - 1;
109 for (q = prog, i = 0; i < n; i++, p++)
a3ed492f 110 *q++ = isupper(*p) ? tolower(*p) : *p;
7e1b7485
RS
111 *q = '\0';
112 return prog;
113}
114
115#elif defined(OPENSSL_SYS_VMS)
116
117char *opt_progname(const char *argv0)
118{
119 const char *p, *q;
120
121 /* Find last special charcter sys:[foo.bar]openssl */
122 for (p = argv0 + strlen(argv0); --p > argv0;)
123 if (*p == ':' || *p == ']' || *p == '>') {
124 p++;
125 break;
126 }
127
128 q = strrchr(p, '.');
129 strncpy(prog, p, sizeof prog - 1);
130 prog[sizeof prog - 1] = '\0';
131 if (q == NULL || q - p >= sizeof prog)
132 prog[q - p] = '\0';
133 return prog;
134}
135
136#else
137
138char *opt_progname(const char *argv0)
139{
140 const char *p;
141
142 /* Could use strchr, but this is like the ones above. */
143 for (p = argv0 + strlen(argv0); --p > argv0;)
144 if (*p == '/') {
145 p++;
146 break;
147 }
148 strncpy(prog, p, sizeof prog - 1);
149 prog[sizeof prog - 1] = '\0';
150 return prog;
151}
152#endif
153
154char *opt_getprog(void)
155{
156 return prog;
157}
158
159/* Set up the arg parsing. */
160char *opt_init(int ac, char **av, const OPTIONS *o)
161{
162 /* Store state. */
163 argc = ac;
164 argv = av;
165 opt_index = 1;
166 opts = o;
167 opt_progname(av[0]);
168 unknown = NULL;
169
170 for (; o->name; ++o) {
171 const OPTIONS *next;
172#ifndef NDEBUG
88806cfc 173 int duplicated, i;
7e1b7485
RS
174#endif
175
176 if (o->name == OPT_HELP_STR || o->name == OPT_MORE_STR)
177 continue;
178#ifndef NDEBUG
179 i = o->valtype;
180
181 /* Make sure options are legit. */
182 assert(o->name[0] != '-');
183 assert(o->retval > 0);
184 assert(i == 0 || i == '-'
185 || i == 'n' || i == 'p' || i == 'u'
186 || i == 's' || i == '<' || i == '>' || i == '/'
187 || i == 'f' || i == 'F');
188
189 /* Make sure there are no duplicates. */
88806cfc 190 for (next = o + 1; next->name; ++next) {
7e1b7485 191 /*
88806cfc 192 * Some compilers inline strcmp and the assert string is too long.
7e1b7485 193 */
88806cfc
RS
194 duplicated = strcmp(o->name, next->name) == 0;
195 assert(!duplicated);
7e1b7485
RS
196 }
197#endif
198 if (o->name[0] == '\0') {
199 assert(unknown == NULL);
200 unknown = o;
201 assert(unknown->valtype == 0 || unknown->valtype == '-');
202 }
203 }
204 return prog;
205}
206
207static OPT_PAIR formats[] = {
208 {"PEM/DER", OPT_FMT_PEMDER},
209 {"pkcs12", OPT_FMT_PKCS12},
210 {"smime", OPT_FMT_SMIME},
211 {"engine", OPT_FMT_ENGINE},
212 {"msblob", OPT_FMT_MSBLOB},
213 {"netscape", OPT_FMT_NETSCAPE},
214 {"nss", OPT_FMT_NSS},
215 {"text", OPT_FMT_TEXT},
216 {"http", OPT_FMT_HTTP},
217 {"pvk", OPT_FMT_PVK},
218 {NULL}
219};
220
221/* Print an error message about a failed format parse. */
222int opt_format_error(const char *s, unsigned long flags)
223{
224 OPT_PAIR *ap;
225
226 if (flags == OPT_FMT_PEMDER)
227 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be pem or der\n",
228 prog, s);
229 else {
230 BIO_printf(bio_err, "%s: Bad format \"%s\"; must be one of:\n",
231 prog, s);
232 for (ap = formats; ap->name; ap++)
233 if (flags & ap->retval)
234 BIO_printf(bio_err, " %s\n", ap->name);
235 }
236 return 0;
237}
238
239/* Parse a format string, put it into *result; return 0 on failure, else 1. */
240int opt_format(const char *s, unsigned long flags, int *result)
241{
242 switch (*s) {
243 default:
244 return 0;
245 case 'D':
246 case 'd':
247 if ((flags & OPT_FMT_PEMDER) == 0)
248 return opt_format_error(s, flags);
249 *result = FORMAT_ASN1;
250 break;
251 case 'T':
252 case 't':
253 if ((flags & OPT_FMT_TEXT) == 0)
254 return opt_format_error(s, flags);
255 *result = FORMAT_TEXT;
256 break;
257 case 'N':
258 case 'n':
0bc2f365
RS
259 if ((flags & OPT_FMT_NSS) == 0)
260 return opt_format_error(s, flags);
261 if (strcmp(s, "NSS") != 0 && strcmp(s, "nss") != 0)
262 return opt_format_error(s, flags);
263 *result = FORMAT_NSS;
7e1b7485
RS
264 break;
265 case 'S':
266 case 's':
267 if ((flags & OPT_FMT_SMIME) == 0)
268 return opt_format_error(s, flags);
269 *result = FORMAT_SMIME;
270 break;
271 case 'M':
272 case 'm':
273 if ((flags & OPT_FMT_MSBLOB) == 0)
274 return opt_format_error(s, flags);
275 *result = FORMAT_MSBLOB;
276 break;
277 case 'E':
278 case 'e':
279 if ((flags & OPT_FMT_ENGINE) == 0)
280 return opt_format_error(s, flags);
281 *result = FORMAT_ENGINE;
282 break;
283 case 'H':
284 case 'h':
285 if ((flags & OPT_FMT_HTTP) == 0)
286 return opt_format_error(s, flags);
287 *result = FORMAT_HTTP;
288 break;
289 case '1':
290 if ((flags & OPT_FMT_PKCS12) == 0)
291 return opt_format_error(s, flags);
292 *result = FORMAT_PKCS12;
293 break;
294 case 'P':
295 case 'p':
296 if (s[1] == '\0' || strcmp(s, "PEM") == 0 || strcmp(s, "pem") == 0) {
297 if ((flags & OPT_FMT_PEMDER) == 0)
298 return opt_format_error(s, flags);
299 *result = FORMAT_PEM;
300 } else if (strcmp(s, "PVK") == 0 || strcmp(s, "pvk") == 0) {
301 if ((flags & OPT_FMT_PVK) == 0)
302 return opt_format_error(s, flags);
303 *result = FORMAT_PVK;
304 } else if (strcmp(s, "P12") == 0 || strcmp(s, "p12") == 0
305 || strcmp(s, "PKCS12") == 0 || strcmp(s, "pkcs12") == 0) {
306 if ((flags & OPT_FMT_PKCS12) == 0)
307 return opt_format_error(s, flags);
308 *result = FORMAT_PKCS12;
309 } else
310 return 0;
311 break;
312 }
313 return 1;
314}
315
316/* Parse a cipher name, put it in *EVP_CIPHER; return 0 on failure, else 1. */
317int opt_cipher(const char *name, const EVP_CIPHER **cipherp)
318{
319 *cipherp = EVP_get_cipherbyname(name);
320 if (*cipherp)
321 return 1;
322 BIO_printf(bio_err, "%s: Unknown cipher %s\n", prog, name);
323 return 0;
324}
325
326/*
327 * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1.
328 */
329int opt_md(const char *name, const EVP_MD **mdp)
330{
331 *mdp = EVP_get_digestbyname(name);
332 if (*mdp)
333 return 1;
334 BIO_printf(bio_err, "%s: Unknown digest %s\n", prog, name);
335 return 0;
336}
337
338/* Look through a list of name/value pairs. */
339int opt_pair(const char *name, const OPT_PAIR* pairs, int *result)
340{
341 const OPT_PAIR *pp;
342
343 for (pp = pairs; pp->name; pp++)
344 if (strcmp(pp->name, name) == 0) {
345 *result = pp->retval;
346 return 1;
347 }
348 BIO_printf(bio_err, "%s: Value must be one of:\n", prog);
349 for (pp = pairs; pp->name; pp++)
350 BIO_printf(bio_err, "\t%s\n", pp->name);
351 return 0;
352}
353
354/* See if cp looks like a hex number, in case user left off the 0x */
355static int scanforhex(const char *cp)
356{
357 if (*cp == '0' && (cp[1] == 'x' || cp[1] == 'X'))
358 return 16;
359 for (; *cp; cp++)
360 /* Look for a hex digit that isn't a regular digit. */
361 if (isxdigit(*cp) && !isdigit(*cp))
362 return 16;
363 return 0;
364}
365
366/* Parse an int, put it into *result; return 0 on failure, else 1. */
367int opt_int(const char *value, int *result)
368{
369 const char *fmt = "%d";
370 int base = scanforhex(value);
371
372 if (base == 16)
373 fmt = "%x";
374 else if (*value == '0')
375 fmt = "%o";
376 if (sscanf(value, fmt, result) != 1) {
377 BIO_printf(bio_err, "%s: Can't parse \"%s\" as a number\n",
378 prog, value);
379 return 0;
380 }
381 return 1;
382}
383
384/* Parse a long, put it into *result; return 0 on failure, else 1. */
385int opt_long(const char *value, long *result)
386{
387 char *endptr;
388 int base = scanforhex(value);
389
390 *result = strtol(value, &endptr, base);
391 if (*endptr) {
392 BIO_printf(bio_err,
393 "%s: Bad char %c in number %s\n", prog, *endptr, value);
394 return 0;
395 }
396 return 1;
397}
398
399/*
400 * Parse an unsigned long, put it into *result; return 0 on failure, else 1.
401 */
402int opt_ulong(const char *value, unsigned long *result)
403{
404 char *endptr;
405 int base = scanforhex(value);
406
407 *result = strtoul(value, &endptr, base);
408 if (*endptr) {
409 BIO_printf(bio_err,
410 "%s: Bad char %c in number %s\n", prog, *endptr, value);
411 return 0;
412 }
413 return 1;
414}
415
416/*
417 * We pass opt as an int but cast it to "enum range" so that all the
418 * items in the OPT_V_ENUM enumeration are caught; this makes -Wswitch
419 * in gcc do the right thing.
420 */
421enum range { OPT_V_ENUM };
422
423int opt_verify(int opt, X509_VERIFY_PARAM *vpm)
424{
425 unsigned long ul;
426 int i;
427 ASN1_OBJECT *otmp;
428 X509_PURPOSE *xptmp;
429 const X509_VERIFY_PARAM *vtmp;
430
431 assert(vpm != NULL);
432 assert(opt > OPT_V__FIRST);
433 assert(opt < OPT_V__LAST);
434
435 switch ((enum range)opt) {
436 case OPT_V__FIRST:
437 case OPT_V__LAST:
438 return 0;
439 case OPT_V_POLICY:
440 otmp = OBJ_txt2obj(opt_arg(), 0);
441 if (otmp == NULL) {
442 BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg());
443 return 0;
444 }
445 X509_VERIFY_PARAM_add0_policy(vpm, otmp);
446 break;
447 case OPT_V_PURPOSE:
448 i = X509_PURPOSE_get_by_sname(opt_arg());
449 if (i < 0) {
450 BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg());
451 return 0;
452 }
453 xptmp = X509_PURPOSE_get0(i);
454 i = X509_PURPOSE_get_id(xptmp);
455 X509_VERIFY_PARAM_set_purpose(vpm, i);
456 break;
457 case OPT_V_VERIFY_NAME:
458 vtmp = X509_VERIFY_PARAM_lookup(opt_arg());
459 if (vtmp == NULL) {
460 BIO_printf(bio_err, "%s: Invalid verify name %s\n",
461 prog, opt_arg());
462 return 0;
463 }
464 X509_VERIFY_PARAM_set1(vpm, vtmp);
465 break;
466 case OPT_V_VERIFY_DEPTH:
467 i = atoi(opt_arg());
468 if (i >= 0)
469 X509_VERIFY_PARAM_set_depth(vpm, i);
470 break;
471 case OPT_V_ATTIME:
472 opt_ulong(opt_arg(), &ul);
473 if (ul)
474 X509_VERIFY_PARAM_set_time(vpm, (time_t)ul);
475 break;
476 case OPT_V_VERIFY_HOSTNAME:
477 if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0))
478 return 0;
479 break;
480 case OPT_V_VERIFY_EMAIL:
481 if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0))
482 return 0;
483 break;
484 case OPT_V_VERIFY_IP:
485 if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg()))
486 return 0;
487 break;
488 case OPT_V_IGNORE_CRITICAL:
489 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL);
490 break;
491 case OPT_V_ISSUER_CHECKS:
492 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CB_ISSUER_CHECK);
493 break;
494 case OPT_V_CRL_CHECK:
495 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK);
496 break;
497 case OPT_V_CRL_CHECK_ALL:
498 X509_VERIFY_PARAM_set_flags(vpm,
499 X509_V_FLAG_CRL_CHECK |
500 X509_V_FLAG_CRL_CHECK_ALL);
501 break;
502 case OPT_V_POLICY_CHECK:
503 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK);
504 break;
505 case OPT_V_EXPLICIT_POLICY:
506 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY);
507 break;
508 case OPT_V_INHIBIT_ANY:
509 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY);
510 break;
511 case OPT_V_INHIBIT_MAP:
512 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP);
513 break;
514 case OPT_V_X509_STRICT:
515 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT);
516 break;
517 case OPT_V_EXTENDED_CRL:
518 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT);
519 break;
520 case OPT_V_USE_DELTAS:
521 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS);
522 break;
523 case OPT_V_POLICY_PRINT:
524 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY);
525 break;
526 case OPT_V_CHECK_SS_SIG:
527 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE);
528 break;
529 case OPT_V_TRUSTED_FIRST:
530 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST);
531 break;
532 case OPT_V_SUITEB_128_ONLY:
533 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY);
534 break;
535 case OPT_V_SUITEB_128:
536 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS);
537 break;
538 case OPT_V_SUITEB_192:
539 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS);
540 break;
541 case OPT_V_PARTIAL_CHAIN:
542 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
543 break;
544 case OPT_V_NO_ALT_CHAINS:
545 X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS);
546 }
547 return 1;
548
549}
550
551/*
552 * Parse the next flag (and value if specified), return 0 if done, -1 on
553 * error, otherwise the flag's retval.
554 */
555int opt_next(void)
556{
557 char *p;
558 char *endptr;
559 const OPTIONS *o;
560 int dummy;
561 int base;
562 long val;
563
564 /* Look at current arg; at end of the list? */
565 arg = NULL;
566 p = argv[opt_index];
567 if (p == NULL)
568 return 0;
569
570 /* If word doesn't start with a -, we're done. */
571 if (*p != '-')
572 return 0;
573
574 /* Hit "--" ? We're done. */
575 opt_index++;
576 if (strcmp(p, "--") == 0)
577 return 0;
578
579 /* Allow -nnn and --nnn */
580 if (*++p == '-')
581 p++;
582 flag = p - 1;
583
584 /* If we have --flag=foo, snip it off */
585 if ((arg = strchr(p, '=')) != NULL)
586 *arg++ = '\0';
587 for (o = opts; o->name; ++o) {
588 /* If not this option, move on to the next one. */
589 if (strcmp(p, o->name) != 0)
590 continue;
591
592 /* If it doesn't take a value, make sure none was given. */
593 if (o->valtype == 0 || o->valtype == '-') {
594 if (arg) {
595 BIO_printf(bio_err,
596 "%s: Option -%s does not take a value\n", prog, p);
597 return -1;
598 }
599 return o->retval;
600 }
601
602 /* Want a value; get the next param if =foo not used. */
603 if (arg == NULL) {
604 if (argv[opt_index] == NULL) {
605 BIO_printf(bio_err,
606 "%s: Option -%s needs a value\n", prog, o->name);
607 return -1;
608 }
609 arg = argv[opt_index++];
610 }
611
612 /* Syntax-check value. */
613 /*
614 * Do some basic syntax-checking on the value. These tests aren't
615 * perfect (ignore range overflow) but they catch common failures.
616 */
617 switch (o->valtype) {
618 default:
619 case 's':
620 /* Just a string. */
621 break;
622 case '/':
623 if (app_isdir(arg) >= 0)
624 break;
625 BIO_printf(bio_err, "%s: Not a directory: %s\n", prog, arg);
626 return -1;
627 case '<':
628 /* Input file. */
629 if (strcmp(arg, "-") == 0 || app_access(arg, R_OK) >= 0)
630 break;
631 BIO_printf(bio_err,
632 "%s: Cannot open input file %s, %s\n",
633 prog, arg, strerror(errno));
634 return -1;
635 case '>':
636 /* Output file. */
637 if (strcmp(arg, "-") == 0 || app_access(arg, W_OK) >= 0 || errno == ENOENT)
638 break;
639 BIO_printf(bio_err,
640 "%s: Cannot open output file %s, %s\n",
641 prog, arg, strerror(errno));
642 return -1;
643 case 'p':
644 case 'n':
645 base = scanforhex(arg);
646 val = strtol(arg, &endptr, base);
647 if (*endptr == '\0') {
648 if (o->valtype == 'p' && val <= 0) {
649 BIO_printf(bio_err,
650 "%s: Non-positive number \"%s\" for -%s\n",
651 prog, arg, o->name);
652 return -1;
653 }
654 break;
655 }
656 BIO_printf(bio_err,
657 "%s: Invalid number \"%s\" for -%s\n",
658 prog, arg, o->name);
659 return -1;
660 case 'u':
661 base = scanforhex(arg);
662 strtoul(arg, &endptr, base);
663 if (*endptr == '\0')
664 break;
665 BIO_printf(bio_err,
666 "%s: Invalid number \"%s\" for -%s\n",
667 prog, arg, o->name);
668 return -1;
669 case 'f':
670 case 'F':
671 if (opt_format(arg,
672 o->valtype == 'F' ? OPT_FMT_PEMDER
673 : OPT_FMT_ANY, &dummy))
674 break;
675 BIO_printf(bio_err,
676 "%s: Invalid format \"%s\" for -%s\n",
677 prog, arg, o->name);
678 return -1;
679 }
680
681 /* Return the flag value. */
682 return o->retval;
683 }
684 if (unknown != NULL) {
685 dunno = p;
686 return unknown->retval;
687 }
688 BIO_printf(bio_err, "%s: Option unknown option -%s\n", prog, p);
689 return -1;
690}
691
692/* Return the most recent flag parameter. */
693char *opt_arg(void)
694{
695 return arg;
696}
697
698/* Return the most recent flag. */
699char *opt_flag(void)
700{
701 return flag;
702}
703
704/* Return the unknown option. */
705char *opt_unknown(void)
706{
707 return dunno;
708}
709
710/* Return the rest of the arguments after parsing flags. */
711char **opt_rest(void)
712{
713 return &argv[opt_index];
714}
715
716/* How many items in remaining args? */
717int opt_num_rest(void)
718{
719 int i = 0;
720 char **pp;
721
722 for (pp = opt_rest(); *pp; pp++, i++)
723 continue;
724 return i;
725}
726
727/* Return a string describing the parameter type. */
728static const char *valtype2param(const OPTIONS *o)
729{
730 switch (o->valtype) {
731 case '-':
732 return "";
733 case 's':
734 return "val";
735 case '/':
736 return "dir";
737 case '<':
738 return "infile";
739 case '>':
740 return "outfile";
741 case 'p':
742 return "pnum";
743 case 'n':
744 return "num";
745 case 'u':
746 return "unum";
747 case 'F':
748 return "der/pem";
749 case 'f':
750 return "format";
751 }
752 return "parm";
753}
754
755void opt_help(const OPTIONS *list)
756{
757 const OPTIONS *o;
758 int i;
759 int standard_prolog;
760 int width = 5;
761 char start[80 + 1];
762 char *p;
763 const char *help;
764
765 /* Starts with its own help message? */
766 standard_prolog = list[0].name != OPT_HELP_STR;
767
768 /* Find the widest help. */
769 for (o = list; o->name; o++) {
770 if (o->name == OPT_MORE_STR)
771 continue;
772 i = 2 + (int)strlen(o->name);
773 if (o->valtype != '-')
774 i += 1 + strlen(valtype2param(o));
775 if (i < MAX_OPT_HELP_WIDTH && i > width)
776 width = i;
777 assert(i < (int)sizeof start);
778 }
779
780 if (standard_prolog)
781 BIO_printf(bio_err, "Usage: %s [options]\nValid options are:\n",
782 prog);
783
784 /* Now let's print. */
785 for (o = list; o->name; o++) {
786 help = o->helpstr ? o->helpstr : "(No additional info)";
787 if (o->name == OPT_HELP_STR) {
788 BIO_printf(bio_err, help, prog);
789 continue;
790 }
791
792 /* Pad out prefix */
16f8d4eb 793 memset(start, ' ', sizeof(start) - 1);
7e1b7485
RS
794 start[sizeof start - 1] = '\0';
795
796 if (o->name == OPT_MORE_STR) {
797 /* Continuation of previous line; padd and print. */
798 start[width] = '\0';
799 BIO_printf(bio_err, "%s %s\n", start, help);
800 continue;
801 }
802
803 /* Build up the "-flag [param]" part. */
804 p = start;
805 *p++ = ' ';
806 *p++ = '-';
807 if (o->name[0])
808 p += strlen(strcpy(p, o->name));
809 else
810 *p++ = '*';
811 if (o->valtype != '-') {
812 *p++ = ' ';
813 p += strlen(strcpy(p, valtype2param(o)));
814 }
815 *p = ' ';
816 if ((int)(p - start) >= MAX_OPT_HELP_WIDTH) {
817 *p = '\0';
818 BIO_printf(bio_err, "%s\n", start);
16f8d4eb 819 memset(start, ' ', sizeof(start));
7e1b7485
RS
820 }
821 start[width] = '\0';
822 BIO_printf(bio_err, "%s %s\n", start, help);
823 }
824}
825
826#ifdef COMPILE_STANDALONE_TEST_DRIVER
827# include <sys/stat.h>
828
829typedef enum OPTION_choice {
830 OPT_ERR = -1, OPT_EOF = 0, OPT_HELP,
831 OPT_IN, OPT_INFORM, OPT_OUT, OPT_COUNT, OPT_U, OPT_FLAG,
832 OPT_STR, OPT_NOTUSED
833} OPTION_CHOICE;
834
835static OPTIONS options[] = {
836 {OPT_HELP_STR, 1, '-', "Usage: %s flags\n"},
837 {OPT_HELP_STR, 1, '-', "Valid options are:\n"},
838 {"help", OPT_HELP, '-', "Display this summary"},
839 {"in", OPT_IN, '<', "input file"},
840 {OPT_MORE_STR, 1, '-', "more detail about input"},
841 {"inform", OPT_INFORM, 'f', "input file format; defaults to pem"},
842 {"out", OPT_OUT, '>', "output file"},
843 {"count", OPT_COUNT, 'p', "a counter greater than zero"},
844 {"u", OPT_U, 'u', "an unsigned number"},
845 {"flag", OPT_FLAG, 0, "just some flag"},
846 {"str", OPT_STR, 's', "the magic word"},
847 {"areallyverylongoption", OPT_HELP, '-', "long way for help"},
848 {NULL}
849};
850
851BIO *bio_err;
852
853int app_isdir(const char *name)
854{
855 struct stat sb;
856
857 return name != NULL && stat(name, &sb) >= 0 && S_ISDIR(sb.st_mode);
858}
859
860int main(int ac, char **av)
861{
862 OPTION_CHOICE o;
863 char **rest;
864 char *prog;
865
866 bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
867
868 prog = opt_init(ac, av, options);
869 while ((o = opt_next()) != OPT_EOF) {
870 switch (c) {
871 case OPT_NOTUSED:
872 case OPT_EOF:
873 case OPT_ERR:
874 printf("%s: Usage error; try -help.\n", prog);
875 return 1;
876 case OPT_HELP:
877 opt_help(options);
878 return 0;
879 case OPT_IN:
880 printf("in %s\n", opt_arg());
881 break;
882 case OPT_INFORM:
883 printf("inform %s\n", opt_arg());
884 break;
885 case OPT_OUT:
886 printf("out %s\n", opt_arg());
887 break;
888 case OPT_COUNT:
889 printf("count %s\n", opt_arg());
890 break;
891 case OPT_U:
892 printf("u %s\n", opt_arg());
893 break;
894 case OPT_FLAG:
895 printf("flag\n");
896 break;
897 case OPT_STR:
898 printf("str %s\n", opt_arg());
899 break;
900 }
901 }
902 argc = opt_num_rest();
903 argv = opt_rest();
904
905 printf("args = %d\n", argc);
906 if (argc)
907 while (*argv)
908 printf(" %s\n", *argv++);
909 return 0;
910}
911#endif