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.

{ || "hello world" }

The following code block requires a numeric argument and returns the number passed as argument incremented:

{ | n | n+1 }

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
object:method()

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:

@ nTop, nLeft GET Var

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

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.

?/??

? [exp_list]
qout([exp_list])
?? [exp_list]
qqout([exp_list])

@...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]
setpos(nTop, nLeft)
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]
devpos(nTop, nLeft)
devout(exp [, cColorString])
@ nTop, nLeft SAY exp PICTURE cSayPicture [COLOR cColorString]
devpos(nTop, nLeft)
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])
setpos(nRow, nCol)

APPEND

APPEND BLANK
dbappend()

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

CLEAR
Scroll()
SetPos(0,0)
ReadKill(.T.)
GetList := {}
CLEAR GETS
ReadKill(.T.)
GetList := {}
CLEAR SCREEN | CLS
Scroll()
SetPos(0,0)

CLOSE

CLOSE
dbCloseArea()
CLOSE idAlias
idAlias->( dbCloseArea() )
CLOSE ALTERNATE
Set(19, "")
CLOSE DATABASES
dbCloseAll()
CLOSE INDEXES
dbClearIndex()

COMMIT

COMMIT
dbCommitAll()

CONTINUE

CONTINUE
__dbContinue()

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
dbDelete()
DELETE [FOR lForCondition] [WHILE lWhileCondition] [NEXT nNextRecords]\
  \[RECORD nRecord] [REST] [ALL]
dbeval( {||dbDelete()}, {||lForCondition}, {||lWhileCondition},\
  \nNextRecords, nRecord, lRest )
DELETE FILE xcFile
ferase( cFile )

EJECT

EJECT
qqout( chr(13) )

ERASE

ERASE xcFile
ferase( cFile )

FIND

FIND xcSearchString
dbSeek( cSearchString )

GO

GO[TO] nRecord
dbgoto(nRecord)
GO[TO] BOTTOM
dbGoBottom()
GO[TO] TOP
dbgotop()

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
__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

PACK
__dbPack()

QUIT

QUIT
__Quit()

READ

READ
ReadModal(GetList)
GetList := {}
READ SAVE
ReadModal(GetList)

RECALL

RECALL
dbRecall()
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], , , , , , , )
ordListRebuild()

RELEASE

RELEASE idMemvar
__MXRelease( "idMemvar" )
RELEASE ALL
__MRelease("*", .t.)
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
idField1 := 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

RUN xcCommandLine
__Run( cCommand )

SAVE SCREEN TO

SAVE SCREEN TO cScreen
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)
SetColor( 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
Set( _SET_DECIMALS, 0 )
SET DECIMALS TO nDecimals
Set( _SET_DECIMALS, nDecimals )
SET DEFAULT TO
Set( _SET_DEFAULT, "" )
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 EPOCH TO nYear
Set( _SET_EPOCH, nYear )
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 )
SET FILTER TO
dbclearfilter()
SET FILTER TO lCondition
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... ] ]
ordListClear()
ordListAdd( cIndex )
ordListAdd( cIndex1 )
...
SET INTENSITY ON | OFF | xlToggle
Set( _SET_INTENSITY, "ON" | "OFF" | lToggle )
SET KEY nInkeyCode [TO]
SetKey( nInkeyCode, NIL )
SET KEY nInkeyCode TO [idProcedure]
SetKey( nInkeyCode, { |p, l, v| idProcedure(p, l, v)} )
SET MARGIN TO
Set( _SET_MARGIN, 0 )
SET MARGIN TO [nPageOffset]
Set( _SET_MARGIN, nPageOffset )
SET MESSAGE TO
Set( _SET_MESSAGE, 0 )
Set( _SET_MCENTER, .F. )
SET MESSAGE TO [nRow [CENTER | CENTRE]]
Set( _SET_MESSAGE, nRow )
Set( _SET_MCENTER, lCenter )
SET ORDER TO [nIndex]
ordSetFocus( nIndex )
SET PATH TO
Set( _SET_PATH, "" )
SET PATH TO [xcPathspec [, cPathspec1... ] ]
Set( _SET_PATH, cPathspec [, cPathspec1... ] )
SET PRINTER ON | OFF | xlToggle
Set( _SET_PRINTER, "ON" | "OFF" | lToggle )
SET PRINTER TO
Set( _SET_PRINTFILE, "" )
SET PRINTER TO [xcDevice|xcFile [ADDITIVE]]
Set( _SET_PRINTFILE, cDevice|cFile, lAdditive )
SET RELATION TO
dbclearrelation()
SET RELATION TO [expKey1 INTO xcAlias1] [, [TO] expKey2 INTO xcAlias2...]
dbClearRel()
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

STORE value TO variable
variable := value

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

UNLOCK
dbUnlock()
UNLOCK ALL
dbUnlockAll()

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
dbclosearea()
USE [xcDatabase]\
  \[INDEX xcIndex1 [, xcIndex2...] [ALIAS xcAlias] [EXCLUSIVE|SHARED] [NEW] \
  \[READONLY] [VIA cDriver]]
dbUseArea( [lNewArea], [cDriver], cDatabase, [cAlias], [lShared], [lReadOnly] )
[dbSetIndex( cIndex1 )]
[dbSetIndex( cIndex2 )]
...

ZAP

ZAP
dbZap()

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