[Top] | [Contents] | [Index] | [ ? ] |
opt
, v3.19a, a
subroutine library for communicating options and
parameter values to a C program via the command line, parameter files,
environment variables, or a rudimentary builtin interactive menu.
1. Nutshell What is opt, in a nutshell? 2. Opt What is opt, in a deeper philosophical sense? 3. Etc What else?
-- The Detailed Node Listing ---
Nutshell
1.1 What the user sees How to use programs that use opt 1.2 What the programmer sees How to write programs that use opt
Opt
2.1 Philosophical digression 2.2 What is Opt? 2.3 User Interface 2.4 Programmer Interface
What is Opt?
2.3 User Interface 2.4 Programmer Interface
User Interface
2.3.1 Direct command line options 2.3.2 Options from a named file 2.3.3 Environment strings 2.3.4 Rudimentary builtin menu 2.3.5 Standard usage messages
Programmer Interface
2.4.1 Example code 2.4.2 Registering options 2.4.3 Setting some strings 2.4.4 Registering functions (hooks) 2.4.5 Misc
Registering options
Etc
3.1 Installation 3.2 Adding opt
to existing code: a recipe3.3 So, you don't like global variables? 3.4 Single file 3.5 Extensions 3.6 Bugs Warranty Copying
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
opt
is a subroutine library which facilitates the
convenient input of parameters
to a C program. Parameters are parsed
from a command line, with further facilities for reading options from
files, from environment strings, or from an interactive environment.
The aim of the opt
package is to permit programs to be both
user- and programmer- friendly. The package attempts to
provide a direct and relatively full-featured input interface to the
ultimate user of the program, and at the same time to impose a minimal
amount of work on the programmer to "add" options parsing to
existing software.
opt
is similar in its effects to the standard UNIX (and also to
the GNU) getopts
packages, and I have tried (though possibly not
as hard as I could have) to keep them as similar as possible whenever
feasable. But opt
does takes a somewhat different philosophy.
Variables are "registered" to strings, and whenever the strings are
used on the command line, the variables are updated accordingly.
This tends to be a little more compact (and in my view
more convenient) than the loop and case-statement approach used by
getopt
. Also, opt
has a few more bells and whistles.
1.1 What the user sees How to use programs that use opt 1.2 What the programmer sees How to write programs that use opt
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Code written with opt
can read parameters from the command line;
for example running the program
birthday -m 9 -d 11 -y1989 -v |
birthday
program. Note that the space between
the single-character option name and the value is optional.
Some parameters can also be set using
long names, for instance:
birthday --month=9 --day 11 -y1989 |
birthday @file.opt |
birthday --menu |
birthday m Month 4 d Day of month 24 y Year 1993 v Verbose FALSE p Use Pade Approximants FALSE g Gregorian FALSE (Type ? for Help) -> |
Note that the programmer may optionally disable the menu, so some
applications that use opt
may not allow the --menu option.
Finally, the program is somewhat self-documenting. Type
birthday --help |
Usage: birthday [options] To invoke the menu, type: birthday --menu The options are: -m, --month <INT> Month -d, --day <INT> Day of month -y <INT> Year -v <INTLEVEL> Verbose -p <BOOL> Use Pade Approximants -g <BOOL> Gregorian |
opt
that will be discussed in later sections.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
/* birthday.c */ #include <stdio.h> #include <opt.h> /* part of opt package */ /* Parameters that user has access to via opt package; * They are typically (but not necessarily) global variables. * Their default values are provided in the assignement statements. */ int month=9; int day=11; int year=1989; int verb=0; int pade=0; int greg=0; /* All of what the program itself does is in the birthday() function; * This function does what a non-options parsing main() might do. */ int birthday(int argc, char **argv) { if (month == 9 && day == 11 && year == 1989) printf("Happy birthday, Max\n"); else if (month == 4 && day == 24 && year == 1993) printf("Happy birthday, Sky\n"); if (verb) printf("Hello, world: %4d/%02d/%02d\n",year,month,day); return OPT_OK; } /* all of the options parsing is in the new main() function */ int main(int argc, char **argv) { /* optrega() registers short name '-m' and long name '--month' to * variable 'month', and provides brief description "Month" */ optrega(&month,OPT_INT,'m',"month","Month"); optrega(&day, OPT_INT,'d',"day", "Day of month"); /* optreg() only provides short name '-y' */ optreg(&year,OPT_INT,'y',"Year"); /* register some flag variables... */ optreg(&verb,OPT_INTLEVEL,'v',"Verbose"); optreg(&pade,OPT_BOOL,'p',"Use Pade Approximants"); optreg(&greg,OPT_BOOL,'g',"Gregorian"); /* the function birthday() is registered with opt */ optMain(birthday); /* opt() is the routine that actually parses the argc/argv * variables */ opt(&argc,&argv); opt_free(); /* and when it's done, argc/argv will contain the leftover * argc/argv variables, including the same argv[0] as in * the original argc/argv */ /* Now that variables are parsed, run birthday() */ return birthday(argc,argv); } |
The opt package consists of the header file `opt.h', which must be
#include
'd in any code that uses opt, and the library file
`libopt.a', which is linked to the program at compile time
cc -Idir_with_opt_h -Ldir_with_libopt_a birthday.c -lopt |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
2.1 Philosophical digression 2.2 What is Opt? 2.3 User Interface 2.4 Programmer Interface
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Programs that provide a convenient user interface, especially those with gooey user interfaces (GUI's), generally require a fair bit of programming to produce. But for short programs that will not be used a lot, "programmer friendly" is more important than "user friendly." If a program grows in size or usefulness, the programmer can then go back and put in a better interface. But in doing so, the programmer trades away the "programmer friendliness" of the original code to end up with software that exhibits "user friendliness".
Suppose you want to write a program that depends on some parameters. As a programmer, it is convenient to set the parameters (in the vernacular, to "hardcode" them) to desired values right in the program. It is not really very convenient, though, because you have to recompile the program every time you want to run it with different values. This is especially inconvenient when the user and the programmer are different people.
It is usually more convenient (for the user) if the parameters can be specified at run time. There is, of course, more than one way to do this. You can specify parameter values in an input file, for instance. Then the program has to open the file, read the values, assign them to the appropriate variables, and then compute accordingly. It's a little inconvenient for the programmer, and a little inconvenient for the user, but if there are a large number of parameters, this is often the best approach. Even for a small number of parameters, it is useful to at least have the option of saving parameter values in a file.
Another approach is to have the program "ask" the user what parameter values are desired. After typing `birthday' for instance, the program might respond with
What is the number of the month?_ |
Enter the day of the month and the year?_ |
printf
's and scanf
's),
but for a lot of parameters, it can get pretty tedious.
One of the most popular approaches is to specify the options and parameter values directly from the command line. The user types
birthday -m 9 -d 11 -y 1989 |
opt
package is to bridge this gap: to on the one hand
simplify the programmer's task of converting command line strings into
parameter assignments, and on the other hand to provide the user a little
more information about the available options and a little more convenience
in setting those options and parameter values.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
I know I've said this already, but...
opt
is a subroutine library for communicating options and
parameter values to a C program via the command line, parameter files,
environment variables, or a rudimentary builtin interactive menu.
The aim of the opt
package is to permit programs to be both
user- and programmer- friendly. The package attempts to
provide a direct and relatively full-featured input interface to the
ultimate user of the program, and at the same time to impose a minimal
amount of work on the programmer to "add" options parsing to
existing software.
The next sections basically parallel the `Nutshell' chapter, but
add a little more detail.
First, the opt
interface will be described, as it appears to the user.
This comprises the advertisement for incorporating opt
into your code.
Then it will be shown how to write code that uses opt
for its user
interface.
2.3 User Interface 2.4 Programmer Interface
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Currently, opt
supports the following modes of interface to the user:
2.3.1 Direct command line options 2.3.2 Options from a named file 2.3.3 Environment strings 2.3.4 Rudimentary builtin menu 2.3.5 Standard usage messages
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
birthday -m9 -d11 -y1989 ;Sets values of month, day, and year birthday -d11 -y1989 -m9 ;Doesn't matter what order birthday -m9 ;Set month=9, day and year to their defaults birthday -m 9 ;Space is permitted between m and 9 birthday - m9 ;Not valid to have space beweeen - and m birthday -m9-d11 ;Not valid; need space between each ;delimited option |
Some kinds of options are of a different form. Among these are "flags" which signal whether a given option is on off. Thus, one might signal that a program is to operate in verbose mode with a command line of the form `birthday -m9 -v'. Alternatively, one can write `birthday -m9 -v+' to explicitly turn the verbose option on, or `birthday -m9 -v-' to explicitly turn verbose off. Unlike options which assign values, flag parameters can be assigned with a single delimiter. Thus, one might have a verbose (`v') flag, a gregorian (`g') flag, and a "use Pade approximant" (`p') flag. In this case, one can write commands of the following forms:
birthday -v -g -p ;Invoke all flags birthday -vgp ;Invoke all flags, in a more compact notation birthday -pv+g- ;Invoke p-flag, while explicitly ;turning v-flag on, g-flag off. |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is clear that a program with many options begins to get unwieldy on
the command line, and it is desirable to save options in a file, and not
have to retype them every time the program is run. The opt
package permits this with command lines of the form `birthday
@bday.opt'. Here `bday.opt' is a file which contains options
which are used by the program birthday
. The form of the options file
`bday.opt' is like that of the command line itself. Thus, if the file
is composed of the string `-m9 -d11 -y1989 -vg' then it is as if that string
replaced `@bday.opt' on the command line.
A file permits some luxuries that are not available on the command line directly. One of these is that you are not limited to a single line, and another is that you can add comments in the file. Thus if the file looks like this:
;file: bday.opt ;Comments are preceded by a semi-colon -m9 ;September -g ;Use gregorian -d11 -y1989 ;Can still have several options on one line |
It is possible to mix direct command line options with file options. Thus `birthday -v @bday.opt -p' is equivalent to `birthday -v -m9 -g -d11 -y1989 -p'. This is particularly useful if you want to make many runs in which only a few parameters are changed at a time. For instance,
birthday @defaults.opt birthday @defaults.opt -m10 birthday @defaults.opt -v |
It is also possible to nest files, so that one might have two files:
;file: bd1.opt -m5 ;set some option values -y 1997 @bd2.opt ;get more options from file bd2.opt |
;file: bd2.opt -d 11 ;set day=11 -y 1989 ;set year=1989 |
Of course, recursive nesting will only get you into trouble.
There is a useful abbreviation for files: @@ stands for the default options filename which is always the program name with the extension ".opt". Thus `birthday @@' is equivalent to `birthday @birthday.opt'
You can also write to an opt
file; the directive `%file.opt'
writes the current options to the file `file.opt' and then exits.
Here, `%%',
invoked for a program called `birthday', is an
abbreviation for `%birthday.opt'.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The program which uses the opt
package can be instructed to look for
an environment variable for options. If birthday sets `BIRTHDAY' as its
option environment variable, and if the environment string
`BIRTHDAY=-m9 -y1989'
is set, then running `birthday' is equivalent to running `birthday -m9
-y1989'. The environment options are assigned before any command line
options, so they can be over-ridden: thus the command `birthday -m10'
resets m to be equal to 10 instead of m=9 suggested by the
environment string, but one still has y=1989. The environment string
is therefore a useful place for storing default options that you
don't want to have to keep typing them each time you run the
program. In the UNIX C-shell you can set an environment string with the
`setenv' command:
setenv BIRTHDAY "-m9 -y1989" |
BIRTHDAY="-m9 -y1989" export BIRTHDAY |
set BIRTHDAY=-m9 -y1989 |
opt
on MS-DOS;
I'd be surprised if it still worked on that platform. Of course I'm
always surprised when anything works on that platform.)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Although the above methods provide flexible means of getting parameter
values to a program which is run in background or batch mode, it is also
useful to alter parameters interactively. The opt
package provides
a convenient way to do this, with an interactive menu.
To invoke the menu type `$' (or `--menu')
at the end of the command line. For instance,
typing `birthday -m4 -y1993 $' will return a menu that looks something like
birthday m Month 4 d Day of month 11 y Year 1993 v Verbose FALSE p Use Pade Approximants FALSE g Gregorian FALSE (Type ? for Help) -> |
-> |
m Month 4 d Day of month 11 y Year 1989 v Verbose TRUE p Use Pade Approximants FALSE g Gregorian TRUE (Type ? for Help) -> |
- Options delimiter ? Help = Run program and return to menu ! Shell to Operating System $ Exit menu + Additional options @<filename> Get options from file @@ Get options from file [birthday.opt] %<filename> Put options in file %% Put options in file [birthday.opt] . Quit -> |
It is also possible that `?c' will give further information about the option specified by `c', although this requires that the programmer supplied extra information (usually, the brief description is all that is available). For example,
-> ?d d: Use day of month, should be less than 32 -> |
If you don't want the user to have access to the menu for some reason, then you can invoke the function `optDisableMenu()' before calling `opt()', to achieve this. You might want to do this to avoid stuff about menus appearing in the usage message, for instance.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
birthday --help |
Usage: birthday [options] To invoke the menu, type: birthday --menu The options are: -m, --month <integer> Month -d, --day <integer> Day of month -y <integer> Year -v <flag> Verbose -p <flag> Use Pade Approximants -g <flag> Gregorian |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
First an example source code will be shown so that the programmer
gets an idea of what it takes to incorporate opt
into his
or her favorite application. Subsequent sections will then go into
more detailed explanation.
2.4.1 Example code 2.4.2 Registering options 2.4.3 Setting some strings 2.4.4 Registering functions (hooks) 2.4.5 Misc
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The easiest way to see how to use the opt
package is with an
example. The following program illustrates most of the features that
you'd actually want to use (and several you probably don't care about).
/* testopt.c */ #include <stdio.h> #include <stdlib.h> #include <opt.h> int month=4; int day=24; int year=1993; char *who=NULL; int go(int argc, char **argv) { if (argc>1) { printf("In program %s, Extra option: %s\n",argv[0],argv[1]); } if (optinvoked(&month)) { printf("User set month...\n"); } if (month == 9 && day == 11 && year == 1989) { printf("Happy birthday, Max\n"); } else { printf("Hello, %s: %4d/%02d/%02d\n",(who==NULL ? "world" : who), year,month,day); } return OPT_OK; } int checkyear(void *v) { if (year == 2000) { printf("Watch out for that year=2000 bug!\n"); return OPT_ERROR; } return OPT_OK; } int quit() { printf("Bye...\n"); return OPT_OK; } int write_altversion() { printf("AltVersion XXX\n"); optExitNumber(12); return OPT_EXIT; } int fix_mon(void *v) { int m; /* fix whatever int variable v is pointing to */ m = *((int *)v); if (m < 1 || m > 12) m=1; *((int *)v) = m; return OPT_OK; } main(int argc, char **argv) { optreg(&month,OPT_INT,'m',"Month"); optlongname(&month,"month"); opthook(&month,fix_mon); optrega(&day,OPT_INT,'d',"day","Day"); opthelp(&day,"Use day of month, should be less than 32"); optreg_INT(&year,'y',"Year"); optreg(&year,OPT_INT,'Y',"Year"); optdescript(&year,"What Year"); opthook(&year,checkyear); optregp(&who,OPT_STRING,"who","Who to say hello to"); optexec("altversion",write_version,"Write version number and exit"); optEnvVarName( "OPT" ); optMain(go); optQuit(quit); opt(&argc,&argv); go(argc,argv); opt_free(); } |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is necessary for the programmer to somehow tell the package
which options are associated with which variables in the program, and
what descriptions opt
should use in the usage message and the menu.
This is done with a function call that "registers" (or associates(1))
a variable and a name. These functions (one for each variable, in general)
are usually called at the beginning of the code.
Opt
can handle three kinds of options:
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Delimited options are the standard options you'd expect an option handling package to work with. Delimited options are flagged by the user with a switch that starts with `-' or `--'.
`Opt' provides a variety of commands for registering delimited options with different variable types, and using the "short", or "long" delimited option forms (or both).
For example,
optreg(&day,OPT_INT,'d',"Day"); |
You can register a long (string) name as well as the short (one character) name. The function name has an extra `a' (mnemonic: all) at the end.
optrega(&month,OPT_INT,'m',"month","Month"); |
optrega(&month,OPT_INT,'\0',"month","Month"); |
The variable OPT_INT
is of type `opt_TYPE'; this is an enumerated type
and is defined in the header file `opt.h'. The available option
types are: OPT_INT
, OPT_SHORT
,
OPT_LONG
, OPT_CHAR
,
OPT_UINT
, OPT_USHORT
,
OPT_ULONG
, OPT_UCHAR
,
OPT_FLOAT
, OPT_DOUBLE
, OPT_BOOL
, OPT_TOGGLE
,
OPT_NEGBOOL
, OPT_NEGTOGGLE
, OPT_INTLEVEL
,
OPT_STRING
, OPT_CSTRING
,
OPT_UNDELIM
, and OPT_UNDELIMC
.
There is also a type OPT_NUL
that is used internally.
Most of these are self-explanatory:
OPT_INT int OPT_SHORT short int OPT_LONG long int OPT_UINT unsigned int OPT_USHORT unsigned short int OPT_ULONG unsigned long int OPT_FLOAT float OPT_DOUBLE double |
OPT_CHAR char |
There are a variety of options for boolean (yes/no, 1/0, on/off) flags:
OPT_BOOL int Probably this is the one that you want. Invoking this option sets the value to 1; and subsequent invocations have no effect. OPT_TOGGLE int Each invocation changes the value -- either from 0 to 1 or from 1 to 0. OPT_NEGBOOL int Like OPT_BOOL but invoking the option sets the value of the variable to 0. OPT_NEGTOGGLE int Like OPT_TOGGLE, in fact a lot like OPT_TOGGLE. I can't think of why you would want to use it. OPT_FLAG int Deprecated! Use OPT_TOGGLE instead. OPT_NEGFLAG int Deprecated! Use OPT_NEGTOGGLE instead. OPT_ABSFLAG int Deprecated! Use OPT_BOOL instead. OPT_ABSNEGFLAG int Deprecated! Use OPT_NEGBOOL instead. In my own experience, I have found absolute flags are usually preferable to toggle flags. The problem with toggles is that you can easily lose track of the current state of the toggle, especially when options can be specified in files, environment variables, and the menu, as well as the command line itself. OPT_INTLEVEL int This is a kind of a combination of flag and int: OPT_INTLEVEL is an integer that can take on only positive values, usually less than ten. I find this useful for "verbose" since I can not only turn verbose ON, but I can have a range from slightly verbose to extremely verbose. For this flag, each invocation increases the level; eg, `-v -v' sets verbose=2, and `-v-' turns verbose off. |
char *vstring=NULL; /* variable string */ char cstring[80]; /* constant string */ char *cstring="hello"; /* this is a constant string too */ |
vstring = (char *)malloc(strlen("string")+1); strcpy(vstring,"string"); |
OPT_STRING char * OPT_CSTRING char * |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The second kind of option that `opt' provides is the positional option. These are similar to delimited options except that they are not flagged by a delimiter switch on the command line. The user specifies values for positional options by simply writing those values as bare arguments on the command line. The processing of positional options is determined by the order in which they appear on the command line, hence the name.
To register a positional option, use the `optregp' command. For example:
char* input = NULL; ... optregp(&input,OPT_STRING,"input-file","File to process"); |
In this example, we have associated the variable `input' with a positional option of type OPT_STRING (a dynamically allocated string). `"input-file"' is a long name associated with the option. It is not actually used in option processing for pure positional parameters, but is used to refer to the positional argument in the usage message that `opt' generates. In addition, if the option is subsequently made "flexible" see section 2.4.2.3 Flexible options, then the option may be set either positionally OR using a delimited option of the form:
--input-file=fred.txt |
Undelimited command line arguments are assigned to positional options in the order in which those positional options were registered. If there are insufficient command line arguments to process all registered positional options, then the remaining postional options are simply never invoked. If there are more command line arguments than positional options, then the remaining command line arguments are returned to the `argv' array after `opt' processing has finished.
Note: At the time of writing, such extra undelimited arguments also cause opt processing to terminate immediately, even if there are as yet unprocessed delimited arguments on the command line. This is probably a mistake and will be fixed in some future release.
Positional options can be registered using any of the types described under 2.4.2.1 Delimited options.
A delimited option can be turned into a positional (or flexible) option by using the `optmode()' function on that option see section 2.4.2.5 Modifying option attributes.
In earlier versions of `opt', positional parameters were handled using a special variable type, `OPT_UNDELIM', that was equivalent to `OPT_STRING', but with positional semantics. This usage is still available in `opt' but is deprecated.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The third kind of option is a flexible option. Flexible options are simply positional options that can also be set by the user using a delimited switch as well. This can be handy in some cases, for instance when setting a positional option from a file.
To register a flexible option, you can use the `optregf()' function:
char* input = NULL; ... optregf(&input,OPT_STRING,'f',"input-file","File to process"); |
In this example, we have associated the variable `input' with a flexible option of type OPT_STRING (a dynamically allocated string). The user may set this option either positionally, using the normal rule that positional options are processed in the order that they were registered, OR by using a delimited option of the form `-f foo.dat' or `--input-file=foo.dat'.
An existing positional or delimited option can be turned into a flexible option by invoking either the `optmode(...,OPT_FLEXIBLE)' or `optmode_n(...,OPT_FLEXIBLE)' functions on that option.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
To give an option a default value, simply assign an appropriate value to the corresponding registered variable, before or after it is registered. Consider the following example:
int year=1999; ... optrega(&year,OPT_INT,'y',"year","Year of interest"); |
If the user does not invoke the `-y' option, then the variable `year' will retain the value of 1999.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
If a variable is registered, then you can change or add to its attributes; for instance:
optreg(&var,OPT_INT,'c'); optlongname(&var,"variance"); |
The various registration functions (`optreg()', etc) return an integer which is the index of the registered option. Sometimes (eg, instance when there is no variable associated with the registration) this integer is a more useful identifier of a given option. The above, for instance, is equivalent to:
n = optreg(&var,OPT_INT,'c'); optlongname_n(n,"variance"); |
void optchar(void *v, char c)
void optchar_n(int n, char)
void optlongname(void *v, char *longname)
void optlongname_n(int n, char *longname)
void optmode(void *v, int mode)
void optmode_n(int n, int mode)
void optdescript(void *v, char *descript)
void optdescript_n(int n, char *descript)
void opthelp(void *v, char *help)
void opthelp_n(int n, char *help)
void optarraydelim(void *v, char delim)
optarraydelim(NULL,delim)
resets the delimiter for
all array options.
void optarraydelim_n(int n, char delim)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As well as registering scalar variables, you can also register dynamically allocated arrays, and manipulate their values with command line options, parameter files, environment strings, or on the menu. As a user, you would type for instance `program -x 1,2,3' to set the array values to 1, 2, and 3. As a programmer, you need to keep track not only of the array pointer but of the size of the array, so to register an array option requires an extra argument. For example
int nx=0; double *x=NULL; ... optreg_array(&nx, &x, OPT_DOUBLE,'x',"Array of x values"); |
As well as the optreg_array
function, you can also use
optrega_array
, optregc_array
, optregcb_array
,
optregs_array
, and optregsb_array
. These are essentially
equivalent to the scalar versions, except that the first argument is a
pointer to the size of the array.
After the options have been processed, the array x[]
will have
nx
elements. In the above example, nx
would be 3, and
x[0]
would be 1, x[1]
would be 2, and x[2]
would be 3.
It would be a mistake to refer to x[3]
, since that is beyond the
array bounds, but since the programmer has access to nx
, that
shouldn't be a problem.
Note that opt
can only handle arrays of simple types (strings,
characters, and numbers); arrays of OPT_BOOL
's or
OPT_INTLEVEL
's are not supported.
The default delimeter for array values is a comma; this can
be changed using the optarraydelim(void *v,char delim)
function.
See the file `test/tarray.c' for examples of this usage.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
opt
also provides a rudimentary C++ interface.
You can always use the plain C code inside your C++ programs, but
you may find it a little more convenient to use the OptRegister
function. This function can be used like optrega
except that it
has a lot more flexibility. Also, if you want to register a standard type,
like OPT_INT
or OPT_DOUBLE
but not a specialty like
OPT_UNDELIM
or OPT_INTLEVEL
, then you can just leave out
the type specifier -- C++ knows what you mean. For example:
// Can invoke with -N500 or --nPulses=500 OptRegister(&N, 'N', "nPulses","total Number of pulses"); // Can only invoke with long name --delta=0.01 OptRegister(&delta,"delta","average time between pulses"); // Can only invoke with short name -x3.14159 OptRegister(&x,'x',"x marks [the horizontal position of] the spot") // You have to specify flags as such, otherwise they are // treated as ordinary integers. Note that the variable is // still an integer. Currently there is no support for the // C++ bool type, which is unfortunate. OptRegister(&flag,OPT_BOOL,'f',"flag","boolean variable"); // The descriptions are optional, so you can have very simple commands OptRegister(&y,'y'); // But beware that there can be ambiguity between longname and description. // The first string is assumed to be the longname OptRegister(&z,'z',"third coordinate value"); // error! // You can also register positional options using OptRegister OptRegister(&y, OPT_POSITIONAL, "y-value", "The value of y"); // Or flexible options OptRegister(&y, OPT_FLEXIBLE, "y-value", "The value of y", OPT_FLEXIBLE); // If you specify both a type and a mode, specify the type first OptRegister(&flag,OPT_BOOL,OPT_FLEXIBLE,'f',"flag","boolean variable"); |
See the example file `test/testcc.cc' for a working example.
Note that using these routines requires that `libopt.a' or `opt.o' be compiled using a C++ compiler. This is normally handled automatically by the installation procedure. If you want to include a single file with your distribution containing the opt code, then use `optcc.cc' rather than `opt.c'. Both of these are generated automatically as part of the opt install procedure.
Beware that there is a problem with gcc 3.0 and 3.1 on Solaris. The
problem has been traced to the compiler itself, and the maintainers have
promised that it will be fixed in the next release. If you use the
environment variable CPLUS_INCLUDE_PATH
to tell the compiler where
`opt.h' is located, then you will get error messages during
compilation. One solution is to use the explicit -I...
directive
during compilation. Another is to disable the C++ interface in opt by
#define
'ing the variable OPT_NOCPLUSINTERFACE
before
#include
'ing `opt.h'. This however will disable the
overloaded OptRegister
function, and you'll have to use the
bulkier optreg
functions from the C interface.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The following functions set strings which the opt
package uses
for various things.
void optUsage(char *s)
void optTitle(char *s)
void optProgName(char *s)
void optVersion(char *s)
optVersion
is not used, then `--version' will do
nothing (except get a warning message that `version' is not
a registered option).
void optEnvVarName(char *s)
opt
package will look for initial command line options.
If not set, the opt
will not be check any environment variable
for options processing.
void optDefaultString(char *s)
void optDefaultFile(char *s)
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Hooks are means by which the user can write routines which
the opt
package calls during its processing. This enables the
programmer to customize the behavior of opt
to the program at
hand. Of course opt
has to be informed of the function
(in the same way that variables have to be registered, so do
functions). The hook function should always return an integer,
and a value of zero
is the default that tells opt
that all is okay. (You can also
return `OPT_OK', which is defined to be zero in `opt.h'.)
The return value tells opt
what to do after the hook has
been run. [** Warning: I am thinking of changing these. --jt **]
OPT_OK
OPT_ERROR
opt
that the hook was not successful. Currently,
opt
doesn't do anything differently from what it does if
`OPT_OK' is returned.
OPT_EXIT
OPT_QUIT
OPT_ABORT
opt
to `--enable-longjmp' (default) at compile time); but if you are running
from the command line, the program will quit calling a quit-hook if
one has been defined.
There are basically two kinds of hooks. The first kind is associated
with a specific variable, and it is run whenever that option is invoked.
These hooks take a single argument, a `void *' that points to the
associated variable. The second kind of hook is not associated with
a specific variable, and it takes no arguments. It might be associated with
a command line string (such as `--version' which you might want to use to
make the program write a version number and exit; but see the optVersion
function in 2.4.3 Setting some strings.), or with the general
behavior of opt
, such as the quit hook described below.
Here, `OPT_PFI' is declared `typedef int (*OPT_PFI)()'
in the header file `opt.h'; it is a pointer to
a function returning an integer.
(Currently we exploit C's loose typecasting
rules, so that `OPT_FPI' refers to a function with any number
of arguments, as
long as it returns an integer. In future versions, we may define
`OPT_PFI_V' and `OPT_PFI_ARG' types, to indicate functions
that take arguments `void *' and `int,char **' respectively.)
The first kind of hook is registered with the function `opthook()'. For instance, if you register a hook with a statement such as
int fix_mon(void *v) { ... } int month=9; ... optreg(&month,OPT_INT,'m',"Month"); opthook(&month,fix_mon) |
opt
calls the hook function, it will use a
pointer to the variable month as the argument.
You can use the argument to get (and manipulate) the value of the
variable month. However, if the variable is global, then you
can also manipulate the month directly. So the following two
examples serve the same purpose.
int fix_mon(void *v) { /* don't bother using the argument v; * just manipulate month directly */ if (month < 1 || month > 12) month=1; return OPT_OK; } |
int fix_mon(void *v) { int m; /* fix whatever int variable v is pointing to */ m = *((int *)v); if (m < 1 || m > 12) m=1; *((int *)v) = m; return OPT_OK; } |
optVersion
function in 2.4.3 Setting some strings.)
opt
program, at least by me.
This function is run when the user types `=' at the opt
menu prompt. Usually, the programmer writes `fcn(argc,argv)' to do
whatever it is that the program is supposed to do (essentially
the same as `main(argc,argv)' but without the command line parsing
that opt
is taking care of). The arguments `argc,argv'
that `fcn' sees are the command line strings that are "leftover"
after opt
has finished parsing; `argv[0]' is retained however,
so that `fcn' behaves just like a `main' function would behave.
When `fcn' is finished, you will be returned to the command
line prompt. If opt
was configured at compile time with the
`--enable-longjmp' (default), then if you interrupt (^C)
`fcn' while it is running,
you will be returned to the command prompt (instead of exiting
the program completely).
opt
exits.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
int optinvoked(void *v)
void optPrintUsage()
void opt_free()
opt
allocated -- for instance, it makes copies of string parameters that are
specified on a command line. But also note that opt
does not
generally take a lot of memory, so if you leave off this command, you
will nearly always be just fine.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
3.1 Installation 3.2 Adding opt
to existing code: a recipe3.3 So, you don't like global variables? 3.4 Single file 3.5 Extensions 3.6 Bugs Warranty Copying
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Because opt
does not require exotic systems services or
esoteric libraries, installation on a variety of platforms should
be straightforward. What follows is a guide to installing OPT on
a UNIX system, but I have heard of at least one successful
install on a Microsoft operating system.
First you have to un-archive the `opt-XXX.tar.gz' file, where `XXX' is the version number, using commands along these lines:
gzip -d opt-XXX.tar.gz tar xvf opt-XXX.tar cd opt-XXX |
Then, it's bascially a generic GNU installation, with configure
,
make
, and make install
. More details can be found in the
`INSTALL' file that should be in the distribution, but those are
details about the generic installation procedure, and contain no
opt
-specific notes.
opt
-specific
options are:
longjmp
is enabled (default), then hitting `^C'
during a run launched from the menu prmopt will return you to the menu prompt;
if longjmp
is disabled, then `^C' exits the program entirely.
You should only disable longjmp if you have trouble compiling.
GNU readline
installed(2),
you can specify this option to obtain readline features (line editing,
history recall, etc) in the opt
menu. If you will be using the
menu even a little bit, these features are very convenient.
.opt
file for instance) with `+' or `-',
respectively; eg, -v+
turns on the v
-flag. But if you
invoke --enable-flagonezero
, then true and false are encoded as
`1' and `0' instead. If you have a lot of long option names,
it looks a little cleaner (some might argure) to have `--verbose=0'
rather than the default `--verbose=-'.
opt
, or you may
be compiling it on a new platform
opt
package you just compiled is actually working.
The tests in the `test/' directory also serve as example code to show you
how to use the opt package in your own programs.
opt
into your personal directory,
you will probably have to become "root" before you do this
step.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
opt
to existing code: a recipe /* yourprogram.c */ #include <stdio.h> int N=5; /* Global variable */ int main(int argc, char **argv) { /** do some complicated thing ** ** that depends on value of N **/ } |
You want to use the opt
package to make the variable N into
a parameter that can be altered on the command line. Here is the recipe.
/* yourprogramonopt.c */ #include <stdio.h> #include <opt.h> int N=5; /* Global variable */ int youroldmain(int argc, char **argv) { /** do some complicated thing ** ** that depends on value of N **/ } int main(int argc, char **argv) { optreg(&N,OPT_INT,'N',"Number that complicated thing depends on"); optMain(youroldmain); opt(&argc,&argv) return youroldmain(argc,argv); } |
If you don't want to use a different `main' function, then you don't have to. In fact the only drawback with this approach is that the user won't be able to use the `"="' command to run the program from within the menu. In such a case, you may want to disable the menu anyway, using the `optDisableMenu()' function.
If the "complicated thing that depends on N" depends on argc,argv, then the argc,argv that `youroldmain()' will see will be the leftover arguments on the command line that come after the `-N 5', or the arguments that come after `--' on the command line.
When the users use your program in the menu mode, they can try different values of N, eg
-> N 5 ;user types `N 5' in response to prompt `->' -> = ;user says to do the complicated thing 5 ;output of complicated thing, followed by prompt -> N 500 = ;user tries another value, and says run with that 2 2 5 5 5 ;computer responds -> N 12345678 ;user types in too large a value, computer hangs ^C ;user hits ^C -> ;computer responds with menu prompt, so user can ;try again with some other value |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
One, they're not as bad as you might think. Remember, these are not obscure variables that will be interacting in odd ways with different components of a complicated whole; these are the variables that you want to give the user direct access to.
Two, although the examples I've given (and the codes I write)
use global variables for the user-alterable parameters, it is
possible to use opt
without global variables. I will leave
this as an exercise for the reader who gives a damn.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
opt
in code that you have written
to be distributed, you are by the GPL quite welcome to do so, following
the usual caveats, provisos, and quid pro quo's.
You may find it
inconvenient, however, to include the full distribution of opt, with
all of its automake'd Makefiles, its multiple source files, and the
extra test and extension directories. As long as your distribution
is not an extension to opt whose purpose is ever fancier options
parsing, but instead does something useful and just uses opt for
its command line processing, then you are permitted to include only
the minimal source needed to make `libopt.a'. In fact, to simplify this
task, you can do a `make opt.c' in the `src/' directory and
a single file, called `opt.c' of course, will be generated.
(It is possible that the opt
distribution will already have an
`opt.c' made for you.) You
are free to include `opt.c' along with `opt.h' in your distribution.
You don't even need to make a `libopt.a' if you don't want to.
Just have your `Makefile' include lines to this effect:
opt.o: opt.c opt.h $(CC) $(CFLAGS) -c opt.c yourprogram.o: yourprogram.c opt.h ... yourprogram: yourpgram.o ... opt.o $(CC) $(LDFLAGS) -o yourprogram yourprogram.o ... opt.o |
opt
distribution, if they want it.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
opt
interface. To use it type
tkopt program [options] |
use
'd by other Perl
scripts to achieve an opt-like interface. The main bug
is that you can already get pretty good option parsing with
only a few lines of Perl, and there exist other packages
(eg, Getopt::Long
) that perform quite powerful processing.
What Opt.pm
provides is nearly identical behavior
to the C version. Thus, you can use tkopt
as a front-end to
perl scripts using Opt.pm
just like you can use it for
C programs linked with libopt.a
.
opt
with the `--with-readline' feature, then
GNU readline
features (line editing, previous line retrieval,
etc) will be available in the menu mode of opt
.
To link your program to this
code, you'll need to have the `readline' and `termcap'
libraries available. But this is all done automagically (where by
"magic" I mean code that is embarassingly complicated) by the
configure script. So if `libopt.a' is built with this option enabled,
it will actually incorporate the `readline' and `termcap'
libraries within itself, and you don't need to do anything different
on the linking step. In particular, you do NOT need to add
`-lreadline -ltermcap' to the `cc' command line.
If it fails, and you don't feel like trying to figure out why, just
reconfigure without the `--with-readline' option. It's nice, but
not really crucial.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Using opt
promotes the use of global variables for the parameters
that opt
sets. Global variables are generally considered harmful
to your health, but in my experience, this has rarely been a problem for
variables that you want the user to have access to anyway. I have seen
various convoluted schemes for getting around this, but I have not been
convinced of their usefulness.
Another bug is that opt
doesn't look much like the
standard and GNU's getopt
package, even though it does pretty
much the same thing. Partly this is a design
choice; I wanted something that was very easy to "attach" to the code.
In particular, with opt
, you register options and associate them
with variables; this tends to be a little more compact (and in my view
more convenient) than the loop and case-statement approach used by
getopt
. Also, opt
has a few more bells and whistles. If
I were smart, I would have built opt
as an add-on to the standard
getopt
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The subroutines and source code in the opt
package are free.
However, I was paid to write this software. That is to say, I wrote
this software while being paid by the University of California to work
for the Department of Energy at Los Alamos National Laboratory. I like
my job, and am grateful to the Laboratory for the opportunity to do
interesting work and collect a nice paycheck. However, I do NOT own the
copyright on this software, and the conditions for redistributing
opt
reflect that.
These conditions, encrypted in legalese, are described in the file
`COPYING' that should be included in the opt
distribution.
For practical purposes, this is the same as the GNU General Public
License, although I read it as saying that the US Government paid for
this software, and the US Government doesn't consider itself bound by
the more restrictive aspects of the GPL. But the rest of you are.
My own imprecise interpretation of the GPL, as it applies to opt
,
follows. I should say that this is a heavily edited version of a
`Copying' section that I copied from some other GNU package (now
forgotten).
Everyone is free to use this software and free to redistribute it on a
free basis. The opt
library is not in the public domain; there
are restrictions on its distribution, but these restrictions are
designed to permit everything that a good cooperating citizen would want
to do. What is not allowed is to prevent or inhibit others from further
sharing any version of this software that they might get from you.
Specifically, I want to make sure that you have the right to give
away copies of opt
, that you receive source code or else can get
it if you want it, that you can change opt
or use pieces of it in
new free programs, and that you know you can do these things.
To make sure that everyone has such rights, I cannot and do not give
you the "right" to deprive anyone else of these rights. For example, if
you distribute copies of the opt
-related code, you must give the
recipients all the rights that you have. You must make sure that they,
too, receive or can get the source code. And you must tell them their
rights.
Also, for my own protection, I must make certain that everyone finds
out that there is no warranty for opt
. If this software is
modified by someone else and passed on, I want the recipients to know
that what they have is not what I distributed, so that any problems
introduced by others will not reflect on my reputation, feeble though it
may be.
Let me say that by opt
-related, I mostly mean
opt
-derived. If your software does something substantially
different from opt
, but uses opt
for its command line
processing, then you can do what pretty much you like with that code:
sell it for a profit, design weapons of mass destruction, etc. That's
my own view. I should note that a more common interpretation of the GPL
holds that if you use a GPL'd library in your code, then your code must
be GPL'd. Just because I don't hold this view doesn't mean you are off
the hook; it just means that I am unlikely to sue you if you use my
package under this less restrictive interpretation.
But in any case, you should make it clear to the users of your code that
the options parsing is done by software that is free; you should tell
them that free software is a wonderful concept; and you should provide
the opt
source code, or at least provide the users with a pointer
to where the code is available. (Currently, that is
`http://nis-www.lanl.gov/~jt/Software'.)
Happy hacking...
[Top] | [Contents] | [Index] | [ ? ] |
When I say "register" I mean it as a verb, in the sense of "register your handgun", and not as a noun, meaning an immediate memory location on a microprocessor. I apologize to any old assembler-coders who may find this language confusing.
If it doesn't,
you can get readline
from any GNU
mirror site.
[Top] | [Contents] | [Index] | [ ? ] |
opt
to existing code: a recipe
[Top] | [Contents] | [Index] | [ ? ] |
1. Nutshell
2. Opt
3. Etc
[Top] | [Contents] | [Index] | [ ? ] |
Button | Name | Go to | From 1.2.3 go to |
---|---|---|---|
[ < ] | Back | previous section in reading order | 1.2.2 |
[ > ] | Forward | next section in reading order | 1.2.4 |
[ << ] | FastBack | previous or up-and-previous section | 1.1 |
[ Up ] | Up | up section | 1.2 |
[ >> ] | FastForward | next or up-and-next section | 1.3 |
[Top] | Top | cover (top) of document | |
[Contents] | Contents | table of contents | |
[Index] | Index | concept index | |
[ ? ] | About | this page |