Browse Source

APPS: Document the core of the opt_ API

Reviewed-by: Tomas Mraz <>
Reviewed-by: David von Oheimb <>
(Merged from
Rich Salz 1 year ago
committed by Dr. David von Oheimb
4 changed files with 306 additions and 7 deletions
  1. +2
  2. +0
  3. +3
  4. +301

+ 2
- 1
apps/include/fmt.h View File

@ -17,7 +17,8 @@
/* On some platforms, it's important to distinguish between text and binary
* On some platforms, it's important to distinguish between text and binary
* files. On some, there might even be specific file formats for different
* contents. The FORMAT_xxx macros are meant to express an intent with the
* file being read or created.

+ 0
- 3
apps/include/opt.h View File

@ -349,7 +349,6 @@ char *opt_init(int ac, char **av, const OPTIONS * o);
int opt_next(void);
void opt_begin(void);
int opt_format(const char *s, unsigned long flags, int *result);
const char *format2str(int format);
int opt_int(const char *arg, int *result);
int opt_int_arg(void);
int opt_ulong(const char *arg, unsigned long *result);
@ -381,8 +380,6 @@ int opt_verify(int i, X509_VERIFY_PARAM *vpm);
int opt_rand(int i);
int opt_provider(int i);
void opt_help(const OPTIONS * list);
void opt_print(const OPTIONS * opt, int doingparams, int width);
int opt_format_error(const char *s, unsigned long flags);
void print_format_error(int format, unsigned long flags);
int opt_isdir(const char *name);
int opt_printf_stderr(const char *fmt, ...);

+ 3
- 3
apps/lib/opt.c View File

@ -227,7 +227,7 @@ static OPT_PAIR formats[] = {
/* Print an error message about a failed format parse. */
int opt_format_error(const char *s, unsigned long flags)
static int opt_format_error(const char *s, unsigned long flags)
@ -325,7 +325,7 @@ int opt_format(const char *s, unsigned long flags, int *result)
/* Return string representing the given format. */
const char *format2str(int format)
static const char *format2str(int format)
switch (format) {
@ -973,7 +973,7 @@ static const char *valtype2param(const OPTIONS *o)
return "parm";
void opt_print(const OPTIONS *o, int doingparams, int width)
static void opt_print(const OPTIONS *o, int doingparams, int width)
const char* help;
char start[80 + 1];

+ 301
- 0
doc/internal/man3/OPTIONS.pod View File

@ -0,0 +1,301 @@
=head1 NAME
opt_progname, opt_appname, opt_getprog, opt_init, opt_format,
opt_int, opt_long, opt_imax, opt_umax, opt_ulong, opt_pair,
opt_string, opt_cipher, opt_md, opt_next, opt_arg, opt_flag, opt_unknown,
opt_num_rest, opt_rest, opt_help, opt_isdir
- Option parsing for commands and tests
#include "opt.h"
typedef struct { ... } OPTIONS;
typedef struct { ... } OPT_PAIR;
char *opt_progname(const char *argv0);
char *opt_appname(const char *arg0);
char *opt_getprog(void);
char *opt_init(int argc, char **argv, const OPTIONS *o);
int opt_next(void);
void opt_help(const OPTIONS *list);
char *opt_arg(void);
char *opt_flag(void);
char *opt_unknown(void);
int opt_cipher(const char *name, EVP_CIPHER **cipherp);
int opt_md(const char *name, EVP_MD **mdp);
int opt_int(const char *value, int *result);
int opt_long(const char *value, long *result);
int opt_imax(const char *value, intmax_t *result);
int opt_umax(const char *value, uintmax_t *result);
int opt_ulong(const char *value, unsigned long *result);
int opt_isdir(const char *name);
int opt_format(const char *s, unsigned long flags, int *result);
int opt_string(const char *name, const char **options);
int opt_pair(const char *name, const OPT_PAIR* pairs, int *result);
int opt_num_rest(void);
char **opt_rest(void);
The functions on this page provide a common set of option-parsing for
the OpenSSL command and the internal test programs.
It is intended to be used like the standard getopt(3) routine, except
that multi-character flag names are supported, and a variety of parsing
and other utility functions are also provided.
Programs that use this should make sure to set the appropriate C<-I>
These routines expect a global B<BIO> named B<bio_err> to point to
the equivalent of B<stderr>. This is already done in the OpenSSL
=head2 Data Types
Each program should define, near the main() routine, an enumeration
that is the set of options the program accepts. For example:
typedef enum OPTION_choice {
The first two lines must appear exactly as shown. In addition to
defining symbolic names for the constants that opt_next() returns,
it also helps guarantee that every command has a C<-help> option.
The third line is a sample
set of flags, and the closing C<typedef> name is used for error-checking
as discussed below.
By declaring the variable as an C<OPTION_CHOICE>, with the right warning
flags, the compiler could check that all specified options are handled.
The B<OPTIONS> C<typedef> specifies an option: what type of argument
it takes (if any), and an optional "help" string. It is a C<struct>
containing these fields:
const char *name;
int retval;
int valtype;
const char *helpstr;
The B<name> is the name of the option that the user would type. Options
are words prefaced with a minus sign. If the user uses two minus signs,
this is also accepted for compatibility with other GNU software. Some
names are special, and are described below.
The B<retval> is the value to return if the option is found. It should be
one of the choices in the enumeration above.
The B<valtype> defines what the option's parameter must be. It should
be chosen from the following set:
\0 No value
'-' No value
's' A text string
'/' A directory
'<' Name of file to open for input
'>' Name of file to open for output
'n' A signed number that fits in the C<int> type
'p' A positive number that fits in the C<int> type
'N' A nonnegative number that fits in the C<int> type
'M' A signed number that fits in the C<intmax_t> type
'U' An unsigned number that fits in the C<uintmax_t> type
'l' A signed number that fits in the C<long> type
'u' An unsigned number that fits in the C<unsigned long> type
'c' File in PEM, DER, or S/MIME format
'F' A file in PEM or DER format
'E' Like 'F' but also allows ENGINE
'f' Any file format
The B<helpstr> is what to display when the user uses the help option,
which should be C<"help">.
A program should declare its options right after the enumeration,
and should follow the ordering of the enumeration as this helps
readability and maintainability:
static OPTIONS my_options[] = {
{"help", OPT_HELP, '-', "Display this summary"},
{"yes", OPT_YES, '-', "Print an affirmative reply"},
{"count", OPT_COUNT, 'p', "Repeat count"},
{"output" OPT_OFILE, '>', "Output file; default is stdout"},
Note that the B<OPT_HELP> option is explicitly listed, and the list ends with
an entry of all-null's. The other two special options, B<OPT_ERR> and B<OPT_EOF>
should not appear in the array.
If the help string is too long to fit into one line, it may be continued
on multiple lines; each entry should use B<OPT_MORE_STR>, like this:
{"output" OPT_OFILE, '>', "Output file; default is stdout"},
{OPT_MORE_STR, 0, 0,
"This flag is not really needed on Unix systems"},
{OPT_MORE_STR, 0, 0,
"(Unix and descendents for ths win!)"}
Each subsequent line will be indented the correct amount.
By default, the help display will include a standard prolog:
Usage: PROGRAM [options]
Valid options are:
...detailed list of options...
Sometimes there are parameters that should appear in the synopsis.
Use B<OPT_HELP_STR> as the first entry in your array:
{OPT_HELP_STR, 1, '-', Usage: %s [options] [text...]\n"}
The B<retval> and B<valtype> are ignored, and the B<helpstr> should
follow the general construction as shown. The C<%s> will get the program
If a command has a large set of options, it can be useful to break them
into sections. Use the macro B<OPT_SECTION> or B<OPT_SECTION_STR>
to indicate this. The two lines below are equivalent:
{OPT_SECTION_STR, 1, '-', "Validation options:\n"},
In addition to providing help about options, you can provide a description
of the parameters a command takes. These should appear at the end of
the options and are indicated by using B<OPT_PARAM_STR> or the
{OPT_PARAM_STR, 1, '-', "Parameters:\n"}
Every "option" after after this should contain the parameter and
the help string:
{"text", 0, 0, "Words to display (optional)"},
=head2 Functions
The opt_init() function takes the "argc, argv" arguments given to main() and
a pointer to the list of options. It returns the simple program
name, as defined by opt_progname().
The opt_progname() function takes the full pathname, C<argv[0]>, and returns
the simple short name of the executable, to be used for error messages and
the like. The opt_appname() functions takes the "application" name (such
as the specific command from L<openssl(1)> and appends it to the program
name. This function should only be called once. Once set, opt_getprog()
also returns the value.
Once opt_init() has been called, opt_next() can be called in a loop to
fetch each option in turn. It returns -1, or OPT_EOF when the
end of arguments has been reached. This is typically done like this:
prog = opt_init(argc, argv, my_options);
while ((o = opt_next()) != OPT_EOF) {
switch (o) {
case OPT_EOF:
case OPT_ERR:
fprintf(stderr, "%s: Use -help for summary\n", prog);
case OPT_HELP:
...other options...
The opt_help() function takes a list of option definitions and prints a
nicely-formatted output.
Within the option parsing loop, opt_flag() returns the option,
without any leading hyphens. The opt_arg() function returns
the option's value, if there is one.
In an option list, there can be at most one option with the empty string.
This is a "wildcard" or "unknown" option. For example, it allows an
option to be be taken as digest algorithm, like C<-sha1>. The
function opt_cipher() takes the specified I<name> and fills in
the cipher into I<cipherp>. The function opt_md() does the same
thing for message digest.
There are a several useful functions for parsing numbers. These are
opt_int(), opt_long(), opt_ulong(), opt_imax(), and opt_umax(). They all
take C<0x> to mean hexadecimal and C<0> to mean octal, and will do the
necessary range-checking. They return 1 if successful and fill in the
C<result> pointer with the value, or 0 on error. Note that opt_next()
will also do range-check on the argument if the appropriate B<valtype>
field is specified for the option. This means that error-checking inside
the C<switch> C<case> can often be elided.
The opt_isdir() function returns 1 if the specified I<name> is
a directory, or 0 if not. The opt_format() function takes a string value,
such as used with the B<-informat> or similar option, and fills
the value from the constants in F<fmt.h> file.
The opt_string() function checks that I<name> appears in the
NULL-terminated array of strings. It returns 1 if found,
or prints a diagnostic and returns 0 if not.
The opt_pair() function takes a list of I<pairs>, each of which
has a text name and an integer. The specified I<name> is
found on the list, it puts the index in I<*result>, and returns
1. If not found, it returns 0.
After processing all the options, the opt_num_rest() returns what is
left, and opt_rest() returns a pointer to the first non-option.
If there were no parameters, it will point to the NULL that is
at the end of the standard B<argv> array.
=head2 Common Options
There are a few groups of options that are common to many OpenSSL programs.
These are handled with sets of macros that define common option names
and common code to handle them. The categories are identified by a
V Validation
X Extended certificate
R Random state
The B<OPT_x_ENUM> macro is used to define the numeration values, where B<x>
is one of the letters above. The B<OPT_x_OPTIONS> macro is used to
list the set of common options, and the B<OPT_x_CASES> is used in
the C<switch> statement.
The common options are used throughout the sources for the OpenSSL commands.
They are also used with common descriptions when generating the
manpages, in the file F<doc/>, which follow a similar naming
Detailed above.
The best examples can be found in sources for the commands in the F<apps>
directory of the source tree.
A notable exception is F<apps/cmp.c> which uses this API, but does
things very differently.
Copyright 2021 The OpenSSL Project Authors. All Rights Reserved.
Licensed under the Apache License 2.0 (the "License"). You may not use this
file except in compliance with the License. You can obtain a copy in the file
LICENSE in the source distribution or at