next
previous
top
last
contents
aiuto
indice analitico
tome
part
TXT
HTML
PDF
pdf
gdoc
P4
 Clean the Clipper 5.2 
A different way to program using Clipper 5.2 without commands, that is, without the file STD.CH.(1)
Clipper 5.2,(2) as the xBase tradition imposes, is not an ordered, clear, simple programming language. The question is: which is the right way to write a Clipper program? If the intention is not to make a xBase program, but a Clipper program, maybe it can be decided that it is better to use Clipper without commands.
 Step 1: try to compile with the /P parameter 
Supposing to compile the file TEST.PRG this way:
C:\>CLIPPER TEST.PRG /P[Enter]
It generates a preprocessed output file (test.PPO), that is a source file without comments, where commands are translated into real Clipper instructions. That is, all the #COMMAND substitution are executed and the translation is sent to the .PPO file. It may be difficult to read this file the first time.
 Step 2: understand well the use of code blocks 
The code block is a small piece of executable program code that can be stored inside a variable, or can be used as a literal constant. The good of it, is that pieces of code may be sent to functions.
A code block is something like a little user defined function where only a sequence of expressions (functions and/or assignments) may appear: no loops, no conditional structures.
A code block may receive arguments and return a value after execution, just like a function. The syntax is the following, where curly brackets are part of the code block:
{ | [argument_list] | exp_list }
 | 
That is: the argument_list is optional; the exp_list may contain one or more expressions separated with a comma.
For example, calling the following code block will give the string ``hello world'' as result.
The following code block requires a numeric argument and returns the number passed as argument incremented:
The following code block requires two numeric arguments and returns the sum of the two square radix:
{ | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
 |  
 
 
 | 
But code blocks may contain more expressions and the result of the execution of the code block is the result of the last expression. The following code block executes in sequence some functions and gives ``hello world'' as a result.
{ | a, b | functionOne(a), functionTwo(b), "hello world" }
 |  
 
 
 | 
To start the execution of a code block a function is used: EVAL(). For example, a code block is assigned to a variable and then executed.
B := { || "hello world" }
EVAL( B ) == "hello world"
 |  
 
 
 | 
Another example with one parameter.
B := { | n | n+1 }
EVAL( B, 1 ) == 2
 |  
 
 
 | 
Another example with two parameters.
B := { | nFirst, nSecond | SQRT(nFirst) + SQRT(nSecond) }
EVAL( B, 2, 4 ) == 20
 |  
 
 
 | 
And so on.
 Step 3: understand the object programming 
Clipper 5.2 do not permit to create objects, but it gives some good objects to use: GET and TBROWSE. Before starting to clean programming from commands, it is necessary to understand how to use well the Clipper objects.
 Classes and methods 
A class defines the structure of a ``black box'', that is a data container; a method is an action to make on a piece of data contained inside the black box. There is no way to reach the data contained inside the black box without a method.
The black box can be called object.
The methods may be seen as they where special functions which interact with a specific piece of data contained inside the object.
 Class definition 
Supposing that Clipper permits to define classes (unluckily only predefined classes can be used), the hypothetical syntax could be:
CLASS ClassName [FROM ParentClass]
    VAR Var1 [,Var2[,...VarN]]
    METHOD {method_definition_1} [, ...{method_definition_n} ]
ENDCLASS
 | 
This way, the class defines a group of variables and a group of method to use with these variables.
 Object creation 
The presence of classes permits to create objects: the black boxes.
Variable_name := ClassName
 
 | 
This way, a variable contains (is) an object. Please note that inside Clipper, an object may be generated also from a function, that is, a function can return an object. This way the example can be:
Variable_name := classfunction( ... )
 
 | 
The next problem is to handle this object.
 Instantiating an object 
As already stated before, methods are used to handle data contained inside an object. This is said to be instantiating an object. Clipper permits also to handle directly (apparently without methods) some variables contained inside objects. These are called ``Exported Instance Variables''. So, an object can be instantiated this way:
object:exported_instance_variable := new_value
 
 | 
An exported instance variable may be read and/or modified depending on the allowed access to it; a method, inside Clipper, is something like a function with or without parameters (if parameters are present, these are usually used to modify data inside the object), that normally returns a value.
 The ``send'' symbol 
To instantiate an object or simply to access an exported instance variable, the ``send'' symbol (colon) is used.
 More about objects 
If this is not enough to understand objects inside Clipper, the following document should be read:
Peter M. Freese, o:Clip - An Object Oriented Extension to Clipper 5.01 1991, CyberSoft
ftp://ftp.simtel.net/pub/simtelnet/msdos/clipper/oclip.zip
 Step 4: understand the get object 
What happens with a command like the following:
A get object is created containing all the necessary information for editing the variable Var at the screen position nTop, nLeft. After that, this get object is added to a get objects array (usually called GetList). The get objects array will contain all the get objects used during a READ.
So, what happens when a READ command is encountered. The get objects array (GetList) is read and the editing of all get objects is executed. After that, the get objects array is cleared.
This method hides what Clipper really makes. The suggestion here is to create a GET() function that will substitute the @...GET command and to use the READMODAL() function to read the get objects array. Here is an example of it:
function GET( aoGet, nRow, nCol, bVar, cGetPicture,
              cColorString, bPreValid, bPostValid )
    // declare a local get object
    local oGet
    // create the get object using the function GETENV()
    oGet := GETENV( nRow, nCol, bVar, NIL, cGetPicture, cGetColor )
    // send to the get object the pre-validation condition code block (WHEN)
    oGet:preBlock  := bPreValid
    // send to the get object the post-validation condition code block (VALID)
    oGet:postBlock := bPostValid
    // display the get on the screen using the display() method
    oGet:display()
    // add the get object to the get objects array
    AADD( aoGet, oGet )
    return NIL
 |  
 
 
 | 
- 
aoGet is the get objects array (so here is explicitly passed). This get objects array is modified (grown) and there is no need to return it as inside Clipper, arrays are always passed by reference to functions.
 
- 
nRow and nCol are the screen coordinates where the get field should appear at, as it works with the @...GET command.
 
- 
bVar is a special code block that permits the editing of a variable. If the variable Var is to be edited, the code block is:
{ |x| iif( pcount() > 0, Var := x, Var }
 |  
 
 
 | 
 
- 
cGetPicture is the picture to use: same as the @...GET command.
 
- 
cColorString is the color string to use: same as the @...GET command.
 
- 
bPreValid is a code block containing the condition that must be valid before the cursor can reach this get field. It is equivalent to the WHEN condition used with the @...GET command, but it must be converted into a code block. For example, if the condition is A > B, the code block is {|| A > B}
 
- 
bPostValid is a code block containing the condition that must be valid before the cursor can leave this get field. It is equivalent to the VALID condition used with the @...GET command, but it must be converted into a code block. For example, if the condition is A > B, the code block is {|| A > B}
 
If there is a get function like the above one, screen I/O may be performed like the following example:
function do_some_editing()
    // define a variable to use as a get objects array
    // and initialise it to the empty array
    local aoGet := {}
    ...
    ...
    // add a new get object to the get objects array
    get(;
        aoGet,;
        10, 10,;
        { |x| iif( pcount() > 0, myVariable := x, myVariable },;
        "@s30@",;
        "gb+/b,  n/w,    n,  n,  w/n",;
        { || .T. },;
        { || .T. };
    )
    ...
    // read the get objects array
    readmodal( aoGet )
    // clear the get objects array
    aoGet := {}
    ...
    return ...
 |  
 
 
 | 
If the function GET() is not liked, the above I/O may be done as it follows:
function do_some_editing()
    // define a variable to use as a get object
    local aoGet
    // define a variable to use as a get objects array
    // and initialise it to the empty array
    local aoGet := {}
    ...
    ...
    // add a new get object to the get objects array
    oGet :=;
        GETENV(;
            10, 10,;
            { |x| iif( pcount() > 0, myVariable := x, myVariable },;
            NIL,;
            "@s30@",;
            "gb+/b,  n/w,    n,  n,  w/n",;
        )
    AADD( aoGet, oGet )
    ...
    // read the get objects array
    readmodal( aoGet )
    // clear the get objects array
    aoGet := {}
    ...
    return ...
 |  
 
 
 | 
 Step 5: trying to stop using commands 
To stop using commands, it is important to understand how commands are or may be translated into functions. Sometimes Clipper uses some undocumented functions: these are functions that start with a underline.
 ?/?? 
 @...BOX 
@ nTop, nLeft, nBottom, nRight BOX cnBoxString [COLOR cColorString]
 
 | 
dispbox(nTop, nLeft, nBottom, nRight, [cnBoxString], [cColorString])
 
 | 
 @...GET 
@ nTop, nLeft GET Var [PICTURE cGetPicture] [COLOR cColorString] \   \[WHEN lPreExpression] [VALID lPostExpression]
 
 | 
aadd( GetList, _GET_( Var, "Var", cGetPicture, [{|| lPostExpression}],\   \[{|| lPreExpression}] ):display() ) atail(GetList):colorDisp(cColorString)
 | 
This is the command substitution made automatically, but it shouldn't be used to make clean programs. The step 4 (u0.1) suggests to create a get function.
 @...SAY 
@ nTop, nLeft SAY exp [COLOR cColorString]
 
 | 
devout(exp [, cColorString])
 
 | 
@ nTop, nLeft SAY exp PICTURE cSayPicture [COLOR cColorString]
 
 | 
devoutpic(exp, cSayPicture, [cColorString])
 
 | 
 @...TO 
@ nTop, nLeft TO nBottom, nRight DOUBLE [COLOR cColorString]
 
 | 
dispbox(nTop, nLeft, nBottom, nRight, 2 [,cColorString])
 
 | 
@ nTop, nLeft TO nBottom, nRight [COLOR cColorString]
 
 | 
dispbox(nTop, nLeft, nBottom, nRight, 1 [,cColorString])
 
 | 
@ nTop, nLeft CLEAR [TO nBottom, nRight]
 
 | 
scroll([nTop], [nLeft], [nBottom, nRight])
 
 | 
 APPEND 
 APPEND FROM 
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition]\   \[FOR lCondition] [VIA xcDriver]
 
 | 
__dbApp( cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords],\   \[nRecord], [lRest], [cDriver] )
 
 | 
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition] [FOR lCondition]\   \DELIMITED xcDelimiter
 
 | 
__dbDelim( .f., cFileName, [cDelimiter], [acFields], [bForCondition], \   \[bWhileCondition], [nNextRecords], [nRecord], [lRest] )
 
 | 
APPEND FROM xcFile [FIELDS idField_list] [scope] [WHILE lCondition]\   \[FOR lCondition] SDF
 
 | 
__dbSDF( .f., cFileName, [acFields], [bForCondition], [bWhileCondition], \   \[nNextRecords], [nRecord], [lRest] )
 
 | 
 CLEAR 
 CLOSE 
idAlias->( dbCloseArea() )
 
 | 
 COMMIT 
 CONTINUE 
 COPY 
COPY FILE xcSourceFile TO xcTargetFile|xcDevice
 
 | 
__CopyFile( cSourceFile, cTargetFile|cDevice )
 
 | 
COPY STRUCTURE [FIELDS idField_list] TO xcDatabase
 
 | 
__dbCopyStruct( cDatabase, [acFields] )
 
 | 
COPY STRUCTURE EXTENDED TO xcExtendedDatabase
 
 | 
__dbCopyXStruct( cExtendedDatabase )
 
 | 
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition]\   \[FOR lCondition] [VIA xcDriver]
 
 | 
__dbCopy( cFileName, [acFields], [bForCondition], [bWhileCondition], [nNextRecords],\   \[nRecord], [lRest], [cDriver] )
 
 | 
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition] [FOR lCondition]\   \DELIMITED xcDelimiter
 
 | 
__dbDelim( .t., cFileName, [cDelimiter], [acFields], [bForCondition], \   \[bWhileCondition], [nNextRecords], [nRecord], [lRest] )
 
 | 
COPY TO xcFile [FIELDS idField_list] [scope] [WHILE lCondition]\   \[FOR lCondition] SDF
 
 | 
__dbSDF( .t., cFileName, [acFields], [bForCondition], [bWhileCondition], \   \[nNextRecords], [nRecord], [lRest] )
 
 | 
 COUNT 
COUNT TO idVar [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]\   \[RECORD nRecord] [REST] [ALL]
 
 | 
dbeval( {||idVar:=idVar+1}, {||lForCondition}, {||lWhileCondition},\   \nNextRecords, nRecord, lRest )
 | 
 CREATE 
CREATE xcDatabase FROM xcExtendedDatabase [NEW] [ALIAS cAlias] [VIA cDriver]
 
 | 
__dbCreate( cDatabase, cExtendedDatabase, [cDriver], [lNew], [cAlias] )
 
 | 
 DEFAULT 
DEFAULT xVar TO xDefaultValue
 
 | 
if xVar == NIL
  xVar := xDefaultValue
end
 
 | 
 DELETE 
DELETE [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]\   \[RECORD nRecord] [REST] [ALL]
 
 | 
dbeval( {||dbDelete()}, {||lForCondition}, {||lWhileCondition},\   \nNextRecords, nRecord, lRest )
 | 
 EJECT 
 ERASE 
 FIND 
 GO 
 INDEX ON 
INDEX ON expKey TO xcIndexName [UNIQUE] [FOR lForCondition]\   \[WHILE lWhileCondition] [[EVAL lEvalCondition] [EVERY nRecords]] \   \[ASCENDING|DESCENDING]
 
 | 
ordCondSet( [cForCondition], [bForCondition], , [bWhileCondition],\   \[bEvalCondition], [nRecords], RECNO(), , , , lDescending )
 
 | 
ordCreate( cIndexName, , cExpKey, bExpKey, lUnique )
 
 | 
 JOIN 
JOIN WITH xcAlias TO xcDatabase [FOR lCondition] [FIELDS idField_list]
 
 | 
__dbJoin( cAlias, cDatabase, [acFields], [bForCondition] )
 
 | 
 KEYBOARD 
__Keyboard( [cString] ) --> NIL
 
 | 
 LABEL FORM 
LABEL FORM xcLabel [TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]\   \[WHILE lCondition] [FOR lCondition] [SAMPLE]
 
 | 
__LabelForm( cLabel, [lToPrinter], [cFile], [lNoConsole],\   \[bForCondition], [bWhileCondition], [nNextRecords], [nRecord],\   \[lRest], [lSample] )
 
 | 
 LIST 
LIST exp_list [TO PRINTER] [TO FILE xcFile] [scope]\   \[WHILE lCondition] [FOR lCondition] [OFF]
 
 | 
__dbList( [lToDisplay], abListColumns, [lAll], [bForCondition], [bWhileCondition],\   \[nNextRecords], [nRecord], [lRest], [lToPrinter], [cFileName] )
 
 | 
 LOCATE 
LOCATE [scope] FOR lCondition [WHILE lCondition]
 
 | 
__dbLocate( [bForCondition], [bWhileCondition], [nNextRecords], [nRecord], [lRest] )
 
 | 
 PACK 
 QUIT 
 READ 
 RECALL 
RECALL [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]\   \[RECORD nRecord] [REST] [ALL]
 
 | 
dbeval( {||dbRecall()}, {||lForCondition}, {||lWhileCondition},\   \nNextRecords, nRecord, lRest )
 | 
 REINDEX 
REINDEX [EVAL lEvalCondition] [EVERY nRecords]
 
 | 
ordCondSet(, , , , [bEvalCondition], [nRecords], , , , , , , )
 
 | 
 RELEASE 
__MXRelease( "idMemvar" )
 
 | 
RELEASE ALL LIKE skeleton
 
 | 
__MRelease( "skeleton", .t. )
 
 | 
RELEASE ALL EXCEPT skeleton
 
 | 
__MRelease( "skeleton", .F. )
 
 | 
 RENAME 
RENAME xcOldFile TO xcNewFile
 
 | 
frename( cOldFile, cNewFile )
 
 | 
 REPLACE 
REPLACE idField1 WITH exp1 [, idField2 WITH exp2...]\   \[FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]\   \[RECORD nRecord] [REST] [ALL]
 
 | 
dbeval( {|| idField1 := exp1 [, idField2 := exp2...]},\   \{||lForCondition}, {||lWhileCondition}, nNextRecords,\   \nRecord, lRest )
 | 
REPLACE idField1 WITH exp1
 
 | 
 REPORT FORM 
REPORT FORM xcReport [TO PRINTER] [TO FILE xcFile] [NOCONSOLE] [scope]\   \[WHILE lCondition] [FOR lCondition] [PLAIN | HEADING cHeading] [NOEJECT] \   \[SUMMARY]
 
 | 
__ReportForm( cForm, [lToPrinter], [cToFile], [lNoConsole], [bForCondition], \   \[bWhileCondition], [nNext], [nRecord], [lRest], [lPlain], [cbHeading], \   \[lBeforeEject], [lSummary] )
 
 | 
 RESTORE 
RESTORE SCREEN FROM cScreen
 
 | 
restscreen( 0, 0, Maxrow(), Maxcol(), cScreen )
 
 | 
 RESTORE FROM 
RESTORE FROM xcMemFile [ADDITIVE]
 
 | 
__MRestore( cMemFileName, [lAdditive] )
 
 | 
 RUN 
 SAVE SCREEN TO 
cScreen := savescreen( 0, 0, maxrow(), maxcol() )
 
 | 
 SAVE TO 
SAVE TO xcMemFile [ALL [LIKE|EXCEPT skeleton]]
 
 | 
_MSave( cMemFileName, [cSkeleton], [lLike] )
 
 | 
 SEEK 
SEEK expSearch [SOFTSEEK]
 
 | 
dbSeek( expSearch [, lSoftSeek] )
 
 | 
 SELECT 
SELECT xnWorkArea | idAlias
 
 | 
dbSelectArea( nWorkArea | cIdAlias )
 
 | 
 SET 
Most of the SET... commands are translated into the SET() function that distinguishes different modes depending on a number. As this number is difficult to handle during programming (essentially because it is difficult to remember the meaning of it), Clipper offers the SET.CH include file that helps with manifest constants.
#define _SET_EXACT         1
#define _SET_FIXED         2
#define _SET_DECIMALS      3
#define _SET_DATEFORMAT    4
#define _SET_EPOCH         5
#define _SET_PATH          6
#define _SET_DEFAULT       7
#define _SET_EXCLUSIVE     8
#define _SET_SOFTSEEK      9
#define _SET_UNIQUE       10
#define _SET_DELETED      11
#define _SET_CANCEL       12
#define _SET_DEBUG        13
#define _SET_TYPEAHEAD    14
#define _SET_COLOR        15
#define _SET_CURSOR       16
#define _SET_CONSOLE      17
#define _SET_ALTERNATE    18
#define _SET_ALTFILE      19
#define _SET_DEVICE       20
#define _SET_EXTRA        21
#define _SET_EXTRAFILE    22
#define _SET_PRINTER      23
#define _SET_PRINTFILE    24
#define _SET_MARGIN       25
#define _SET_BELL         26
#define _SET_CONFIRM      27
#define _SET_ESCAPE       28
#define _SET_INSERT       29
#define _SET_EXIT         30
#define _SET_INTENSITY    31
#define _SET_SCOREBOARD   32
#define _SET_DELIMITERS   33
#define _SET_DELIMCHARS   34
#define _SET_WRAP         35
#define _SET_MESSAGE      36
#define _SET_MCENTER      37
#define _SET_SCROLLBREAK  38
 
 |  
 
 
 | 
SET ALTERNATE TO xcFile [ADDITIVE]
 
 | 
Set( _SET_ALTFILE, cFile, lAdditive )
 
 | 
SET ALTERNATE ON | OFF | xlToggle
 
 | 
Set( _SET_ALTERNATE, "ON" | "OFF" | lToggle )
 
 | 
SET BELL ON | OFF | xlToggle
 
 | 
Set( _SET_BELL, "ON" | "OFF" | lToggle )
 
 | 
SET COLOR | COLOUR TO (cColorString)
 
 | 
SET CONFIRM ON | OFF | xlToggle
 
 | 
Set( _SET_CONFIRM, "ON" | "OFF" | lToggle )
 
 | 
SET CONSOLE ON | OFF | xlToggle
 
 | 
Set( _SET_CONSOLE, "ON" | "OFF" | lToggle )
 
 | 
SET CURSOR ON | OFF | xlToggle
 
 | 
SetCursor( 1 | 0 | iif( lToggle, 1, 0 ) )
 
 | 
SET DATE FORMAT [TO] cDateFormat
 
 | 
Set( _SET_DATEFORMAT, cDateFormat )
 
 | 
SET DECIMALS TO nDecimals
 
 | 
Set( _SET_DECIMALS, nDecimals )
 
 | 
SET DEFAULT TO xcPathspec
 
 | 
Set( _SET_DEFAULT, cPathspec )
 
 | 
SET DELETED ON | OFF | xlToggle
 
 | 
Set( _SET_DELETED, "ON" | "OFF" | lToggle )
 
 | 
SET DELIMITERS ON | OFF | xlToggle
 
 | 
Set( _SET_DELIMITERS, "ON" | "OFF" | lToggle )
 
 | 
SET DELIMITERS TO [DEFAULT]
 
 | 
Set( _SET_DELIMCHARS, "::" )
 
 | 
SET DELIMITERS TO cDelimiters
 
 | 
Set( _SET_DELIMCHARS, cDelimiters )
 
 | 
SET DEVICE TO SCREEN | PRINTER
 
 | 
Set( _SET_DEVICE, "SCREEN" | "PRINTER" )
 
 | 
SET ESCAPE ON | OFF | xlToggle
 
 | 
Set( _SET_ESCAPE, "ON" | "OFF" | lToggle )
 
 | 
SET EXACT ON | OFF | xlToggle
 
 | 
Set( _SET_EXACT, "ON" | "OFF" | lToggle )
 
 | 
SET EXCLUSIVE ON | OFF | xlToggle
 
 | 
Set( _SET_EXCLUSIVE, "ON" | "OFF" | lToggle )
 
 | 
dbsetfilter( bCondition, cCondition )
 
 | 
SET FIXED ON | OFF | xlToggle
 
 | 
Set( _SET_FIXED, "ON" | "OFF" | lToggle )
 
 | 
SET FUNCTION nFunctionKey TO cString
 
 | 
__SetFunction( nFunctionKey, cString )
 
 | 
SET INDEX TO [xcIndex [, xcIndex1... ] ]
 
 | 
ordListAdd( cIndex )
ordListAdd( cIndex1 )
...
 
 | 
SET INTENSITY ON | OFF | xlToggle
 
 | 
Set( _SET_INTENSITY, "ON" | "OFF" | lToggle )
 
 | 
SetKey( nInkeyCode, NIL )
 
 | 
SET KEY nInkeyCode TO [idProcedure]
 
 | 
SetKey( nInkeyCode, { |p, l, v| idProcedure(p, l, v)} )
 | 
SET MARGIN TO [nPageOffset]
 
 | 
Set( _SET_MARGIN, nPageOffset )
 
 | 
SET MESSAGE TO [nRow [CENTER | CENTRE]]
 
 | 
Set( _SET_MESSAGE, nRow )
 
 | 
Set( _SET_MCENTER, lCenter )
 
 | 
SET PATH TO [xcPathspec [, cPathspec1... ] ]
 
 | 
Set( _SET_PATH, cPathspec [, cPathspec1... ] )
 
 | 
SET PRINTER ON | OFF | xlToggle
 
 | 
Set( _SET_PRINTER, "ON" | "OFF" | lToggle )
 
 | 
Set( _SET_PRINTFILE, "" )
 
 | 
SET PRINTER TO [xcDevice|xcFile [ADDITIVE]]
 
 | 
Set( _SET_PRINTFILE, cDevice|cFile, lAdditive )
 
 | 
SET RELATION TO [expKey1 INTO xcAlias1] [, [TO] expKey2 INTO xcAlias2...]
 
 | 
dbSetRelation( cAlias1, {||expKey1}, ["expKey1"] )
 | 
dbSetRelation( cAlias2, {||expKey2}, ["expKey1"] )
 | 
SET RELATION TO [expKey1 INTO xcAlias1]\   \[, [TO] expKey2 INTO xcAlias2...] ADDITIVE
 
 | 
dbSetRelation( cAlias1, {||expKey1}, ["expKey1"] )
 | 
dbSetRelation( cAlias2, {||expKey2}, ["expKey1"] )
 | 
SET SCOREBOARD ON | OFF | xlToggle
 
 | 
Set( _SET_SCOREBOARD, "ON" | "OFF" | lToggle )
 
 | 
SET SOFTSEEK ON | OFF | xlToggle
 
 | 
Set( _SET_SOFTSEEK, "ON" | "OFF" | lToggle )
 
 | 
SET TYPEAHEAD TO nKeyboardSise
 
 | 
Set( _SET_TYPEAHEAD, nKeyboardSise )
 
 | 
SET UNIQUE ON | OFF | xlToggle
 
 | 
Set( _SET_UNIQUE, "ON" | "OFF" | lToggle )
 
 | 
SET WRAP ON | OFF | xlToggle
 
 | 
Set( _SET_WRAP, "ON" | "OFF" | lToggle )
 
 | 
 SKIP 
SKIP [nRecords] [ALIAS idAlias|nWorkArea]
 
 | 
[idAlias|nWorkArea -> ]( dbSkip([nRecords]) )
 
 | 
 SORT 
SORT TO xcDatabase ON idField1 [/[A|D][C]] [, idField2 [/[A|D][C]] ...]\   \[scope] [WHILE lCondition] [FOR lCondition]
 
 | 
__dbSort( cDatabase, [acFields], [bForCondition], [bWhileCondition],\   \[nNextRecords], [nRecord], [lRest] )
 
 | 
 STORE 
 SUM 
SUM nExp1 [, nExp2...] TO idVar1 [, idVar2...] [FOR lForCondition]\   \[WHILE lWhileCondition] [NEXT nNextRecords] [RECORD nRecord] [REST] [ALL]
 
 | 
dbeval( {||idVar1:=idVar1+nExp1 [, idVar2:=idVar2+nExp2...] },\   \{||lForCondition}, {||lWhileCondition}, nNextRecords, nRecord, lRest )
 | 
 TOTAL ON 
TOTAL ON expKey [FIELDS idField_list] TO xcDatabase [scope]\   \[WHILE lCondition] [FOR lCondition]
 
 | 
__dbTotal( cDatabase, bKey, [acFields], [bForCondition], [bWhileCondition],\   \[nNextRecords], [nRecord], [lRest] )
 
 | 
 UNLOCK 
 UPDATE FROM 
UPDATE FROM xcAlias ON expKey [RANDOM] REPLACE idField1\   \WITH exp [, idField2 WITH exp ...]
 
 | 
__dbUpdate( cAlias, bKey, [lRandom], [bReplacement] )
 
 | 
Example:
__dbUpdate( "INVOICE", {|| LAST}, .T.,; {|| FIELD->TOTAL1 := \   \INVOICE->SUM1,; FIELD->TOTAL2 := INVOICE->SUM2 } )
 |  
 
 
 | 
 USE 
USE [xcDatabase]\   \[INDEX xcIndex1 [, xcIndex2...] [ALIAS xcAlias] [EXCLUSIVE|SHARED] [NEW] \   \[READONLY] [VIA cDriver]]
 
 | 
dbUseArea( [lNewArea], [cDriver], cDatabase, [cAlias], [lShared], [lReadOnly] )
 
 | 
 ZAP 
 Step 6: free yourself from STD.CH - /U 
Now that no command is used, the standard include file STD.CH is no more necessary. Clipper uses STD.CH automatically, unless specified differently. Just compile this way:
C:>CLIPPER TEST.PRG /U[Enter]
 Step 7: take control over all include files 
Clipper comes with so many include files (*.CH). To avoid confusion, a single STANDARD.CH file containing all what is needed for the application may be prepared. At least, it is necessary the following.
*=================================================================
* DISPBOX()
*=================================================================
* Single-line box
#define BOX_SINGLE;
    (;
        CHR(218) +;
        CHR(196) +;
        CHR(191) +;
        CHR(179) +;
        CHR(217) +;
        CHR(196) +;
        CHR(192) +;
        CHR(179);
    )
* Double-line box
#define BOX_DOUBLE;
    (;
        CHR(201) +;
        CHR(205) +;
        CHR(187) +;
        CHR(186) +;
        CHR(188) +;
        CHR(205) +;
        CHR(200) +;
        CHR(186);
    )
* Single-line top, double-line sides
#define BOX_SINGLE_DOUBLE;
    (;
        CHR(214) +;
        CHR(196) +;
        CHR(183) +;
        CHR(186) +;
        CHR(189) +;
        CHR(196) +;
        CHR(211) +;
        CHR(186);
    )
* Double-line top, single-line sides
#define BOX_DOUBLE_SINGLE;
    (;
        CHR(213) +;
        CHR(205) +;
        CHR(184) +;
        CHR(179) +;
        CHR(190) +;
        CHR(205) +;
        CHR(212) +;
        CHR(179);
    )
*=================================================================
* ERRORS
*=================================================================
* Severity levels (e:severity)
#define ERROR_SEVERITY_WHOCARES        0
#define ERROR_SEVERITY_WARNING         1
#define ERROR_SEVERITY_ERROR           2
#define ERROR_SEVERITY_CATASTROPHIC    3
* Generic error codes (e:genCode)
#define ERROR_GENERIC_ARG             1
#define ERROR_GENERIC_BOUND           2
#define ERROR_GENERIC_STROVERFLOW     3
#define ERROR_GENERIC_NUMOVERFLOW     4
#define ERROR_GENERIC_ZERODIV         5
#define ERROR_GENERIC_NUMERR          6
#define ERROR_GENERIC_SYNTAX          7
#define ERROR_GENERIC_COMPLEXITY      8
#define ERROR_GENERIC_MEM            11
#define ERROR_GENERIC_NOFUNC         12
#define ERROR_GENERIC_NOMETHOD       13
#define ERROR_GENERIC_NOVAR          14
#define ERROR_GENERIC_NOALIAS        15
#define ERROR_GENERIC_NOVARMETHOD    16
#define ERROR_GENERIC_BADALIAS       17
#define ERROR_GENERIC_DUPALIAS       18
#define ERROR_GENERIC_CREATE         20
#define ERROR_GENERIC_OPEN           21
#define ERROR_GENERIC_CLOSE          22
#define ERROR_GENERIC_READ           23
#define ERROR_GENERIC_WRITE          24
#define ERROR_GENERIC_PRINT          25
#define ERROR_GENERIC_UNSUPPORTED    30
#define ERROR_GENERIC_LIMIT          31
#define ERROR_GENERIC_CORRUPTION     32
#define ERROR_GENERIC_DATATYPE       33
#define ERROR_GENERIC_DATAWIDTH      34
#define ERROR_GENERIC_NOTABLE        35
#define ERROR_GENERIC_NOORDER        36
#define ERROR_GENERIC_SHARED         37
#define ERROR_GENERIC_UNLOCKED       38
#define ERROR_GENERIC_READONLY       39
#define ERROR_GENERIC_APPENDLOCK     40
#define ERROR_GENERIC_LOCK           41
*=================================================================
* INKEY()
*=================================================================
#define K_UP                5   //   Up arrow, Ctrl-E
#define K_DOWN             24   //   Down arrow, Ctrl-X
#define K_LEFT             19   //   Left arrow, Ctrl-S
#define K_RIGHT             4   //   Right arrow, Ctrl-D
#define K_HOME              1   //   Home, Ctrl-A
#define K_END               6   //   End, Ctrl-F
#define K_PGUP             18   //   PgUp, Ctrl-R
#define K_PGDN              3   //   PgDn, Ctrl-C
#define K_CTRL_UP         397   // * Ctrl-Up arrow
#define K_CTRL_DOWN       401   // * Ctrl-Down arrow
#define K_CTRL_LEFT        26   //   Ctrl-Left arrow, Ctrl-Z
#define K_CTRL_RIGHT        2   //   Ctrl-Right arrow, Ctrl-B
#define K_CTRL_HOME        29   //   Ctrl-Home, Ctrl-</synsqb>
#define K_CTRL_END         23   //   Ctrl-End, Ctrl-W
#define K_CTRL_PGUP        31   //   Ctrl-PgUp, Ctrl-Hyphen
#define K_CTRL_PGDN        30   //   Ctrl-PgDn, Ctrl-^
#define K_ALT_UP          408   // * Alt-Up arrow
#define K_ALT_DOWN        416   // * Alt-Down arrow
#define K_ALT_LEFT        411   // * Alt-Left arrow
#define K_ALT_RIGHT       413   // * Alt-Right arrow
#define K_ALT_HOME        407   // * Alt-Home
#define K_ALT_END         415   // * Alt-End
#define K_ALT_PGUP        409   // * Alt-PgUp
#define K_ALT_PGDN        417   // * Alt-PgDn
#define K_ENTER            13   //   Enter, Ctrl-M
#define K_RETURN           13   //   Return, Ctrl-M
#define K_SPACE            32   //   Space bar
#define K_ESC              27   //   Esc, Ctrl-<synsqb>
#define K_CTRL_ENTER       10   //   Ctrl-Enter
#define K_CTRL_RETURN      10   //   Ctrl-Return
#define K_CTRL_RET         10   //   Ctrl-Return (Compat.)
#define K_CTRL_PRTSCR     379   // * Ctrl-Print Screen
#define K_CTRL_QUESTION   309   //   Ctrl-?
#define K_ALT_ENTER       284   // * Alt-Enter
#define K_ALT_RETURN      284   // * Alt-Return
#define K_ALT_EQUALS      387   // * Alt-Equals
#define K_ALT_ESC         257   // * Alt-Esc
#define KP_ALT_ENTER      422   // * Keypad Alt-Enter
#define KP_CTRL_5         399   // * Keypad Ctrl-5
#define KP_CTRL_SLASH     405   // * Keypad Ctrl-/
#define KP_CTRL_ASTERISK  406   // * Keypad Ctrl-*
#define KP_CTRL_MINUS     398   // * Keypad Ctrl--
#define KP_CTRL_PLUS      400   // * Keypad Ctrl-+
#define KP_ALT_5            5   // * Keypad Alt-5
#define KP_ALT_SLASH      420   // * Keypad Alt-/
#define KP_ALT_ASTERISK   311   // * Keypad Alt-*
#define KP_ALT_MINUS      330   // * Keypad Alt--
#define KP_ALT_PLUS       334   // * Keypad Alt-+
#define K_INS              22   //   Ins, Ctrl-V
#define K_DEL               7   //   Del, Ctrl-G
#define K_BS                8   //   Backspace, Ctrl-H
#define K_TAB               9   //   Tab, Ctrl-I
#define K_SH_TAB          271   //   Shift-Tab
#define K_CTRL_INS        402   // * Ctrl-Ins
#define K_CTRL_DEL        403   // * Ctrl-Del
#define K_CTRL_BS         127   //   Ctrl-Backspace
#define K_CTRL_TAB        404   // * Ctrl-Tab
#define K_ALT_INS         418   // * Alt-Ins
#define K_ALT_DEL         419   // * Alt-Del
#define K_ALT_BS          270   // * Alt-Backspace
#define K_ALT_TAB         421   // * Alt-Tab
#define K_CTRL_A            1   //   Ctrl-A, Home
#define K_CTRL_B            2   //   Ctrl-B, Ctrl-Right arrow
#define K_CTRL_C            3   //   Ctrl-C, PgDn, Ctrl-ScrollLock
#define K_CTRL_D            4   //   Ctrl-D, Right arrow
#define K_CTRL_E            5   //   Ctrl-E, Up arrow
#define K_CTRL_F            6   //   Ctrl-F, End
#define K_CTRL_G            7   //   Ctrl-G, Del
#define K_CTRL_H            8   //   Ctrl-H, Backspace
#define K_CTRL_I            9   //   Ctrl-I, Tab
#define K_CTRL_J           10   //   Ctrl-J
#define K_CTRL_K           11   //   Ctrl-K
#define K_CTRL_L           12   //   Ctrl-L
#define K_CTRL_M           13   //   Ctrl-M, Return
#define K_CTRL_N           14   //   Ctrl-N
#define K_CTRL_O           15   //   Ctrl-O
#define K_CTRL_P           16   //   Ctrl-P
#define K_CTRL_Q           17   //   Ctrl-Q
#define K_CTRL_R           18   //   Ctrl-R, PgUp
#define K_CTRL_S           19   //   Ctrl-S, Left arrow
#define K_CTRL_T           20   //   Ctrl-T
#define K_CTRL_U           21   //   Ctrl-U
#define K_CTRL_V           22   //   Ctrl-V, Ins
#define K_CTRL_W           23   //   Ctrl-W, Ctrl-End
#define K_CTRL_X           24   //   Ctrl-X, Down arrow
#define K_CTRL_Y           25   //   Ctrl-Y
#define K_CTRL_Z           26   //   Ctrl-Z, Ctrl-Left arrow
#define K_ALT_A           286   //   Alt-A
#define K_ALT_B           304   //   Alt-B
#define K_ALT_C           302   //   Alt-C
#define K_ALT_D           288   //   Alt-D
#define K_ALT_E           274   //   Alt-E
#define K_ALT_F           289   //   Alt-F
#define K_ALT_G           290   //   Alt-G
#define K_ALT_H           291   //   Alt-H
#define K_ALT_I           279   //   Alt-I
#define K_ALT_J           292   //   Alt-J
#define K_ALT_K           293   //   Alt-K
#define K_ALT_L           294   //   Alt-L
#define K_ALT_M           306   //   Alt-M
#define K_ALT_N           305   //   Alt-N
#define K_ALT_O           280   //   Alt-O
#define K_ALT_P           281   //   Alt-P
#define K_ALT_Q           272   //   Alt-Q
#define K_ALT_R           275   //   Alt-R
#define K_ALT_S           287   //   Alt-S
#define K_ALT_T           276   //   Alt-T
#define K_ALT_U           278   //   Alt-U
#define K_ALT_V           303   //   Alt-V
#define K_ALT_W           273   //   Alt-W
#define K_ALT_X           301   //   Alt-X
#define K_ALT_Y           277   //   Alt-Y
#define K_ALT_Z           300   //   Alt-Z
#define K_ALT_1           376   //   Alt-1
#define K_ALT_2           377   //   Alt-2
#define K_ALT_3           378   //   Alt-3
#define K_ALT_4           379   //   Alt-4
#define K_ALT_5           380   //   Alt-5
#define K_ALT_6           381   //   Alt-6
#define K_ALT_7           382   //   Alt-7
#define K_ALT_8           383   //   Alt-8
#define K_ALT_9           384   //   Alt-9
#define K_ALT_0           385   //   Alt-0
#define K_F1               28   //   F1, Ctrl-Backslash
#define K_F2               -1   //   F2
#define K_F3               -2   //   F3
#define K_F4               -3   //   F4
#define K_F5               -4   //   F5
#define K_F6               -5   //   F6
#define K_F7               -6   //   F7
#define K_F8               -7   //   F8
#define K_F9               -8   //   F9
#define K_F10              -9   //   F10
#define K_F11             -40   // * F11
#define K_F12             -41   // * F12
#define K_CTRL_F1         -20   //   Ctrl-F1
#define K_CTRL_F2         -21   //   Ctrl-F2
#define K_CTRL_F3         -22   //   Ctrl-F4
#define K_CTRL_F4         -23   //   Ctrl-F3
#define K_CTRL_F5         -24   //   Ctrl-F5
#define K_CTRL_F6         -25   //   Ctrl-F6
#define K_CTRL_F7         -26   //   Ctrl-F7
#define K_CTRL_F8         -27   //   Ctrl-F8
#define K_CTRL_F9         -28   //   Ctrl-F9
#define K_CTRL_F10        -29   //   Ctrl-F10
#define K_CTRL_F11        -44   // * Ctrl-F11
#define K_CTRL_F12        -45   // * Ctrl-F12
#define K_ALT_F1          -30   //   Alt-F1
#define K_ALT_F2          -31   //   Alt-F2
#define K_ALT_F3          -32   //   Alt-F3
#define K_ALT_F4          -33   //   Alt-F4
#define K_ALT_F5          -34   //   Alt-F5
#define K_ALT_F6          -35   //   Alt-F6
#define K_ALT_F7          -36   //   Alt-F7
#define K_ALT_F8          -37   //   Alt-F8
#define K_ALT_F9          -38   //   Alt-F9
#define K_ALT_F10         -39   //   Alt-F10
#define K_ALT_F11         -46   // * Alt-F11
#define K_ALT_F12         -47   // * Alt-F12
#define K_SH_F1           -10   //   Shift-F1
#define K_SH_F2           -11   //   Shift-F2
#define K_SH_F3           -12   //   Shift-F3
#define K_SH_F4           -13   //   Shift-F4
#define K_SH_F5           -14   //   Shift-F5
#define K_SH_F6           -15   //   Shift-F6
#define K_SH_F7           -16   //   Shift-F7
#define K_SH_F8           -17   //   Shift-F8
#define K_SH_F9           -18   //   Shift-F9
#define K_SH_F10          -19   //   Shift-F10
#define K_SH_F11          -42   // * Shift-F11
#define K_SH_F12          -43   // * Shift-F12
*=================================================================
* MEMOEDIT()
*=================================================================
* User function entry modes
#define MEMOEDIT_IDLE           0      // idle, all keys processed
#define MEMOEDIT_UNKEY          1      // unknown key, memo unaltered
#define MEMOEDIT_UNKEYX         2      // unknown key, memo altered
#define MEMOEDIT_INIT           3      // initialization mode
* User function return codes
#define MEMOEDIT_DEFAULT        0      // perform default action
#define MEMOEDIT_IGNORE        32      // ignore unknown key
#define MEMOEDIT_DATA          33      // treat unknown key as data
#define MEMOEDIT_TOGGLEWRAP    34      // toggle word-wrap mode
#define MEMOEDIT_TOGGLESCROLL  35      // toggle scrolling mode
#define MEMOEDIT_WORDRIGHT    100      // perform word-right operation
#define MEMOEDIT_BOTTOMRIGHT  101      // perform bottom-right operation
*=================================================================
* SET()
*=================================================================
#define _SET_EXACT         1
#define _SET_FIXED         2
#define _SET_DECIMALS      3
#define _SET_DATEFORMAT    4
#define _SET_EPOCH         5
#define _SET_PATH          6
#define _SET_DEFAULT       7
#define _SET_EXCLUSIVE     8
#define _SET_SOFTSEEK      9
#define _SET_UNIQUE       10
#define _SET_DELETED      11
#define _SET_CANCEL       12
#define _SET_DEBUG        13
#define _SET_TYPEAHEAD    14
#define _SET_COLOR        15
#define _SET_CURSOR       16
#define _SET_CONSOLE      17
#define _SET_ALTERNATE    18
#define _SET_ALTFILE      19
#define _SET_DEVICE       20
#define _SET_EXTRA        21
#define _SET_EXTRAFILE    22
#define _SET_PRINTER      23
#define _SET_PRINTFILE    24
#define _SET_MARGIN       25
#define _SET_BELL         26
#define _SET_CONFIRM      27
#define _SET_ESCAPE       28
#define _SET_INSERT       29
#define _SET_EXIT         30
#define _SET_INTENSITY    31
#define _SET_SCOREBOARD   32
#define _SET_DELIMITERS   33
#define _SET_DELIMCHARS   34
#define _SET_WRAP         35
#define _SET_MESSAGE      36
#define _SET_MCENTER      37
#define _SET_SCROLLBREAK  38
*=================================================================
* SETCURSOR()
*=================================================================
#define SETCURSOR_NONE     0  // No cursor
#define SETCURSOR_NORMAL   1  // Normal cursor (underline)
#define SETCURSOR_INSERT   2  // Insert cursor (lower half block)
#define SETCURSOR_SPECIAL1 3  // Special cursor (full block)
#define SETCURSOR_SPECIAL2 4  // Special cursor (upper half block)
*=================================================================
* RDD REQUESTs
*=================================================================
external dbfndx
external dbfntx // default
 |  
 
 
 | 
1) This material appeared originally at http://www.geocities.com/SiliconValley/7737/clipper52clean.html, in 1996.
2) Clipper 5.2   Proprietary software
«a2» 2013.11.11  --- Copyright © Daniele Giacomini -- appunti2@gmail.com http://informaticalibera.net