class ref name: rundriver
class name: rundriver
category-group: quickdirt
layer: 0
header file: z_rundriver.h
libraries: libz00.lib

synopsis.
The rundriver class introduces a protocol for non-GUI programs - those run from a command line (whether in a unix shell or a Microsoft "cmd" [console] window). The class also provides a framework for programs - a program can run in "interactive" mode - getting requests from the user, then doing it; or in "batch" mode. It specifies a protocol for command-line flags (reminiscent of getopts), and a set of actions associated with the flags. See the quickdirt group page for a listing of these flags.

rundriver_o is a "near-virtual" class. That is, you can use the class object as-is, and not sub-class from it, but it is not intended to be used as-is. You should make a subclass from this class, in order to do something useful. The rundriver functions batch(), and interactive() do absolutely nothing. However, you can instantiate a rundriver_o object - perhaps you want it for just parsing a command line, for example.

This class falls into the category of "manager" type objects. A program should have only 1 instance. The job of this singleton instance is to help manage the affairs of the program.

description.
A typical command-line (console-based) program often includes tasks common to many other programs:

- process its command-line arguments to obtain settings for the program;
- display a brief help message to explain the command-line options;
- display a longer help message to explain the program;
- show what version of the program it is;
- set the level of trace messages to display (called "volume" here);
- for database-oriented programs, get the name of the server and the name of the database to connect to;
- run the program.

Ths rundriver_o class allows you to simplify these tasks, and sets up a standardized framework for them.

Unlike the menuloop object [layer 0], rundriver does not have a perpetual loop. After all initial configuration is done, run() is called and that is where you would normally exit out of the program. What run() does is entirely up to you.

The rundriver_o class employs a fixed set of command-line flags (eg "options"). These flags are the following:

-V:    shows version information
-h:    shows a brief help message, then exits
-help: shows help (long format)
-fullhelp: shows loads of help (extra-long)
-i:    run in "interactive" mode
-batch: run in "batch" mode
-wet:  run in "wet" mode
-dry:  run in "dry" mode
-vol [n]: (also "-volume) sets program "volume" ('n' is in [0 .. 100])
-server [name]: set RDBMS server
-db | -database [name]:  set RDBMS database name (if used)
"interactive mode" - a framework is created for letting a user, perhaps a tester, let the object do its various tasks. Typically, the user can set values and configure the objec, then do the object's operations, and display the results. This is better than batch or validation code, in that it does not limit you to whatever specific combination of data values and operations were installed into the code, which then becomes immutable. Thus unforeseen usage or values can be tried at any time.

"batch mode" - the batch() function is a placeholder where you can develop a batch process (say, run nightly via a cron job) for the object. Or, you can use it to try various features of the object.

The output is typically displayed to the user in detail. This differs from validation as it is not a rigorous, formal attempt to verify correctness. And it differs from interactive testing since it simply runs and does its thing. Hence, it can be put into a larger framework of a test suite, run overnight, and then scrutinized the next day. "batch" is often a by-product of the developer's thoughts while he or she is creating the underlying object.

"Wet mode" and its converse "dry mode" are provided as a convenience to the application. If the program sets "dry mode", either via the command line or an explicit call to member function set_drymode(), it can then query the object, and if it's in dry mode, not do anything or change any data when applicable:

    rundriver_o x;
    x.set_drymode();
    /* a whole lot of code */
    .
    if (x.is_wet())
    {
        /* send an e-mail */
        /* update a database */
        /* web server: reply to a client */
    }
    /* ..more code */
This is a simple concept, and is provided as a troubleshooting tool. The default is [logically] "wet mode".

member functions (primary)

rundriver_o()
SIGNATURE: rundriver_o ()
SYNOPSIS: creates an empty rundriver object. all flags are at their default values.
 

volume()
SIGNATURE: int volume () const
SYNOPSIS:
informational: the "volume" the user wants. the value is from 0 to 100, always. 0 means completely silent (except for unrecoverable errors); 100 indicates maximum trace information, at every possible opportunity. Typically, trace level 100 requires an editor to process thousands of lines of output.
 

is_wet()
SIGNATURE: boolean is_wet () const
SYNOPSIS:
this is a convenient, informational flag totally under application control. It is intended to help the application know if it should run under "wet" or "dry" mode. "Dry mode" is a dry run - the program goes through all its paces, but does not affect any actual data or do any actual work. This flag is a troubleshooting tool.
DESCRIPTION:
If the application has set "wet mode" by calling set_wetmode(), this function returns 1. If in "dry mode (done by calling set_drymode() or set_wetmode(FALSE)), this returns 0.
TRAITS: this function is inline
 

do_version()
SIGNATURE: boolean do_version () const
SYNOPSIS: informational: if return value is 1, the program version should be displayed (and then program exit).
TRAITS: this function is inline
 

do_help()
SIGNATURE: boolean do_help (int *plev = NULL) const
SYNOPSIS: informational: if return value is 1, a help message is desired. the program should then exit.
PARAMETERS

  • plev: an optional [output] variable that tells what "detail level" of help is desired:
    0: none - the command-line had no "help" parameters;
    1: brief ("-h") - display a summary list of command- line parameters (and exit)
    2: long version
    3: full help - provide the user with a lot of info
  • DESCRIPTION: if this function returns TRUE, the program is to display help, and exit with exit code 0.
    RETURNS:
    TRUE: help is needed/wanted. show help message and exit.
    FALSE: no help wanted
     

    do_interact()
    SIGNATURE: boolean do_interact () const
    SYNOPSIS:
    informational: tells if the object is in "interactive mode" (the definition of what "interactive mode" is entirely in user control). When in interactive mode, run() calls interactive().
    TRAITS: this function is inline
     

    do_batch()
    SIGNATURE: boolean do_batch () const
    SYNOPSIS: informational: tells if the object is in "batch mode". when in batch mode, run() calls batch().
    TRAITS: this function is inline
     

    use_kbjerk()
    SIGNATURE: boolean use_kbjerk () const
    SYNOPSIS:
    if this is set, this means that we should get missing information from the console. if this is not set, then we should abort an operation, due to missing data.
    TRAITS: this is a rather strange feature - the "keyboard jerk"
     

    is_nonstop()
    SIGNATURE: boolean is_nonstop() const
    SYNOPSIS:
    this tells if some operations will go on if an error is encountered. if this returns FALSE, operations such as batch() should stop upon an error.
    TRAITS: this function is inline
     

    is_abort_oner()
    SIGNATURE: boolean is_abort_onerr() const
    SYNOPSIS:
    this tells if some operations should abort if an error is encountered. if this returns TRUE, operations such as batch() should stop upon an error.
    TRAITS: this function is inline
     

    stop_onerr()
    SIGNATURE: boolean stop_onerr() const
    SYNOPSIS:
    this tells if some operations should abort if an error is encountered. This function is an alias for is_abort_oner().
    TRAITS: this function is inline
     

    name()
    SIGNATURE: int name (int *pe = NULL) const
    SYNOPSIS:
    returns the name of the program (in output parameter 'buf'), which is set by call to member function set_name(). This function is just part of simple "get and set" routines.
    PARAMETERS

  • pe: an [output] error indicator variable. values:
    0: success; name retrieved
    zErr_Param_NotSet: name not set
    zErr_Param_NullPointer: my_prognam is null
  • RETURNS:
    0: success
    -1: error (see value of 'pe')
     

    database_server()
    SIGNATURE: int database_server (char *buf, int *pe = NULL) const
    SYNOPSIS:
    returns the name of the database server (in output parameter 'buf'), if set by call to member function set_database_server().
     

    database_name()
    SIGNATURE: int database_name (char *buf, int *pe = NULL) const
    SYNOPSIS:
    returns the name of the database (in output parameter 'buf'), which is set by call to member function set_database_name(). This function is part of just simple "get and set" routines.
     

    database_account()
    SIGNATURE: int database_account (char *buf, int *pe = NULL) const
    SYNOPSIS:
    returns the user account name for the database. The result is copied into output parameter 'buf'. The value is set by a call to member function set_database_account(). This function is part of just simple "get and set" routines.
     

    database_password()
    SIGNATURE: int database_password (char *buf, int *pe = NULL) const
    SYNOPSIS:
    returns the password for the database user account. The result is copied into output parameter 'buf'. This value is set by call to member function set_database_password(). This function is part of just simple "get and set" routines.
     

    help_level()
    SIGNATURE: int help_level() const
    SYNOPSIS: tells what level of help is wanted [1..3]
     

    is_runparam()
    SIGNATURE: boolean is_runparam (const char *str, boolean &warg, int *xtra = NULL, int *pi = NULL)
    SYNOPSIS:
    This routine tests if argument is one of the standard command-line parameters, to be processed by rundriver_o::cmdline(). This is convenient for child (eg, sub-) classes to check if their unknown command-line parameters are illegal or standard ones. This function is static, so it must not be used with an object instance.
    example:
    boolean boo = rundriver_o::is_runparam ("help"); if (!boo) { /* not a rundriver parameter; could be illegal */ }
    PARAMETERS

    • str: the string (from argv[]). The text in "str" may include a leading dash ('-') or slash ('/') character. A "dash" is the Vettrasoft-standard leading character for command-line options; however, a slash is also allowed for the rundriver object.
    • warg: [required output] boolean variable, tells if the parameter specified by "str" takes an an argument. If "str" is invalid, "warg" is set to FALSE.
      example:
      boolean got_arg, is_parm;
      is_parm = is_runparam("vol", gotarg);
      In this case, both "is_parm" and "got_arg" are TRUE, since "vol" is a rundriver command-line argument, and it requires a value (which would immediately follow "-vol" on the command-line).
    • xtra: [optional output] variable type indicator flag. values:
      0: a 'core' standard rundriver_o parameter
      1: an 'extended' rundriver_o parameter (eg, such as for database-oriented operations)
    • pi: [optional output] error indicator flag. values:
      0: ok; variable is a valid rundriver object parameter;
      1: variable is not a rundriver object parameter;
      2: NULL pointer (application error);
      3: "str" is a dash ('-') only {munged input data).
    RETURNS:
    TRUE: command-line argument belongs to rundriver_o.
    FALSE: argument is not known to rundriver_o (either application-specific, or errant).
     

    isvalid_arg()
    SIGNATURE: boolean isvalid_arg (const char *name)
    SYNOPSIS: this tells if the string given my 'name' represents a valid rundriver_o command-line argument
    DESCRIPTION: this function is a simplified version of is_runparam().
    TRAITS: this function is static
     

    arg_isinteractive()
    SIGNATURE: boolean arg_isinteractive (const char *, int * = NULL)
    TRAITS: this is a static function. it must be called as testdriver_o::arg_isinteractive().
     

    arg_isbatch()
    SIGNATURE: boolean arg_isbatch (const char *, int * = NULL)
    TRAITS: this is a static function. it must be called as testdriver_o::arg_isbatch().
     

    set_wetmode()
    SIGNATURE: int set_wetmode (const boolean bf = TRUE)
    SYNOPSIS: this assigns either wet mode or dry mode to the object (and by interpretation, to the program).
    PARAMETERS

  • bf: an [input] value for the wet-mode flag. if TRUE, object is set to "wet mode", if FALSE, object is set to "dry mode"
  • RETURNS: 0 (always)
     

    set_drymode()
    SIGNATURE: int set_drymode ()
    SYNOPSIS: this assigns "dry mode" to the object (and by interpretation, to the program).
    RETURNS: 0 (always)
     

    set_volume()
    SIGNATURE: int set_volume (int x)
    SYNOPSIS:
    this assigns a 'volume level' that controls which error and debug messages are emitted when the program is run. A value is assigned to a message, and an overall value assigned to the program at run time. If the message volume value is less than or equal to the program run-time level, the message is printed.
    PARAMETERS

  • x: an [input] value for the volume. 'x' must be within 0 to 100 (inclusive) in order for this call to succeed.
  • RETURNS:
    0: success
    -1: error, value out of range
     

    set_name()
    SIGNATURE: int set_name (const char *prog_name)
    SYNOPSIS:
    this assigns a name for the program and the class corresponding to it. The names are kept in the rundriver object. You should use the name of the current program as the argument.
     

    set_name()
    SIGNATURE: int set_name (const char *prog_name, const char *obj_name)
    SYNOPSIS:
    This assigns a name for the program. This version of "set_name()" allows you to use a name for the class object that is separate from the program. You should use the name of the current program (without the path) for the first argument. The second parameter allows you to use a different name for the class object name (this is mainly for test drivers).
    Note: this function may be going away, to be replaced by the single-parameter version of "set_name()".
     

    set_safety()
    SIGNATURE: int set_safety (boolean = TRUE)
    SYNOPSIS:
    [WARNING: OBSOLETE - this is an old note]
    this sets "safe" mode, for when doing validations.
    TRAITS: the meaning-purpose of this function has ben lost
     

    set_database_server()
    SIGNATURE: int set_database_server (char *my_name, int * = NULL)
    SYNOPSIS: sets the name of the database server to acces to "my_name".
     

    set_database_name()
    SIGNATURE: int set_database_name (char *my_name, int * = NULL)
    SYNOPSIS: sets the name of the database to acces to "my_name".
     

    set_database_account()
    SIGNATURE: int set_database_account (char *my_account, int * = NULL)
    SYNOPSIS: sets the database user account name to "my_account".
     

    set_database_password()
    SIGNATURE: int set_database_password (char *my_password, int * = NULL)
    SYNOPSIS: sets the password for database acces to "my_password".
     

    set_kbjerk()
    SIGNATURE: int set_kbjerk (boolean my_jerk = TRUE)
    SYNOPSIS: set the "keyboard jerk" flag to TRUE or FALSE, according to "my_jerk". Default value is TRUE.
    TRAITS: the meaning-purpose of this function has ben lost
     

    set_interactive()
    SIGNATURE: void set_interactive (boolean new_mode = TRUE)
    SYNOPSIS: sets the object's mode to "interactive".
    TRAITS: this function is inline
     

    clear_interactive()
    SIGNATURE: void clear_interactive ()
    SYNOPSIS:
    unsets the object's mode from "interactive" (whether or not it was set prior). if it was not in interactive mode, this is a do-nothing operation.
    TRAITS: this function is inline
     

    set_batch()
    SIGNATURE: void set_batch (boolean new_mode = TRUE)
    SYNOPSIS: sets the object's mode to "batch".
    TRAITS: this function is inline
     

    clear_batch()
    SIGNATURE: void clear_batch ()
    SYNOPSIS:
    turns off "batch mode". note, there is no 'fail-over' mode, in that another mode is assumed. if "batch mode" is turned off, any batch operations are skipped.
    TRAITS: this function is inline
     

    cmdline()
    SIGNATURE: int cmdline (const int, char **, int * = NULL)
    SYNOPSIS:
    command-line processor function. This class has its own. If you sub-class from the rundriver object, you can do 3 things:

    • hide this function my making its own version of cmdline().
    • make your own version of cmdline(), but call the parent (rundriver_o) version inside.
      see the example.
    • use the default function (this one). cmdline().
    • do command-line processing outside of the rundriver class (your own).
    • not do any command-line processing at all.

     

    help()
    SIGNATURE: virtual void help (boolean long_fmt = FALSE, const char *progname = NULL) const
    SYNOPSIS:
    this function is called if help is to be displayed. If and when this is called is completely under application control. However, it is called automatically inside setup() - if that function is used.
    PARAMETERS

    • long_fmt: if TRUE, the long version of help is to be displayed. the standard convention is to call help(), then if this flag is set, to call usage().
    • progname: the name of the program. This string is provided as a convenience.
     

    usage()
    SIGNATURE: virtual void usage (const char *prog_name = NULL)
    SYNOPSIS: provides a more detailed help message. purpose is similar to that of member function help().
    PARAMETERS

  • progname: the name of the program, as it is to be displayed. This string is provided as a convenience.
  •  

    version()
    SIGNATURE: virtual void version (const char *) const
    SYNOPSIS:
    show version information. if this function is not shadowed in a subclass (eg rundriver_o::version() is called), it will show a "build date:" string using the built-in compiler macros __DATE__ & __TIME__
     

    description()
    SIGNATURE: virtual void description (const char *prognam = NULL) const
    SYNOPSIS:
    this function continues in the spirit of help() and usage(). it is intended to provide off-line help (such as popping up a GUI-based help book).
     

    setup_install()
    SIGNATURE: virtual int setup_install (int *pe = NULL)
    PARAMETERS

  • pe: error indicator var. returns 0
  • TRAITS: the meaning-purpose of this function has ben lost
     

    set_up()
    SIGNATURE: int set_up (const int argc, const char **argv, int *pi = NULL)
    SYNOPSIS:
    this is a convenience function. normally, it is up to you (eg, the application) to decide when, where, and how to call the member functions of this class. or you can simply call set_up(). This member function will:

    1. call z_start().
    2. call rundriver_o::cmdline().
    3. call your [overloading] cmdline().
    4. display help (if desired).
    5. display version info (if desired).
    6. do validation (if desired).

    TRAITS: this function is virtual
     

    reset()
    SIGNATURE: int reset ()
    SYNOPSIS: sets the rundriver object to at-construction state, with all names wiped out and all flags reset.
     

    clean_up()
    SIGNATURE: int clean_up ()
    SYNOPSIS: the converse of set_up(). provided for symmetry
     

    run()
    SIGNATURE: int run (const int argc, const char **argv, int *pi = NULL)
    SYNOPSIS:
    this function, as-is in this class, is useless, and thus is not intended to be used. You should sub-class from rundriver_o, making your own function with the same signiture in the subclass. This will over-ride rundriver's run() function. Calling your own run() will invoke the parent classes' function.
    RETURNS:
    0: rundriver action found and performed (batch; help; version info; etc.)
    1: no rundriver action encountered; no errors
    -1: got an error (see output value of 'pi' for more info)
    TRAITS: this function is virtual
     

    interactive()
    SIGNATURE: int interactive (int my_volume = 0)
    SYNOPSIS:
    Runs "interactive mode". In the testdriver_o class itself, this function is a no-op: nothing is done and 1 is returned. This function is intended to be redefined and implemented in sub-classes derived from the testdriver_o class.
    TRAITS: this function is virtual
     

    batch()
    SIGNATURE: int batch (int my_volume = 0)
    SYNOPSIS: Runs "batch mode". In the testdriver_o class itself, this function is a no-op: nothing is done and 1 is returned.
    TRAITS: this function is virtual
     

    note.
    This class has no copy constructors or assignment operators, because (Highlander) it is intended to be only one.

    Earlier versions of this class provided "validation" services - one could set/unset whether to do validataion, and a function ("valiate()") existed. Everything related to validation was removed, as it was the realm of the sub-class testdriver_o, and clearly did not belong in this [base] class.

    examples.
    here is a quick example showing how to use this class. this is taken from Vettrasoft's krypt file encryptor program. a great mass of code has been culled out, leaving only what pertains to the rundriver class.

    #include "z_rundriver.h"
    
    class krypt_driver_o : public rundriver_o
    {
    public:
        krypt_driver_o () { }
    
        // --overrides--
        virtual int     cmdline     (int, char **);
                void    version     (const char *);
        virtual void    help        (boolean = FALSE, const char * = NULL) const;
        virtual void    usage       (const char * = NULL) const;
        virtual void    description (const char * = NULL) const;
        virtual int     validate    (const char *, int = 0, boolean = TRUE);
    
        // -- runs the driver--
        int run (int, char **);
    };
    
    
    //----------------------------------------------------------------------
    int main (int argc, char *argv[])
    {
        krypt_driver_o rd;
        rd.set_name ("krypt", "krypt_driver");
        ie = rd.run (argc, argv);
        exit (ie);
    }
    
    //----------------------------------------------------------------------
    int krypt_driver_o::run (int argc, char **argv)
    {
        int ie = rundriver_o::run (argc, argv);
        if (ie) return ie;
    
        if (do_help())
            exit(0);        // help was already done; just get out of here
    
        if (volume() > 20)
            std::cout << "hello, good morning, goodbye, goodnight.\n";
    
        return 0;
    }
    
    //----------------------------------------------------------------------
    int krypt_driver_o::cmdline (int argc, char **argv)
    {
        int ie, i;
        ie = rundriver_o::cmdline (argc, argv);
        if (ie < 0) return -1;
    
        for (i = 1; i < argc; i ++)
        {
            if (argv[i][0] == '-')
            {
                s = &argv[i][1];
                if (s == "krypto")
                    { /* ... */ }
                else if (s == "cough")
                    { /* ... */ }
                else if (s == "burp")
                    { /* ... */ }
            }
        }
        return 0;
    }
    
    //----------------------------------------------------------------------
    void krypt_driver_o::help (boolean do_long_fmt, const char *e_name) const
    {
        std::cout << e_name << ": encrypt/decrypt a file\n";
    
        if (do_long_fmt)
            usage (e_name);
    }
    
    //----------------------------------------------------------------------
    void krypt_driver_o::usage (const char *e_name) const
    {
      std::cout << e_name << ": add some instructions how to use this program..\n";
    }
    

    bugs.
    the return values of do_help(), do_version(), do_validate(), in_safe_mode (), and use_kbjerk() should be changed to boolean. return value of int is not consistent with the remainder of the Z Directory.

    history.

    Sat 10/05/2002: created; rundriver_o is born
    Wed 04/06/2011: added m_cmdline_done flag; some clean up
    Sat 09/12/2015: created 'isvalid_arg()' [-GeG]