Knowing the terminology and usage basics, here is a detailed description of
each of the different kinds of options which hest can deal
with. This is the information you'd need to set the elements of a
hestOpt struct, either by static initialization, or by a call
to hestOptAdd(). Essentially, this page describes in detail
the somewhat complicated behavior of the hestParse() function.
-
The first thing that happens in hestParse() is to verify
that the hestOpt array itself is valid. This is the
same check that hestOptCheck() does.
-
The response file arguments are parsed. But if the
respFileEnable flag of the hestParm struct is zero
(false), then no response files are parsed, and this step is skipped.
Otherwise, any argument that starts with the "@" character is
assumed to be a response file name (But the role of @ is not
set in stone; you can alter either the respFileFlag field in
the hestParm struct, or you can alter the
hestRespFileFlag global.) You can have as many response file
arguments on the command line as you want, where ever you want. The
response files are parsed as follows:
- The file is read one line at a time until the end of the file
is reached.
- Everything after the pound character ("#") is ignored,
as is the # itself. This is how you can comment your
reponse files. The role of # is not set it stone: you can
alter the respFileComment field of the hestParm
struct, or you can alter the hestRespFileComment global.
- Blank lines are ignored.
- Each line is parsed into white-space seperated tokens: these
are the arguments you would normally type on the command line.
- As each line is parsed, the new arguments are effectively appended
to the list of arguments parsed so far. There is no memory of which
line the different arguments came from.
- All white space is considered equal, and is compressed to a
single space character.
- The big long list of space-seperated arguments is effectively
inserted into the original command line, in place of the where
the @-prefixed response file name had been.
-
The flagged options (the flag and its parameters) are extracted
from the command line. hestParse() has to decide which
arguments belong to which flagged options, so that it can extract
what it should. For stand-alone flags, single fixed parameter options,
and multiple fixed parameter options, this is simple. For single
and multiple variable parameter options, it uses four ways to
find the end of the parameter list:
- The end of the command line obviously signals the end of a
parameter list.
- An argument recognized as a flag for the current hestOpt
array also terminates the parameter list. This is risky only when
your variable parameters are either strings which can be mistaken
for flags, or are negative numbers. Oh well.
- An argument consisting only of two hyphens ("--") also
terminates the paramter list. When --
performs the role of terminating a parameter list, it is removed
from the command-line. -- isn't set in stone: you can
set the second character, after the initial hyphen, to something
else, either by altering the varParamStopFlag field of
the hestParm struct, or by altering the hestVarParamStopFlag
global.
- The max field of the hestOpt struct determines
the maximum number of parameters to be associated with the option.
If max arguments are parsed without any of the previous
three rules going into effect, then this obviously terminates
the parameter list.
A flagged option can appear multiple times on the command-line, or
in a response file and the command-line. Only the last occurance
will be used. Because the arguments found in response files are
effectively inserted into the command line at the point the response
file is named, this means that the original command line can over-ride,
or can be over-ridden by, arguments in the response files, depending
on the ordering.
- The remaining arguments are parsed as the unflagged options. Unlike with
flagged options, the order of the unflaged options in the
hestOpt array is significant: the hestOpt array will be
traversed, and each unflagged option will cause some arguments to be
extracted from the command line. Again, there is the same problem of
determining which arguments belong to which options. Currently, for
simplicity's sake, there is a simple rule: you can have only one
variable parameter unflagged option. This means there is an
unambiguous way to parse the remaining arguments into parameters for
the different options.
All the actions described above are performed on copies of
the given argc, argv arguments passed to
hestParse(). They are left untouched.
Once values have been parsed and hestParse() has returned,
there is no way of knowing whether the values set came from
the command-line or the given default information.
The strings from the comman-line are parsed into values using
the airParseStr[] array of functions. These are
essentially wrappers around the system's sscanf
function, with two exceptions:
- When parsing floats or doubles, these
will recognize a strings containing "nan", "inf", "+inf",
and "-inf" as the IEEE 754 special floating point values.
- The booleans are actually treated as integers, but "on", "yes", "y",
"true", "t", and "1" are all parsed (in a case-insensitive
manner) as 1, and "off", "no", "n", "false", "f", and "0" are all
parsed as 0.
For reference, here again is the relevent section of the hestOpt
struct definition (from hest.h):
char *flag, /* how the option is identified on the cmd line */
*name; /* simple description of option's parameter(s) */
int type, /* type of option (from airType enum) */
min, max; /* min and max # of parameters for option */
void *valueP; /* storage of parsed values */
char *dflt, /* default value written out as string */
*info; /* description to be printed with "glossary" info */
int *sawP, /* used ONLY for multiple variable parameter options
(min < max > 2): storage of # of parsed values */
Some of the fields in the hestOpt struct are the same
regardless of the kind of option, or are the same for nearly all kinds
of options. They are described here, and not in the detailed
explanation of each kind (below). Exceptions to these general rules
are noted below.
- flag: This string contains the short, and possibly long,
form of the flag. If flag is NULL, then there is no flag
whatsoever, and the option is unflagged. Otherwise ...
- The short form of the flag is prefixed by a single hyphen
("-"); the long form is prefixed by two hyphens
("--"). If there is no "," in flag, then
the flag only exists in short form. If flag contains a comma,
then the characters before the comma
constitute the short form of the flag, and the stuff after the comma
is the long form of the flag.
- Flags are case sensitive.
- By their nature, unflagged options must appear on the command
line, while flagged options can either be mandatory or optional.
Whether or not a flagged option is mandatory or optional depends on
whether default information is given. If dflt is NULL, then
the option is mandatory; if dflt is non-NULL, then the option
is optional.
- Actually, the meaning of the , character in seperating
the short and long form of the flag is not fixed in
stone: the character signifying the break between the long and short
form of the flag can be set as the multiFlagSep field of the
hestParm struct, or by setting the
hestMultiFlagSep global.
- type: An integer value from the airType enum.
- valueP:
- This is always a pointer or address of some kind.
- Whenever memory is allocated by hestParse(), valueP
or *valueP will be set to point to it. Because the interpretion
of valueP is different for each option kind and type,
you probably shouldn't try to free this memory yourself. It is simplest
to just pass the same hestOpt array to hestParseFree(),
and it will free any and all memory allocated by hestParse().
- Even if it turned out that no memory was allocated,
hestParseFree() will know that, and there is no harm in calling
it needlessly.
- For all options, valueP can be NULL, so that the option will
parsed, but no values will be set, and no memory is allocated
- dflt: How default information is provided. As mentioned
above, whether dflt is NULL or not determines whether flagged
options are mandatory or optional. Default information is ignored
for unflagged options, because unflagged options are always mandatory.
- info is the string printed as part of the detailed
explanation of the options, generated by hestGlossary(). It is
always optional: it can be set to NULL if no detailed information is
needed.
- sawP is ignored for all kinds of options except
multiple variable parameter.
Stand-alone flags:
(min == 0; max == 0)
- flag: (see general rules above)
- name: Ignored (there are no parameters to describe)
- type: Ignored (int is assumed).
- valueP: The address of an int. If the flag appears
on the command line, *valueP is set to 1; if it does not appear,
valueP is set to 0.
- dflt: Ignored. (Stand-alone flags are inherently optional,
and there are no parameters to give values for.)
Single fixed parameter:
(min == 1; max == 1)
- flag: (see general rules above)
- name: Must be non-NULL. A succinct (one-word) description
of the single parameter to be supplied for this option.
- type: (see general rules above)
- valueP:
- For everything other than a string, this should
be the address of a variable with the type implied by the type
member above.
float v; ---> &v
- For strings, this should be the address of a char*:
char *s; ---> &s
- hestParse() set *valueP to the parsed and newly
allocated string: Memory will
be allocated.
- The above is true regardless of whether the string was parsed from
the command-line or from the default.
- Use NULL to tell hestParse() to discard the parameter after
parsing. No value is set, nor is any string allocated.
- dflt: If dflt is non-NULL, it should contain
the string representation of a single value of the type indicated by
the type member.
Multiple fixed parameters:
(min == max; max > 1)
- name: Must be non-NULL. This should be a succinct representation
of the option's parameters, and this representation should
explicitly indicate that multiple
parameters are required. This helps hestUsage() generate the most
useful usage information. For example, if you needed to supply X and Y
image resolution as two integer parameters, then the name should
be something like "resX resY", and not just "resolution".
- type: (see general rules above)
- valueP:
- This must be the base address of an already allocated array.
The reason the array should be already allocated is that you should know
exactly how many elements you want, or else you wouldn't be using a
multiple fixed parameter option.
- For all non-string types, valueP should be simply
the variable representing the pre-allocated array:
float v[3]; ---> v
The parsed values are stored in
the individual valueP[i] elements of the array (after appropriate
casting). No memory is allocated.
- For strings, the type of valueP should be char**,
kind of like argv itself:
char *str[3]; ---> str
Each valueP[i] element of the
array is set to a parsed and newly allocated string: Memory will be
allocated>.
Unlike argv, this can not be a NULL-terminated array of
char*s, because the array allocation size should be fixed
(by the caller) at the number of parameters.
- The above is true regardless of whether the string was parsed from
the command-line or from the default.
- Use NULL to tell hestParse() to discard the parameter after
parsing. No values are set, nor are any strings allocated.
- dflt: If dflt is non-NULL, it should contain
the string representation of a min values (or max
values, same thing) of the type indicated by the type member.
The different values, including strings, are delimited by white space.
Currently, quoted or escaped white space (so as to include white space
in strings) is not intelligently handled.
Single variable parameter:
(min == 0; max == 1)
- name: Exactly the same as for single fixed parameter.
- type: (see general rules above) Note, however, that
this kind of option was not really intended to deal with strings.
It is best suited for integer variables like verboseness or debug
level.
- valueP: The type information is exactly the same
as for single fixed parameter options. How the value is set,
however, is different. If the option is unflagged:
- If the option does not appear (that is, if the single parameter
constituting the option does not appear), then the value is set
to the default. For strings, this means memory is allocated.
- If the option does appear, the the value is set to the
command-line parameter. For strings, this means memory is allocated.
If the option is flagged:
- If the option does not appear (that is, the flag does not
appear), then the value is set according to the default. For strings,
this means memory is allocated.
- If the flag appears, but it has no parameters, then:
- For non-strings, the default is parsed, say, as value V,
and then the value is set to !V, the logical "not" of the value.
"Not" returns 0 (zero) for all non-zero values, and 1 (one) for zero.
- For strings, the value is set to NULL. No memory is allocated.
- If the flag appears, and has the single parameter, then the value
is set to that paramter. For strings, memory is allocated.
- dflt: This is the exception to all the other kinds of
options: the default string is required for single variable
parameter options. This is because of the funny semantics of
this kind of option.
Multiple variable parameters:
(min < max; max > 1)
Note: If you know ahead of time that you want at most, say,
five parameters for an option, then you can set max as 5. However, if
there is no obvious upper limit to the number of parameters, then set
max to -1. hest internally interprets this as
INT_MAX, from /usr/include/limits.h. Setting
min to 1 and max to -1 is the best way to support
parsing the output of command-line filename expansion, as from
"*.txt"
- flag: (see general rules above)
- name: Must be non-NULL. Should be a succinct description
of one of the option's parameters, or of the minimum number
of parameters (min), whichever is greater. The hestUsage()
function will follow name with ellipses ("...") in order to
represent the parameters that should constitute this option.
- type: (see general rules above)
- valueP: hestParse() will allocate an array (and
in the case of strings, allocate each string element of the array), and
set *valueP to the base address of that array. If you know ahead
of time how many parameters you want, then use a multiple
fixed parameter option.
- For all non-string types, valueP should be the
address of a variable which is a pointer to type:
float *vs; ---> &vs
In this case, *valueP (same as vs) will be set to the
address of the newly allocated array of floats, and all the
v[i] elements are set to the parsed parameters.
Memory is allocated for the array.
- For strings, the type of valueP should be char***,
because it must be the address of a char** array:
char **strs; ---> &str
In this case, *valueP (same as strs) will be set to the
address of the newly allocated array of char*, and the elements
strs[i] are set to the parameters. Memory is allocated,
both for the array of char*, and for the string elements
themselves.
- In contrast to multiple fixed parameter string
options, the char** array created by hestParse()
for multiple variable parameter string options
is NULL-terminated, like an argv. This is to support
the usage of hestParse() to extract a set of flagged options,
and then put the remainder of the command-line into a new char**,
which can then be treated as a new argv.
- The above is true regardless of whether the string was parsed from
the command-line or from the default.
- Use NULL to tell hestParse() to discard the parameter after
parsing. No values are set, nor are any strings allocated.
- dflt: Can be NULL or non-NULL; same rules as for
multiple fixed parameters, except that the number of items in the
dflt string should obviously be in the allowable range
(between min and max).