[Contents] [Index] [Help] [Retrace] [Browse <] [Browse >]

by John Orr


One of the new features in release 2.0 is system standard command line
parsing.  Its presence has two benefits: it standardizes the way in which
the user supplies command line arguments, making it much easier on the
user, and it also removes some tedious programming (and code size) from
every application that uses it.

The dos.library's ReadArgs() routine is the heart of this feature:

   struct RDArgs *rda = ReadArgs( UBYTE *argtemplate, LONG *argarray,
                                     struct RDArgs *myrda );

This function stores each argument supplied on the command line in its
corresponding entry in the array of LONG words, argarray.  The format in
which ReadArgs() stores each argument is based on the description of the
command line supplied in the first argument, argtemplate.  This
description is a C-style string containing a name for each argument.

Each argument name in the template should be a full, descriptive name (for
example ``Quick'' not ``Q'').  Each option can be prepended by an
abbreviation of the form ``abbrev='' (for example ``Q=Quick'').  The
argtemplate options must be delimited by commas.  Avoid using the names of
common commands as keywords, otherwise the user will have to delimit them
with quotes.

The ordinal position that an argument appears in the description string
determines what its corresponding position in argarray is (the first
argument corresponds to the first entry in argarray, the second argument
corresponds to the second entry in argarray, ...).  There must be an entry
in argarray for each argument in the description string so that ReadArgs()
has a place to store each argument's value.

Each argument name in the template can be followed by modifiers that tell
ReadArgs() the format of the argument.  The valid modifiers are:

/S - Switch.  This is considered a boolean variable.  If this option is
    present, ReadArgs() will set the corresponding array entry in
    argarray (an array of LONGs) to something besides zero. If the option
    is not present, ReadArgs() will set the entry to 0.

/K - Keyword.  This means that ReadArgs() will not fill in the
    corresponding entry in argarray unless the keyword appears with the
    parameter.  For example, if the template is ``Name/K'', then unless
    ``Name=<string>'' or ``Name <string>'' appears in the command line,
    the ``Name'' entry in argarray will not be altered by ReadArgs(). /N
    - Number. This means the parameter is considered a decimal integer,
    and ReadArgs() will convert it to a LONG.  If the argument is not
    valid, ReadArgs() will fail.  If the option is present in the command
    line (and it is valid), ReadArgs() will fill in the corresponding
    entry with a pointer to the LONG.

/T - Toggle.  This is similar to the switch (/S) modifier, but causes the
    corresponding boolean (in argarray) to toggle.   For example,  if the
    array entry corresponding to an argtemplate of ``binary/T'' is set to
    something besides FALSE and the word ``binary'' appears by itself on
    the command line, ReadArgs() will toggle that array entry to FALSE.

/A - Always.  This modifier tells ReadArgs() that this option is required.
    ReadArgs() will fail if the keyword does not appear in the command
    line.

/F - Final (rest of line).  If this is specified, the part of the command
    line that follows this option is taken as the parameter for this
    option, even if other option keywords appear in it.

/M - Multiple arguments.  This means the argument will take any number of
    strings (or integers as this modifier can be used with the /N
    modifier), returning them as an array of strings.  Any arguments not
    considered to be part of another option will be added to this option.
    Only one /M should appear in a template.  Example: for a template
    ``Dir/M,All/S'' the command-line ``foo bar all qwe'' will set the
    boolean ``all'', and return an array consisting of ``foo'', ``bar'',
    and ``qwe''.  The entry in the array will be a pointer to an array of
    string pointers, the last of which will be NULL.

There is an intentional interaction between /M parameters and /A
parameters.  If there are unfilled /A parameters after parsing, ReadArgs()
will grab strings from the end of a previous /M parameter list to fill the
/A's.  This is used for things like Copy (``From/A/M,To/A'').

If the user does not supply a non-required argument (one without the
``/A'' modifier) on the command line, ReadArgs() will leave the argument's
argarray entry alone.  Before calling ReadArgs(), a program should either
set the argarray entries to reasonable default values or clear them, so
the application can't be confused by any garbage values left in the array.

If it is successful, ReadArgs() returns a pointer to a RDArgs structure
(from <dos/rdargs.h>).  ReadArgs() uses this structure internally to
control its operation.  It is possible to pass ReadArgs() a custom RDArgs
structure (myrda in the ReadArgs() prototype above).  For most
applications myrda will be NULL, as most applications do not need to
control ReadArgs().

    struct RDArgs {
        struct    CSource RDA_Source; /* Select input source */
        LONG      RDA_DAList;         /* PRIVATE. */
        UBYTE     *RDA_Buffer;        /* Optional string parsing space. */
        LONG      RDA_BufSiz;         /* Size of RDA_Buffer (0..n) */
        UBYTE     *RDA_ExtHelp;       /* Optional extended help */
        LONG      RDA_Flags;          /* Flags for any required control */
    };

Any successful call to ReadArgs() (even those that use a custom RDArgs
structure) must be complemented with a call to FreeArgs() to free the
resources that ReadArgs() allocates:

    void FreeArgs(struct RDArgs *rda);

where rda is the RDArgs structure used by ReadArgs().

An application can use a custom RDArgs structure to provide an alternate
command line source, an alternate temporary storage buffer, or an extended
help string.  The custom RDArgs structure must be allocated with
AllocDosObject() and deallocated with FreeDosObject().  See the Autodocs
for more details on these functions.

The RDArgs.RDA_Source field is used to supply ReadArgs() with an alternate
command line to parse.  If this field is non-NULL, ReadArgs() will use it
as a pointer to a CSource structure describing the alternate command line.
The CSource structure (from <dos/rdargs.h>) is as follows:

    struct CSource {
        UBYTE   *CS_Buffer;
        LONG    CS_Length;
        LONG    CS_CurChr;
    };

Where CS_Buffer is the command line to parse, CS_Length is the length of
CS_Buffer, and CS_CurChr is the position in CS_Buffer from which
ReadArgs() should begin its parsing.  Normally CS_CurChr is initialized to
zero.

ReadArgs() uses the RDArgs structure's RDA_DAList field for internal use.
This field must be set to NULL before ReadArgs() uses this structure.

The RDA_Buffer and RDA_BufSiz fields allow an application to supply a
fixed-size buffer in which to store parsed data.  This allows the
application to pre-allocate a buffer rather than requiring ReadArgs() to
allocate buffer space.  If either RDA_Buffer or RDA_BufSiz is NULL,
ReadArgs() assumes the application has not supplied a buffer.

RDA_ExtHelp is a text string which ReadArgs() displays if the user asks
for additional help.  The user asks for additional help by typing a
question mark when ReadArgs() prompts the user for input (which normally
happens only after he or she types a question mark as the only argument on
the command line).

RDA_Flags is a bit field used to toggle certain options of ReadArgs().
Currently, only one option is implemented, RDAF_NOPROMPT.   When set,
RDAF_NOPROMPT prevents ReadArgs() from prompting the user.

The following code, ReadArgs.c, uses a custom RDArgs structure to pass a
command line to ReadArgs.