home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC Press 1997 July
/
Sezamfile97_1.iso
/
msdos
/
clipper
/
nettos11.a01
/
SYNCHRO
/
LOGREC.PRG
< prev
next >
Wrap
Text File
|
1993-02-23
|
14KB
|
488 lines
/*
* File......: LOGREC.PRG
* Author....: Glenn Scott
* CIS ID....: 71620,1521
* Date......: $Date$
* Revision..: $Revision$
* Log file..: $Logfile$
*
* This is an original work by Glenn Scott and is placed in the
* public domain.
*
* Modification history:
* ---------------------
*
* $Log$
*
*/
#include "netto.ch"
#include "ftint86.ch"
#define OP_LOG 208
#define OP_LOCK 209
#define OP_REL 210
#define OP_RELSET 211
#define OP_CLR 212
#define OP_CLRSET 213
/* $DOC$
* $FUNCNAME$
* FN_LOGLR()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Log logical record
* $SYNTAX$
*
* fn_logLR( <cRecord>, <nLockDir>, <nTimeOut> ) -> lSuccess
*
* $ARGUMENTS$
*
* <cRecord> - a character string containing the name of the
* "record" to be logged in the log table for
* possible later locking.
*
* <nLockDir> - Locking directive. Only used if you're in
* "extended lock mode", otherwise ignored.
* The following locking directives are valid:
*
* 0 = Log Record (the default). This only logs the record in
* the table; it does not lock the record.
* 1 = Log and lock record with an exclusive lock.
* This will log the record and lock it for exclusive use
* by one user. He is the only one who can read and write
* this record.
* 3 = Log and lock record with a shareable, read-only lock.
* This will log a record and lock it with a read-only lock.
* While this record is locked anyone can read it, no one can
* update it. If you wish to update this record with a write,
* the read-only lock must be changed to an exclusive lock.
*
* <nTimeOut> - Amount of time to wait for a lock in 1/18th
* of a second ticks. 0 = Don't wait (the
* default). This parameter is only valid if
* you're in extended lock mode (lock mode 1),
* otherwise, it will be ignored.
*
* $RETURNS$
*
* <lSuccess>, .t. if the call succeeds, .f. if it doesn't.
* Check FN_ERROR() for specific error codes. The valid codes
* are:
*
* 0 = Success
* 254 = Timeout failure
* 255 = Failure
*
* $DESCRIPTION$
*
* This call places a logical record in the log table and
* optionally locks it.
*
* Logical Records are simply "names" that are locked by
* workstations. The server maintains the tables for each
* workstation. They don't represent actual files or
* physical byte ranges, but they could. You can use these
* logical records to lock anything of significance.
*
* The server maintains a "log table" for each workstation.
* To lock something, it must first be "logged". After
* everything is logged, then a "lock" is issued.
*
* You can unlock the entire set of logged records at once,
* or just one at a time. You can remove the logged records
* from the table all at once, or one at a time.
*
* This is most useful in a Clipper application if you want
* to lock a "bunch of things", but treat the package as
* one lock. For example, say an employee record consists of
* one record in EMPLOYEE.DBF and a few records in "TIMECARD.DBF"
* and still more records in "HISTORY.DBF." Perhaps you want
* to show a bunch of this data on the screen and you don't
* want anyone to change anything about this employee while
* you're working.
*
* The "employee" is thus a "conceptual" thing. You can't
* rlock() the employee, what does that mean? Which record
* from which file?
*
* Instead, you can issue a logical lock on "SCOTT, GLENN" or
* better yet, on the employee's ID number.
*
* Now, if every application _cooperates_ and checks the
* status of the logical lock on "SCOTT, GLENN" before
* updating, then you in effect have created a lock on multiple
* records in multiple databases.
*
* The sequence would look something like this:
*
* fn_logLr( "SCOTT, GLENN" )
* if fn_lkLRSet()
* qout( "Got the lock" )
* // Do processing here on this employee
* else
* qout( "Lock failed, try later" )
* endif
* fn_clLRSet() // unlock everything and clear log table
*
*
* IMPORTANT! There's no _real_ (i.e., physical) locking going
* on here. If some application does not obey the logicial
* locking protocol you define (i.e., lock the employee id),
* then this won't work.
*
* You could implement this sort of scheme by using a .DBF and
* thus it would not be NetWare-specific, but one advantage to
* this technique is that if the workstation reboots, the locks
* will eventually get cleared when the first of two things happens:
*
* - the workstation loads the shell and attaches to
* the server again
*
* - the watchdog process in the server detects the station
* is gone and clears the connection.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET() FN_GETLMOD()
* $INCLUDE$
*
* $END$
*/
function fn_logLR( cRec, nLockDir, nTimeOut )
local aRegs[ INT86_MAX_REGS ], lRes, nCurMode := fn_getLMod()
default nLockDir to 0,;
nTimeOut to 0
cRec := iif( len( cRec ) > 99, substr( cRec, 1, 99 ), cRec )
aRegs[ AX ] := makehi( OP_LOG )
aRegs[ DS ] := I2BYTE( len( cRec ) ) + cRec
aRegs[ DX ] := REG_DS
if nCurMode == 1
aRegs[ AX ] += nLockDir
aRegs[ BP ] := nTimeOut
endif
lRes := ft_int86( INT21, aRegs )
if lRes
if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
_fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
lRes := .f.
else
lRes := .t.
_fnSetErr( ESUCCESS )
endif
else
_fnSetErr( EINT86 )
endif
return lRes
/* $DOC$
* $FUNCNAME$
* FN_RELLR()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Release logical record
* $SYNTAX$
*
* fn_relLR( <cRecord> ) -> lSuccess
*
* $ARGUMENTS$
*
* <cRecord> - the name of the "record" to unlock
*
* $RETURNS$
*
* <lSuccess>, .t. if the call succeeds, .f. if there was
* no record found (failure).
*
* $DESCRIPTION$
*
* This call unlocks a logical record previously logged,
* but does not remove it from the log table. See the
* FN_CLRLR() and FN_CLLRSET() functions.
*
* For more information logical record locking, see the
* description for the FN_LOGLR() function.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_LOGLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET()
* $INCLUDE$
*
* $END$
*/
function fn_relLR( cRec )
return _fnRecOp( OP_REL, cRec )
/* $DOC$
* $FUNCNAME$
* FN_CLRLR()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Clear logical record
* $SYNTAX$
*
* fn_clrLR( <cRecord> ) -> lSuccess
*
* $ARGUMENTS$
*
* <cRecord> - the name of the "record" to unlock and remove from
* the workstation's log table
*
* $RETURNS$
*
* <lSuccess>, .t. if the call succeeds, .f. if there was
* no record found (failure).
*
* $DESCRIPTION$
*
* This call unlocks a logical record previously logged,
* and removes it from the workstation's log table.
*
* For more information logical record locking, see the
* description for the FN_LOGLR() function.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_LOGLR() FN_RELLR() FN_LKLRSET() FN_RELLRSE() FN_CLLRSET()
* $INCLUDE$
*
* $END$
*/
function fn_clrLR( cRec )
return _fnRecOp( OP_CLR, cRec )
/* ------------------------------------------------------------------------ */
static function _fnRecOp( xOp, cRec )
local aRegs[ INT86_MAX_REGS ], lRes := .f.
cRec := iif( len( cRec ) > 99, substr( cRec, 1, 99 ), cRec )
aRegs[ AX ] := makehi( xOp )
aRegs[ DS ] := I2BYTE( len( cRec ) ) + cRec
aRegs[ DX ] := REG_DS
lRes := ft_int86( INT21, aRegs )
if lRes
if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
_fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
lRes := .f.
else
lRes := .t.
_fnSetErr( ESUCCESS )
endif
else
_fnSetErr( EINT86 )
endif
return lRes
/* ------------------------------------------------------------------------ */
/* $DOC$
* $FUNCNAME$
* FN_LKLRSET()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Lock logical record set
* $SYNTAX$
*
* fn_lkLRSet( <nTimeOut>, <nLockDir> ) -> lSuccess
*
* $ARGUMENTS$
*
* <nTimeOut> is the amount of time to wait for the lock.
* If the workstation is in "compatibility mode" (lock mode 0),
* then a value of 0 = don't wait, and any other value means
* wait forever. 0 is the default.
*
* If the workstation is in "extended mode" (lock mode 1), then
* <nTimeOut> is the number of 1/18th per second ticks to wait.
* 0 = don't wait (the default).
*
* <nLockDir> is the "locking directive" and is only significant
* if the workstation is in extended mode (lock mode 1), otherwise
* it is ignored. The following are the valid locking directives:
*
* 0 = Log and lock record with an exclusive lock.
* This will log the record and lock it for exclusive use
* by one user. He is the only one who can read and write
* this record.
* 1 = Lock record with a shareable lock
* 3 = Log and lock record with a shareable, read-only lock.
* This will log a record and lock it with a read-only lock.
* While this record is locked anyone can read it, no one can
* update it. If you wish to update this record with a write,
* the read-only lock must be changed to an exclusive lock.
*
* $RETURNS$
*
* <lSuccess>, .t. if the call succeeds, .f. if it doesn't.
* Check FN_ERROR() for specific error codes. Valid error codes
* are:
*
* 0 = Success
* 254 = Timeout failure
* 255 = Failure
*
* $DESCRIPTION$
*
* Attempts to lock all records in the current log table. If
* it can't lock them all, it will fail, leaving none of them
* locked.
*
* For more information logical record locking, see the
* description for the FN_LOGLR() function.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_LOGLR() FN_RELLR() FN_CLRLR() FN_RELLRSE() FN_CLLRSET()
* $INCLUDE$
*
* $END$
*/
function fn_lkLRSet( nTimeout, nLockDir )
local aRegs[ INT86_MAX_REGS ], lRes := .f., nCurMode
default nTimeout to 0,;
nLockDir to 0
nCurMode := fn_getLMod()
aRegs[ AX ] := makehi( OP_LOCK )
if nCurMode == 1
aRegs[ AX ] += nLockDir
aRegs[ BP ] := nTimeout
else
aRegs[ DX ] := iif( nTimeOut # 0, 1, 0 )
endif
if ft_int86( INT21, aRegs )
if UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) # ESUCCESS
_fnSetErr( UNSIGNED( LOWBYTE( aRegs[ AX ] ) ) )
else
lRes := .t.
_fnSetErr( ESUCCESS )
endif
else
_fnSetErr( EINT86 )
endif
return lRes
/* $DOC$
* $FUNCNAME$
* FN_RELLRSE()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Release logical record set
* $SYNTAX$
*
* fn_relLRSe() -> lSuccess
*
* $ARGUMENTS$
*
* None
*
* $RETURNS$
*
* <lSuccess>, which should be ignored since the underlying API
* returns nothing.
*
* $DESCRIPTION$
*
* This call unlocks all records in the log table, but leaves
* them in the log table (for possible later locking, for example).
* If you want to actually delete them, use the "clear" functions
* FN_CLRLR() and FN_CLLRSET().
*
* For more information logical record locking, see the
* description for the FN_LOGLR() function.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_LOGLR() FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_CLLRSET()
* $INCLUDE$
*
* $END$
*/
function fn_relLRSe()
return _fnReq( OP_RELSET, "", "" ) == ESUCCESS
/* $DOC$
* $FUNCNAME$
* FN_CLLRSET()
* $CATEGORY$
* Synchronization
* $ONELINER$
* Clear logical record set
* $SYNTAX$
*
* fn_clLRSet() -> lSuccess
*
* $ARGUMENTS$
*
* None
*
* $RETURNS$
*
* <lSuccess>, which should be ignored since the underlying
* API returns nothing.
*
* $DESCRIPTION$
*
* Unlocks all logical records in the log table and removes them
* from the log table as well.
*
* For more information logical record locking, see the
* description for the FN_LOGLR() function.
*
* $EXAMPLES$
*
* $SEEALSO$
* FN_LOGLR() FN_RELLR() FN_CLRLR() FN_LKLRSET() FN_RELLRSE()
* $INCLUDE$
*
* $END$
*/
function fn_clLRSet()
return _fnReq( OP_CLRSET, "", "" ) == ESUCCESS