Commander Help

Design Overview

Contents | Bottom

Commander includes the following components:

How to Test Commander Against the Sample Meta-File

The quickest way to understand Commander is to try it from the VFP Command Window by running the following command:

? commandr( )

This will automatically initialize the default meta-file and evaluate the default sample function, which just displays a WAIT WINDOW message.  Creation and maintenance of the Commander meta-file can be done via VFP's BROWSE command, and this is made easier by taking advantage of VFP's Browse preferences, e.g. via the BROWSE LAST option.  Of course you can also populate the Commander meta-file programmatically, which is a major benefit of the design.  (See the Saver application for an example of totally programmatic meta-file creation and use of the Commander facility.)

Try running commandr( ) against the sample pseudo-function definitions, which you can review in a BROWSE window.  The current record determines the default functionid, when you pass no arguments to commandr( ).  Go through the examples in sequence, to see the simplest ones first.  Look in the Notes field for explanatory comments about each function.  The meta-file records for functionid = 'demo07', for example, illustrates the factorial function.  The example for functionid = 'demo07b' shows another way to implement the factorial function more cleanly and efficiently, using the m.cmdr_self global memory variable and direct calls to method cmdrm_dofunc.

To clean up after testing commandr( ) without closing out the current VFP session, use this command:


This will release the default Commander object and close the meta-file, which is useful during development and testing of the Commander facility itself, to avoid "class is in use" errors.

Arguments and Global Memory Variables

Both the Commander shell UDF, commandr( ), and the primary Commander method, CMDRM_DoFunc, support the same calling syntax, i.e. they take the same arguments and return the same result.  From VFP command level you would use the UDF interface supported by commandr.prg/fxp/app, which also handles various initialization details.  (If you are using the Commander class-level interfaces, you have explicit control over more flexible initialization options.)  In either case, the following 10 optional arguments are supported:

Because the arguments are declared PARAMETERS (as opposed to LPARAMETERS) in method CMDRM_DoFunc, they behave as PRIVATE memory variables, scoped to be visible during the execution of metafile-based function steps.  In addition to these arguments, a Commander function can employ any of the following global memory variables, declared as PRIVATE and initialized by CMDRM_DoFunc:

Memory Variable Description
cmdr_exit forced termination flag (for convenient EXIT from the processing loop).  Setting this flag to .T. will cause CMDRM_DoFunc to terminate without proceeding to the next step defined in the meta-file.
cmdr_funid current functionid being processed, which may have been determined by default if no explicit cmdr_idarg was supplied.
cmdr_next next sequence number to GOTO, if value is numeric.  Executing a step that assigns a sequence number to this mvar overrides the normal sequential flow, instead jumping directly to the given seq # within the same functionid.  Upon making such a jump, the value of m.cmdr_next is automatically reset to .F.  If the given seq # is not found (for the current functionid), an error is produced.  No special action is taken if m.cmdr_next is non-numeric, or if the end of the pseudo-function is encountered (i.e. if m.cmdr_next is assigned a value in the last step of the function definition).  There is no check for possible infinite loops, so use this feature with care.
cmdr_nuarg count of optional user-defined arguments (not including the initial cmdr_idarg).  This is only useful when Commander's CMDRM_DoFunc method is called directly within an application, as opposed to calls originating from the shell UDF interface, commandr( ).
cmdr_retvl function return value (defaults to .T.).  By assigning a value to this variable, you can set any type of value to be returned as the result of the CMDRM_DoFunc.  If an error is encountered, however, the result will always be .F., regardless of the value of m.cmdr_retvl.  (Detailed error information is returned via the standard ErrHandler mechanism, so you can easily sort out error cases from other results.) 
cmdr_self current Commander object reference, i.e. a way of referring directly to the Commander class object that is running the present function evaluation.

The Commander Class

The Commander class is a modular, general purpose component that can be used in any VFP application to support dynamic, table-driven functions.  The following custom properties and methods are attached to each Commander object (in additional to the standard error handling properties and error handling methods inherited from ErrHandler):

Commander Properties

Property containing the length of the functionid field in the Commander meta-file.  This is automatically initialized in method CMDRM_Open.
Property containing the fully-qualified path to the meta-file of function definitions used by this object.  Initialized automatically in the Init event method.
Flag property to suppress errors in CMDRM_DoFunc when the specified functionid is not found.  Defaults to .F.  If the application sets this to .T., missing functionid cases are treated as successful no-ops, not errors.

Commander Methods

cmdrm_addfuncstep (funcid_arg, seq_arg, cmdlin_arg)
Method for adding a single meta-file record, corresponding to a single procedure step.  This method re-uses logically deleted records.  Returns a success flag result.
cmdrm_deletefunc (funcid_arg)
Method for deleting all meta-file records associated with a given functionid.  Returns a success flag result.
cmdrm_dofunc (cmdr_idarg, cmdr_arg1, ..., cmdr_arg9)
Method to invoke a specified table-driven function with optional user-defined arguments.  Returns a success flag result or an optional user-defined result.  Both this method and the commandr( ) UDF interface support the same arguments.
cmdrm_open (funcid_arg)
Method to open the commander meta-file.  This is used internally to support automatic opening by other Commander methods, as necessary.  (Automatic creation of a new meta-file is handled by logic in the Init method.)  Returns a success flag result.
cmdrm_seekfunc (funcid_arg)
Method to do a lookup for a given functionid.  Returns .T. if a non-deleted record is found, else .F.

Init (metafi_arg, targob_arg)
The Commander.Init event method supports these 2 optional arguments:

metafi_arg: function definitions meta-file path/name, including extension.  If the specified meta-file is not found, it will be created automatically from a template meta-file.  If this argument is omitted or empty, the default meta-file name (defined by macro CMDM_FILE in include file commandr.h) will be used.

targob_arg: optional object reference to the target ErrHandler to be used.  If supplied, hold on to the given ErrHandler in ehp_targobj.  If NULL, empty, or omitted, let ehp_targ... properties determine the target ErrHandler requirements and any related initializations.
The only other native VFP method with any Commander class logic, aside from Init, is the Destroy event method.  This logic does nothing but close the meta-file (under the alias defined by the macro CMDM_ALIAS defined in include file commandr.h), if it's still open.

Commander Meta-File Structure

Commander uses a "meta-file" to store its representation of user-defined functions.  This is simply an indexed VFP table of records that define one or more uniquely named pseudo-functions, each comprised of a sequence of steps.  The Commander application includes a sample meta-file and an empty template meta-file, from which any number of additional Commander meta-files can be generated automatically (by logic in the Init event method).  These files all share the following structural details:

Meta-File Fields

Field Name Type Width Description
FUNCTIONID Character 10 Id of the pseudo-function to which this record belongs.  Each record defines a step in the function logic.  Functionid + seq comprises a unique key for each record.  Commander allows the length of this field to be altered, but it defaults to 10.
SEQ Numeric 10 Sequence number for ordering of steps within each function definition (regardless of the physical record order).  Gaps are allowed in the sequence of steps; only the order matters.  This field forms the suffix of the unique key for each record.  Commander allows the length of this field to be altered, but it defaults to 10.
CMDLINE Memo 4 Arbitrary VFP command line for this step of the function logic.  This will normally be invoked by &-macro expansion in Commander's CMDRM_DoFunc method.  Commander also supports a special string assignment syntax, if the command line begins with "*=".
NOTES Memo 4 Optional free-form notes pertaining to this step of the pseudo-function.  (The Notes field can be removed altogether, if desired, because the program logic does not require it to be present.)  Used for annotation of the sample meta-file.
MODIDATE DateTime 8 Date and time of last modification to this record.  Use this for manual maintenance of the meta-file.  Also maintained automatically by Commander's CMDRM_AddFuncStep logic.  (The name of this field is actually determined by macro variables, FNAM_DTMOD and FNAM_DTMNQ defined in include file mdacomm.h, in order to support alternate global naming conventions.)

Meta-File Indexes

Index Name Expression Comments
DELETED DELETED( ) (for the benefit of VFP's Rushmore query optimization)
FUNCSEQ FUNCTIONID + STR(SEQ) This is the most useful ordering, by function id, by sequence number.  Logically used like a unique key, but uniqueness is not rigidly enforced.
FUNCTIONID FUNCTIONID (simple field index - for query optimization)
MODIDATE MODIDATE (simple field index - for query optimization)
SEQ SEQ (simple field index - for query optimization)

Special Literal String Assignment Syntax

The default interpretation of each step in a function definition, i.e. the CMDLINE field, is to treat it as a VFP command line, which is processed via VFP's &-macro expansion capability.  While this is an extremely powerful feature (unique to Visual FoxPro), it has certain limitations.  Commander also supports an alternate syntax in the CMDLINE field, for actions that reduce to assigning a literal string value to a name expression.  This special syntax is more efficient than &-macro expansion, and it also avoids some VFP limitations and inconveniences when dealing with very long strings, or strings containing special characters (like quotes and newlines).

For example, the following CMDLINE value:

x = "here is a literal character string value"

Can be reformulated in Commander's special literal string assignment syntax as:

*=x=*here is a literal character string value

The "*=" prefix (defined as macro CMDM_DLAS1 in include file commandr.h) tells Commander that this is a special case of literal string assignment.  The "=*" delimiter (defined as macro CMDM_DLAS2) marks the end of the name expression, in this case the variable x.  Everything that follows this delimiter is taken to be the character string value to be assigned to x, without surrounding quotes or any concerns about special characters, up to VFP's maximum memo field length.

The CMDRCLON Utility Function

Apart from the Commander class library there is a separate, but related utility program for cloning metafile-based function definitions.  This function has the following usage:

success = cmdrclon(fromid_arg, toid_arg, metafi_arg, outfil_arg)

with the following 2 - 4 arguments:

funcionid for the Commander meta-file records to be copied.  This function definition must exist, or cmdrclon() will gripe and fail.  If empty, use the current functionid from the currently selected area, if available.  The id of the function to be cloned must be non-blank.
(required) new functionid to be assigned to records cloned from the source.  The caller is responsible for specifying an unused function id, if this is what is desired (which will normally be the case).  This target function id must be non-blank and must differ from the source function id, unless a separate output file is specified.
optional path & filename of the Commander meta-file to be used, unless the source is determined by default because fromid_arg is blank.  Otherwise, if metafi_arg is omitted or empty, the default Commander meta-file is assumed, taken from the macro variable CMDM_FILE (defined in include file commandr.h).  The meta-file must exist, or this function gripes and fails.
optional output path & filename, into which records are to be copied.  If omitted or empty, use the input file as the destination for output.  If non-empty, but the target table doesn't yet exist, it is automatically created.

Commander Forum


 Top | Unframe 

Copyright 2000 - 2002, SpaceTime Systems