Macro evaluation–unary

 Macro evaluation--unary                         (Special)



     <cMacroVar> can be any character variable.  The period (.) is the
     macro terminator and indicates the end of the macro variable and
     distinguishes the macro variable from adjacent text in the statement.

     <cMacroExp> is a character expression enclosed in parentheses.  In
     this instance, the expression is evaluated first, and the macro
     operation is performed on the resulting character value.  This allows
     the contents of fields and array elements to be compiled and run.


     The macro operator in CA-Clipper is a special operator that allows
     runtime compilation of expressions and text substitution within strings.
     Whenever the macro operator (&) is encountered, the operand is submitted
     to a special runtime compiler (the macro compiler) that compiles
     expressions, but not statements or commands.

 Text Substitution

     Whenever a reference to a private or public macro variable, embedded in
     a character string, is encountered, the variable reference is replaced
     by the content of the macro variable.  For example,

     cMacro := "there"
     ? "Hello &cMacro"            // Result: Hello there

     If you specify a macro expression (e.g., &(cMacro1 + cMacro2)), and the
     macro variable is a local, static, field variable, or an array element,
     it is treated as literal text and not expanded.

Macro operator:nesting
 Compile and Run

     When a macro variable or expression specified within an expression is
     encountered, it is treated like an expression, with the macro symbol
     behaving as the compile and run operator.  If the macro is specified as
     a macro variable,

     cMacro := "DTOC(DATE())"
     ? &cMacro

     the macro compiler compiles, then executes the content of the macro
     variable.  The compiled code is then discarded.

     If you specify an expression enclosed in parentheses and prefaced by the
     macro operator (&),

     ? &(INDEXKEY(0))

     the expression is evaluated and the resulting character string is
     compiled and run as a macro variable.

     Using the macro operator, you can compile a character string containing
     a code block definition:

     bBlock := &("{ |exp| QOUT(exp) }")

     The run portion of the operation returns the code block as a value.  You
     may then use the code block by invoking it with the EVAL() function.
     This is especially significant in activations that involve extensive
     looping through user-defined conditions (operations that in earlier
     versions of CA-Clipper required macro expansion).  In those versions,
     the macro expression was compiled and run for each iteration of the
     loop.  With the combination of a macro expansion and a code block
     EVAL(), the compilation is performed once at compile time, and the
     EVAL() merely executes the code block each time through the loop:

     EVAL(bBlock, DATE())

     The time savings at runtime can be enormous.


     .  Command keywords: You cannot use the macro operator (&) to
        substitute or compile command keywords.  However, you can redefine
        command keywords by modifying the command definition in,
        overriding an existing command definition with a new definition using
        the #command directive, or redefining a command keyword using the
        #translate directive.  In any case, you may redefine a command
        keyword only at compile time, not at runtime.

     .  Command arguments: In prior versions of CA-Clipper as well as
        in other dialects, you could use macro variables as the arguments of
        commands requiring literal text values.  These included all file
        command arguments and SET commands with toggle arguments.  In these
        instances, you can now use an extended expression enclosed in
        parentheses in place of the literal argument.  For example,

        xcDatabase = "Invoices"
        USE &xcDatabase.

        can be replaced with:

        xcDatabase = "Invoices"
        USE (xcDatabase)

        It is important to use extended expressions if you are using local
        and static variables.  Generally, commands are preprocessed into
        function calls with command arguments translated into function
        arguments as valid CA-Clipper values.  File names in file commands,
        for instance, are stringified using the smart stringify result marker
        and passed as arguments to the functions that actually perform the
        desired actions.  If you specify a literal or macro value as the
        command argument, it is stringified.  If, however, the argument is an
        extended expression, it is written to the result text exactly as
        specified.  This example,

        #command RENAME <xcOld> TO <xcNew>;
              FRENAME( <(xcOld)>, <(xcNew)> )
        RENAME &xcOld TO &xcNew
        RENAME (xcOld) TO (xcNew)

        is written to the result text as this:

        FRENAME( "&xcOld", "&xcNew" )
        FRENAME( xcOld, xcNew )

        when preprocessed.  When the macro variables are stringified, the
        macro variable names are hidden in the string and not compiled.
        Later, at runtime, they are substituted into the string and passed as
        arguments to the FRENAME() function.  This precludes local and static
        macro variables since the names of the variables are not present at
        runtime to be substituted.  Public and private variables, however,
        behave as expected.

     .  Lists as arguments of commands:  The macro operator (&) will
        not fully substitute or compile a list as an argument of most
        commands.  In particular, these are commands where an argument list
        is preprocessed into an array or a code block.  Instances of this are
        arguments of the FIELDS clause and SET INDEX.  An exception is the
        SET COLOR command which preprocesses the list of colors into a single
        character string and passes it to the SETCOLOR() function.

        In any case, list arguments should always be specified as extended
        expressions with each list argument specified:

        LOCAL xcIndex := { "Ntx1", "Ntx2" }
        SET INDEX TO (xcIndex[1]), (xcIndex[2])

     .  Arrays: You can use the macro operator (&) with arrays and
        array elements.  However, because of the increased power of
        CA-Clipper arrays, you may find less need to use the macro operator
        (&) to  make variable references to arrays.  You can now assign array
        references to variables, return array references from user-defined
        functions, and nest array references within other arrays.  You may
        also create arrays by specifying literal arrays or using the ARRAY()

        You can, therefore, make references to arrays and array elements
        using both macro variables and macro expressions with the restriction
        that you cannot make the subscript references in a PRIVATE or PUBLIC
        statement.  Also, you cannot specify the macro operator (&) in a
        declaration statement, such as a LOCAL or STATIC statement.
        Attempting this will generate a fatal compiler error.

        This example references array elements using macro variables:

        cName := "aArray"
        nElements := 5
        cNameElement := "aArray[1]"
        PRIVATE &cName.[nElements]      // Creates "array" with 5
                                        // elements
        &cNameElement. := 100           // Assigns 100 to element 1
        &cName.[3] := "abc"             // Assigns "abc" to element 3

        You can successfully apply a macro operator (&) to an array element
        if the reference is made using a macro expression.  A macro variable
        reference, however, will generate a runtime error.  For example, the
        following lists the values of all fields of the current record:

        USE Customer NEW
        aStruc := DBSTRUCT()
        FOR nField := 1 TO LEN(aStruc)
           ? &(aStruc[nField, 1])

     .  Code blocks: You can apply the macro operator (&) to a macro
        variable or expression in a code block in most cases. There is a
        restriction when the macro variable or macro expression contains a
        declared variable.  A runtime error occurs if you specify a complex
        expression (an expression that contains an operator and one or more
        operands) that includes the macro operator (&) within a code block.

        This has important implications for the use of local and static
        variables in the conditional clauses of commands, since these clauses
        are blockified as they are written to the result text during
        preprocessing.  This applies to all FOR and WHILE clauses, the SET
        FILTER command, and the SET RELATION linking expression.  The general
        workaround is to gather the entire expression into a single macro
        variable then apply the macro operator (&) to the variable.

     .  Macro conditions: When using the macro operator (&) to specify
        conditional clauses of database commands such as FOR or WHILE
        clauses, there are some restrictions based on the expression's
        complexity and size:

        -  The maximum string size the macro compiler can process is 254

        -  There is a limit to the complexity of conditions (the more
           complex, the fewer the number of conditions you can specify).

     .  Procedures and functions: You can reference procedure and
        function calls using macro variables and expressions.  With DO, the
        macro variable reference to the procedure can be all or part of the
        procedure name.  With a call to a function (built-in or user-
        defined), the macro variable reference must include the function name
        and all of its arguments.

        In CA-Clipper, because of the added facility code blocks, all
        invocations of procedures and functions using the macro operator
        should be converted to the evaluation of code blocks.  This code

        cProc := "AcctsRpt"
        DO &cProc

        can be replaced with:

        bProc := &( "{ || AcctsRpt() }" )

        The advantage of a code block over a macro evaluation is that the
        result of the compilation of a string containing a code block can be
        saved and, therefore, need only be compiled once.  Macro evaluations
        compile each time they are referenced.

     .  References into overlays:  You must declare procedures and
        user-defined functions that are used in macro expressions and
        variables but not referenced elsewhere as EXTERNAL, or the linker
        will not include them into the executable (.EXE) file.

     .  TEXT...ENDTEXT:  Macro variables referenced within a
        TEXT...ENDTEXT construct are expanded.  Note that a field cannot be
        expanded, so you must first assign the field value to a memory
        variable then reference the memory variable as a macro variable
        within the TEXT...ENDTEXT.  For example:

        USE Customer NEW
        myVar := Customer->CustName
        This is text with a macro &myVar

     .  Nested macros:  The processing of macro variables and
        expressions in CA-Clipper permits nested macro definitions.  For
        example, after assigning a macro variable to another macro variable,
        the original macro variable can be expanded resulting in the
        expansion of the second macro variable and evaluation of its

        cOne = "&cTwo"             // expand cTwo
        cTwo = "cThree"            // yielding "cThree"
        cThree = "hello"
        ? &cOne                    // Result: "hello"

C5 Error Handling

C5 Error Handling Commands, Statements and Funtions

Statement :


Define a sequence of statements for a BREAK

    [BREAK [<exp>]]
    [RECOVER [USING <idVar>]]

Functions :

ALTD() :

Invoke the Clipper Debugger

ALTD( [ <nAction> ] ) --> NIL


Branch out of a BEGIN SEQUENCE…END construct

BREAK( <exp> ) --> NIL


Return the DOS error number

DOSERROR( [ <nNewOsCode> ] ) --> nOsCode


Post a code block to execute when a runtime error occurs

ERRORBLOCK( [ <bErrorHandler> ] ) --> bCurrentErrorHandler


Set the Clipper return code

ERRORLEVEL( [ <nNewReturnCode> ] ) --> nCurrentReturnCode


Determine if a network command has failed

NETERR( [ <lNewError> ] ) --> lError


Write a list of values to the standard error device

OUTERR( <exp list> ) --> NIL


Return the source line number of the current or previous activation

PROCLINE( [ <nActivation> ] ) --> nSourceLine


Return the name of the current or previous procedure or user-defined function

PROCNAME( [ <nActivation> ] ) --> cProcedureName

Error Class :

Provides objects containing information about runtime errors.

Description :

An Error object is a simple object that contains information pertaining to a runtime error. Error objects have no methods, only exported instance variables. When a runtime error occurs, CA-Clipper creates a new Error object and passes it as an argument to the error handler block specified with the ERRORBLOCK() function. Within the error handler, the Error object can then be queried to determine the nature of the error condition.

Error objects can also be returned to the RECOVER statement of a BEGIN SEQUENCE construct with a BREAK statement. Here, the error object can be queried for local error handling. For more detailed information and examples refer to the Error Handling Strategies chapter in the Programming and Utilities guide.

Class Function :

ErrorNew() :

Returns a new Error object.

ErrorNew() --> objError

Exported Instance Variables :

args (Assignable) :

An array of function or operator arguments.

Contains an array of the arguments supplied to an operator or function when an argument error occurs. For other types of errors, Error:args contains a NIL value.

canDefault (Assignable) :

Indicates whether or not default recovery is available.

Contains a logical value indicating whether the subsystem can perform default error recovery for the error condition. A value of true (.T.) indicates that default recovery is available. Availability of default handling and the actual default recovery strategy depends on the subsystem and the error condition. The minimum action is simply to ignore the error condition.

Default recovery is requested by returning false (.F.) from the error block invoked to handle the error. Note that Error:canDefault is never true (.T.) if Error:canSubstitute is true (.T.).

canRetry (Assignable) :

Indicates whether or not a retry is possible after an error.

Contains a logical value indicating whether the subsystem can retry the operation that caused the error condition. A value of true (.T.) indicates that a retry is possible. Retry may or may not be available, depending on the subsystem and the error condition.

Retry is requested by returning true (.T.) from the error block invoked to handle the error. Note that Error:canRetry never contains true (.T.) if Error:canSubstitute contains true (.T.).

canSubstitute (Assignable) :

Indicates if a new result can be substituted after an error

Contains a logical value indicating whether a new result can be substituted for the operation that produced the error condition. Argument errors and certain other simple errors allow the error handler to substitute a new result value for the failed operation. A value of true (.T.) means that substitution is possible.

The substitution is performed by returning the new result value from the code block invoked to handle the error. Note that Error:canSubstitute is never true (.T.) if either Error:canDefault or Error:canRetry is true (.T.).

cargo (Assignable) :

User-definable variable.

Contains a value of any data type unused by the Error system. It is provided as a user-definable slot, allowing arbitrary information to be attached to an Error object and retrieved later.

description (Assignable) :

Character description of the error condition.

Contains a character string that describes the error condition. A zero-length string indicates that the subsystem does not provide a printable description for the error. If Error:genCode is not zero, a printable description is always available.

filename (Assignable) :

Name of the file associated with the error

Contains a character value representing the name originally used to open the file associated with the error condition. A zero-length string indicates either that the error condition is not associated with a particular file or that the subsystem does not retain filename information.

genCode (Assignable) :

Error code number.

Contains an integer numeric value representing a CA-Clipper generic error code. Generic error codes allow default handling of similar errors from different subsystems. A value of zero indicates that the error condition is specific to the subsystem and does not correspond to any of the generic error codes. The header file,, provides a set of manifest constants for generic error codes.

operation (Assignable) :

Character description of the failed operation.

Contains a character string that describes the operation being attempted when the error occurred. For operators and functions, Error:operation contains the name of the operator or function. For undefined variables or functions, it contains the name of the variable or function. A zero-length string indicates that the subsystem does not provide a printable description of the operation.

osCode (Assignable) :

Operating system error code number

Contains an integer numeric value representing the operating system error code associated with the error condition. A value of zero indicates that the error condition was not caused by an error from the operating system. When Error:osCode is set to a value other than zero DOSERROR() is updated with the same value.

Error:osCode properly reflects the DOS extended error code for file errors. This allows proper distinction between errors which result from sharing violations (e.g., opening EXCLUSIVE when another process has already opened the file) and access violations (e.g., opening read/write when the file is marked read-only).

For a list of DOS error codes please look at here 

severity (Assignable) :

Indicates error severity

Contains a numeric value indicating the severity of the error condition. Four standard values are defined in

Error:severity Values
------------------------------------------------------------        Meaning
ES_WHOCARES     The condition does not represent a failure;
                the error is informational.
ES_WARNING      The condition does not prevent further
                operations, but may result in a more serious 
                error later. 
ES_ERROR        The condition prevents further operations without 
                corrective action of some kind. 
ES_CATASTROPHIC The condition requires immediate termination 
                of the application.

Note that the Clipper runtime support code only generates errors with severities of ES_WARNING or ES_ERROR

subCode (Assignable) :

Subsystem-specific error code number.

Contains an integer numeric value representing a subsystem-specific error code. A value of zero indicates that the subsystem does not assign any particular number to the error condition.

subSystem (Assignable) :

Character description of the subsystem generating the error.

Contains a character string representing the name of the subsystem generating the error. For errors with basic CA-Clipper operators and functions, the subsystem name “BASE” is given. For errors generated by a database driver, Error:subSystem contains the name of the database driver

tries (Assignable) :

Number of times the failed operation has been attempted.

Contains an integer numeric value representing the number of times the failed operation has been attempted. When Error:canRetry is true (.T.), Error:tries can be used to limit the number of retry attempts. A value of zero indicates that the subsystem does not track the number of times the operation has been tried.

Examples :

. This example demonstrates how a file open operation might be handled in an error handler replicating the default CA-Clipper behavior. When, for example, an attempt to open a database file with a USE command fails, control returns to the statement following the offending command:

#include ""
#command RETRY => RETURN (.T.) // Retry operation
#command RESUME => RETURN (.F.) // Default recovery
FUNCTION MyError( objError )
   // Handle file open error
   IF objError:genCode == EG_OPEN .AND.;
      objError:canDefault .AND.;
  . <other error statements>

. This example retries an operation within an error handler a specified number of times:

 #include ""
 #command RETRY => RETURN (.T.) // Retry operation
 #command RESUME => RETURN (.F.) // Default recovery
FUNCTION MyError( objError )

 // Handle printer not ready error
 IF objError:genCode == EG_PRINT .AND.;
    objError:canRetry .AND.;
    objError:tries < 25

 . <other error statements>

. This code fragment returns an error object from an error handler to the RECOVER statement for further processing:

LOCAL objLocal, bLastHandler
// Save current and set new error handler
bLastHandler := ERRORBLOCK({ |objErr| ;
MyHandler(objErr, .T.)})
   . <operation that might fail>
   . <send messages to objLocal and handle the error>
// Restore previous error handler
ERRORBLOCK( bLastHandler )
FUNCTION MyHandler( objError, lLocalHandler )

    // Handle locally returning the error object
    IF lLocalHandler
       BREAK objError
    . <other statements to handle the error>

Files: Header file is, default error handler is in Errorsys.prg.