0.0: Invocation 1.0: Introducation 2.0: Packages 3.0: Options 4.0: Initializations 5.0: Usage 6.0: Handling Default Initializations 7.0: See Also
oui [options] file [file ...] -k Keep incomplete output file on error -o <filename> Specify Output Filename -q Print usage message -u Don't sort the "sort" strings -v Increasing level of verbosity -w Treat warnings as errors
oui
is a little language for processing Options, Usage and Initializations
for C programs.
When invoking a program from a shell command line,
"options" are characters which may be added to the program name,
possibly with arguments, which request a change in the behaviour of
the program. For example, the
-l
option to the command
ls
causes a long-format output.
"Usage" is text which describes the
options available from the command line as well as other useful
information about running the program. Under QNX, usage information
can be read by invoking the
use
utility, (e.g. use ls.
)
"Initializations" are C-language commands which must be executed before the features of a particular package can be used. This includes processing command-line options as well as any other startup operations such as clearing the screen or establishing a connection with a windowing system.
oui
reads in definition files for one or more "packages" and produces
C source code for a function called
oui_init_options()
and usage information compatible with the QNX
usemsg
utility.
oui
is particularly helpful as an adjunct to function libraries. Many
library "packages" require initialization code to be run and may
offer standard options to users from the command line.
oui
input file defines one or more "packages". The first line of the file
should be the package definition:
<package> sampleThis statement defines the name of the current package to be "sample".
oui
guarantees that each file is read only once and that each package is
defined only once. If an attempt is made to read a file more than once,
the subsequent attempts are simply ignored. If a package statement is
encountered for a package which is already defined, all of the statements
in the new definition are ignored. (This mechanism can be used for
overriding default definitions.)It is often the case that one package is only useful in combination with another package or packages. This can be indicated by way of the "include" statement:
<include> msgThis statement indicates that the current package requires the "msg" package. As it happens, there is a package named msg in the ARP oui library which defines the options, usage and initializations for programs accessing the
msg()
function. Any number of packages may be listed on one include statement.
When combining multiple packages, it is often the case that the
initializations for one package must come before or after the
initializations for another package. This type of dependency can be
expressed through the
<preceed>
and <follow>
statements.
<follow> msg msghdr dgThis statement requests that the initializations for the current package be sequenced after any initializations for the msg, msghdr and dg packages. The preceed and follow statements do not cause the specified packages to be included. They simply specify the ordering if they are included by some other mechanism.
oui
supports the POSIX-style command-line options as accepted by the
getopt()
function. This style of options consists of single-letter options which are
preceeded on the command line by a hyphen (e.g. ls -l). An option letter
may take an argument (e.g. sin -n 1). Multiple options may be combined by
concatenation (e.g. ls -lt).
If your package is going to support one or more command-line options,
you must specify which option letters it will handle in an
<opts>
statement:
<opts> "lt:q"This statement indicates that the program will accept option letters l, t and q, and that the t option requires an argument. The syntax of this statement is important. There should be no spaces or tabs after the right angle bracket or between or after the option letters.
When packages are combined, the options required by each package are checked against the options for every other package to guarantee that there are no conflicts. In certain special cases, two related packages may wish to "share" an option letter. This can be accomplished by creating a third package which they both include. This is the case with the msg package and the client package which share the -h option. If they each specified h as an option, oui would complain that there was a conflict.
Specifying the option letters only means that the application will quietly accept those options at runtime. We have not as yet told oui what to do when those options are specified.
<init>
statement specifies code to be executed during initialization. This code
does not necessarily have anything to do with options:
<init> printf("Starting Up...");Within the ARP libraries, we use the convention of naming functions which handle command-line options using the suffix "_init_options()". The DG package contains the lines:
<init> DG_init_options(argc, argv);(You should recognize
argc
and argv
as the standard C method of accessing the command line in the main
program.) Your package may include any number of lines after the
<init>
statement.
If your initialization references a function or data object, that object
should most likely be defined prior to its invocation. This is usually done
in C via the #include
statement. In oui, this is replaced with the
<include>
statement:
<include> "dg.h" <include> <stdlib.h>Note that this is the same keyword which is used for including additional oui packages. The difference is that C header filenames are enclosed in quotes or angle brackets.
You should include any header files required by your initializations
without regard to whether other packages might also be including those
headers. oui will guarantee that only one
#include
statement will be generated for each required header.
Sometimes you will need to make global or static definitions within the C
file which is generated by oui. The
<defs>
keyword is used for this purpose. Each line following the
<defs>
command is copied into the output file outside of the initialization
function:
<defs> int file_count; #define MAX_FILES 5In other cases, a local variable is required within the initialization function for holding intermediate values or default initializations. This is handled by the
<vars>
command. Each line following this command is placed in the output
immediately after the declaration of the initialization function prior to
any of the
<init>
statements. I will describe later how these variables are used to
provide default initialization parameters.
Often you may find you want to add a single option to an existing program,
for example passing a calibration constant to a data extraction program.
Ordinarily, processing any options requires generation of a function which
loops while calling
getopt().
This is somewhat tedious when only a single option is required. The
<switch>
and
<arg>
commands will generate this loop for you automatically. Lines following the
<switch>
command are placed inside a switch statement in a position suitable for
case
statements. For example, the commands:
<switch> case 'l': limit = atoi(optarg); break;will process a -l option which takes an integer argument. When an argument is required (as specified by a ':' following the option letter in the
<opts>
statement), the <switch>
code can reference the argument string via the global variable
optarg
as described in the getopt()
documentation.
Warning: As currently implemented, the <switch> command does not respect the <follow> and <preceed> directives. A single loop is generated and is placed before all the other initializations. However it can still be useful in these cases: go ahead and use <switch>, then use the generated C code to create your own init_options() function. You can put the new init_options() function back into the .oui file under <defs>, remove the <switch> and replace it with an <init> referencing the new function.
The <args>
command will place code in a loop which processes any arguments remaining
on the command line after the options are handled. Again, the
optarg
variable is used to reference each argument in turn:
<args> process(optarg);
Note that the same caveats apply to <args> as apply to <switch>. It is really only useful in very simple cases.
<synopsis>
command may be used to override the default command-line synopsis,
<sort>
may be used to give one-line descriptions of the options supported
by this package, and <unsort>
may be used to supply more general usage information.
<synopsis>
accepts exactly one line of text which becomes the first line of
the programs usage message. There may be only one
<synopsis>
statement among all the packages referenced, since there can be
only one synopsis. The default synopsis is:
%C [options]and is often sufficient if coupled with good descriptions of the options.
Usage for the options is provided with the <sort>
command:
<sort> -l <limit> Define a new upper limit -c Clear the server's error countEach option line should begin with a tab character, which will line up the resulting output with the synopsis' "[options]". As the command implies, all the <sort> lines are sorted by option letter before being output. This behaviour can be disabled by specifying -u on the oui command line.
More general usage can be provided with the
<unsort>
command. This text will not be rearranged in the final output,
so it is possible to provide paragraphs of information.
Oui always ignores blank lines and lines with only whitespace in the
input, since whitespace often helps to make the input file readable.
This can present a problem if you want a blank line to appear in the
output. This is most likely only in the
<unsort>
text, but might arise elsewhere also. The
<blank>
command will introduce a blank line into the output of the appropriate
section.
Finally, comments may be introduced to the input file by way of the
<comment>
command. All lines following this command up to the next keyword
are treated as comments and ignored.
msg_init_options() ,
for example, requires a default message header which may be overridden
by a command-line option. Often the package creator can predict a
reasonable default behaviour, but a particular application may wish
to provide a different default behaviour. For msg ,
a default header of "hdr" is OK in the general case, but collection
programs should use a default of "col", soldrvs should use "sol"
and so on.I have come up with a mechanism to provide this sort of flexibility. It works like this:
1) The package in question defines a local variable
to hold the initialization parameter. In our example, the package is
msghdr
and the initialization parameter is the message header:
<package> msghdr ... <var> char *msg_hdr;2) A second package is defined, usually in the same file as the first package, which provides the default initialization:
<package> msghdr_init <init> msg_hdr = "hdr";3) Note that the parameter initialization must preceed the use of that parameter in the final output. Hence a statement
<follow> msghdr_initmust be placed in the package which uses the parameter.
4) An application (or another library package) wishing to override
the initialization simply redefines the msghdr_init
package, providing a different initialization. The first package
by that name which is read by oui is the only one which is
used, so controlling the order in which the packages is read
controls which initialization takes effect.
This approach has proven effective in handling a wide range of message header defaults. The hooks have not been fully realized for other packages requiring additional parameters, such as the command control package, but I believe the same approach can be made to work there.
getopt()
function
in the "Watcom C Library Reference". There is also a compatible
getopts function available in the shell (/bin/sh
), which
is documented under "sh" in the "QNX Utilities Reference-N to Z"
Return to Manuals Guide
last updated: Wed Nov 21 15:21:10 2007 | webmaster@huarp.harvard.edu |
Copyright 2007 by the President and Fellows of Harvard College |