I'm looking into Openssl's source code to find out how the programmers made it possible to run different applications based on command line arguments. For instance: I can run openssl speed
, which has its own options, I can run openssl s_server
which has its own options as well, and so on. It all works like a charm on many operating systems. Besides, Openssl have something which I call 'command line suggestions' where it suggests available options when I press the tabulator key.
I'm looking into source code but have any clue how to implement something similar in my application. Any ideas?
how the programmers made it possible to run different applications based on command line arguments.
Those are called subcommands in OpenSSL. They include s_cient
, s_server
, digest
, enc
, dec
, x509
, speed
, etc.
Any ideas?
OpenSSL provides a a main
for the openssl
command and all the subcommands. The main
in the subcommand is wrapped in a macro so that if not building openssl
command, then the subcommand can become its own stand-alone program.
Here's what the use of the macro look like. All of the subcommands do this:
int MAIN(int, char **);
int MAIN(int argc, char **argv)
{
...
}
OpenSSL knows when its including all the subcommands with the openssl
command, and it defines MONOLITH
to switch "off" the mains
in the subcommands.
And from apps.h
:
#ifndef MONOLITH
#define MAIN(a,v) main(a,v)
#ifndef NON_MAIN
CONF *config=NULL;
BIO *bio_err=NULL;
#else
extern CONF *config;
extern BIO *bio_err;
#endif
#else
#define MAIN(a,v) PROG(a,v)
extern CONF *config;
extern char *default_config_file;
extern BIO *bio_err;
#endif
If you build the subcommand stand-alone, then you will also need to build apps.c
and link to apps.o
because its common to them.
If I recall correctly, PROG
unrolls to something like prog_xxx
when MONOLITH
is defined using preprocessor magic, where xxx
is the subcommand in question. So they just look like a bunch of functions: prog_s_cient
, prog_s_server
, prog_digest
, etc.
$ cd apps
$ grep -R MAIN *
app_rand.c:#define NON_MAIN
app_rand.c:#undef NON_MAIN
apps.c:#define NON_MAIN
apps.c:#undef NON_MAIN
apps.h:#define MAIN(a,v) main(a,v)
apps.h:#ifndef NON_MAIN
apps.h:#define MAIN(a,v) PROG(a,v)
asn1pars.c:int MAIN(int, char **);
asn1pars.c:int MAIN(int argc, char **argv)
ca.c:int MAIN(int, char **);
ca.c:int MAIN(int argc, char **argv)
ciphers.c:int MAIN(int, char **);
ciphers.c:int MAIN(int argc, char **argv)
cms.c:int MAIN(int, char **);
cms.c:int MAIN(int argc, char **argv)
crl.c:int MAIN(int, char **);
crl.c:int MAIN(int argc, char **argv)
crl2p7.c:int MAIN(int, char **);
crl2p7.c:int MAIN(int argc, char **argv)
dgst.c:int MAIN(int, char **);
dgst.c:int MAIN(int argc, char **argv)
dh.c:int MAIN(int, char **);
dh.c:int MAIN(int argc, char **argv)
dhparam.c:int MAIN(int, char **);
dhparam.c:int MAIN(int argc, char **argv)
dsa.c:int MAIN(int, char **);
dsa.c:int MAIN(int argc, char **argv)
dsaparam.c:int MAIN(int, char **);
dsaparam.c:int MAIN(int argc, char **argv)
ec.c:int MAIN(int, char **);
ec.c:int MAIN(int argc, char **argv)
ecparam.c:int MAIN(int, char **);
ecparam.c:int MAIN(int argc, char **argv)
enc.c:int MAIN(int, char **);
enc.c:int MAIN(int argc, char **argv)
engine.c:int MAIN(int, char **);
engine.c:int MAIN(int argc, char **argv)
errstr.c:int MAIN(int, char **);
errstr.c:int MAIN(int argc, char **argv)
gendh.c:int MAIN(int, char **);
gendh.c:int MAIN(int argc, char **argv)
gendsa.c:int MAIN(int, char **);
gendsa.c:int MAIN(int argc, char **argv)
genpkey.c:int MAIN(int, char **);
genpkey.c:int MAIN(int argc, char **argv)
genrsa.c:int MAIN(int, char **);
genrsa.c:int MAIN(int argc, char **argv)
nseq.c:int MAIN(int, char **);
nseq.c:int MAIN(int argc, char **argv)
ocsp.c:int MAIN(int, char **);
ocsp.c:int MAIN(int argc, char **argv)
passwd.c:int MAIN(int, char **);
passwd.c:int MAIN(int argc, char **argv)
passwd.c:int MAIN(int argc, char **argv)
pkcs12.c:int MAIN(int, char **);
pkcs12.c:int MAIN(int argc, char **argv)
pkcs7.c:int MAIN(int, char **);
pkcs7.c:int MAIN(int argc, char **argv)
pkcs8.c:int MAIN(int, char **);
pkcs8.c:int MAIN(int argc, char **argv)
pkey.c:int MAIN(int, char **);
pkey.c:int MAIN(int argc, char **argv)
pkeyparam.c:int MAIN(int, char **);
pkeyparam.c:int MAIN(int argc, char **argv)
pkeyutl.c:int MAIN(int argc, char **);
pkeyutl.c:int MAIN(int argc, char **argv)
prime.c:int MAIN(int, char **);
prime.c:int MAIN(int argc, char **argv)
rand.c:int MAIN(int, char **);
rand.c:int MAIN(int argc, char **argv)
req.c:int MAIN(int, char **);
req.c:int MAIN(int argc, char **argv)
rsa.c:int MAIN(int, char **);
rsa.c:int MAIN(int argc, char **argv)
rsautl.c:int MAIN(int argc, char **);
rsautl.c:int MAIN(int argc, char **argv)
s_cb.c:#define NON_MAIN
s_cb.c:#undef NON_MAIN
s_client.c:int MAIN(int, char **);
s_client.c:int MAIN(int argc, char **argv)
s_server.c:int MAIN(int, char **);
s_server.c:int MAIN(int argc, char *argv[])
s_socket.c:#define NON_MAIN
s_socket.c:#undef NON_MAIN
s_time.c: * MAIN - main processing area for client
s_time.c:int MAIN(int, char **);
s_time.c:int MAIN(int argc, char **argv)
sess_id.c:int MAIN(int, char **);
sess_id.c:int MAIN(int argc, char **argv)
smime.c:int MAIN(int, char **);
smime.c:int MAIN(int argc, char **argv)
speed.c:int MAIN(int, char **);
speed.c:int MAIN(int argc, char **argv)
spkac.c:int MAIN(int, char **);
spkac.c:int MAIN(int argc, char **argv)
srp.c:int MAIN(int, char **);
srp.c:int MAIN(int argc, char **argv)
ts.c:int MAIN(int, char **);
ts.c:int MAIN(int argc, char **argv)
verify.c:int MAIN(int, char **);
verify.c:int MAIN(int argc, char **argv)
version.c:int MAIN(int, char **);
version.c:int MAIN(int argc, char **argv)
x509.c:int MAIN(int, char **);
x509.c:int MAIN(int argc, char **argv)