$DEFINE .F. 0
$DEFINE .T. NOT .F.
STRUCT dbcont
memo AS BYTE
updty AS BYTE
updtm AS BYTE
updtd AS BYTE
nrecs AS LONG
frecp AS WORD
recsize AS WORD
filler AS STRING*20
END STRUCT
STRUCT flddef
fname AS STRING*11
ftype AS STRING*1
filler AS STRING*4
flen AS BYTE
decimals AS BYTE
fill2 AS STRING*14
END STRUCT
STRUCT fldinfo
name AS STRING*10
owntype AS STRING*1
maxlen AS BYTE
decimals AS BYTE
END STRUCT
DIM mStru AS QMEMORYSTREAM, fldStr AS QMEMORYSTREAM
DIM h AS dbCont, f AS fldDef
DIM openStr AS QFILESTREAM
DIM openDbf AS STRING*64
SUB struinfo(id AS STRING, thistype AS STRING, _
fullen AS BYTE, point AS BYTE)
DIM u AS fldinfo
u.name=id: u.owntype=thistype: u.maxlen=fullen: u.decimals=point
mStru.WriteUDT(u)
END SUB
FUNCTION dbCreate( nameArch AS STRING) AS INTEGER
DIM openStr AS QFILESTREAM
DIM mstream AS QMEMORYSTREAM
IF mStru.size = 0 THEN
PRINT "No information available.."
EXIT FUNCTION
END IF
IF openStr.OPEN(nameArch, fmCreate) = FALSE THEN
result = FALSE
EXIT FUNCTION
END IF
DIM now AS STRING*10
now = DATE$
DIM h AS dbcont
DIM thisfld AS flddef
DIM nflds AS WORD
DIM u AS fldinfo
h.memo = &H03
h.recsize = 0
h.nrecs = 0
nflds = mStru.size / SIZEOF(u)
mStru.position = 0
FOR i% = 1 TO nflds
mStru.readUDT(u)
WITH thisfld
.fname = UCASE$(sz10Convert(u.name))
.ftype = u.owntype
.flen = u.maxlen
.decimals = u.decimals
END WITH
IF thisfld.ftype = "M" THEN
h.memo = &H83
END IF
mstream.writeUDT(thisfld)
IF thisfld.ftype = "C" THEN
h.recsize = h.recsize + thisfld.flen + thisfld.decimals*256
ELSE
h.recsize = h.recsize + thisfld.flen
END IF
NEXT
h.recsize = h.recsize + 1
IF h.memo = &H83 THEN
dbtCreate(REPLACESUBSTR$(nameArch, "dbf", "dbt"))
END IF
h.frecp = 32 * (1 + nflds) + 2
h.updty = VAL( MID$(now, 9,2) )
h.updtm = VAL( MID$(now, 1,2) )
h.updtd = VAL( MID$(now, 4,2) )
WITH openStr
.writeUDT(h)
.copyFrom(mstream,0)
.writeNum(&H000D,2)
.writeNum(&H1A,1)
END WITH
mstream.CLOSE
openStr.CLOSE
result = TRUE
END FUNCTION
FUNCTION dbOpen(dbfArc AS STRING, mode AS INTEGER) AS INTEGER
result = FALSE
IF openStr.OPEN(dbfArc, mode) = FALSE THEN
PRINT "It can't be open.. " + dbfArc
EXIT FUNCTION
END IF
openStr.ReadUDT(h)
IF h.memo = &H03 OR h.memo = &H83 THEN
ELSE
PRINT "Invalid file format.."
EXIT FUNCTION
END IF
IF h.memo = &H83 THEN
dbtOpen(REPLACESUBSTR$(dbfArc, "dbf", "dbt"), mode)
END IF
openDbf = dbfArc
fldstr.CopyFrom(openStr, h.frecp-SIZEOF(h)-2)
openStr.position = h.frecp
result = TRUE
END FUNCTION
SUB dbClose
IF h.memo = 0 THEN
EXIT SUB
END IF
IF h.memo = &H83 THEN
dbtClose
END IF
openStr.CLOSE
h.memo = 0
fldStr.size = 0
openDbf = ""
END SUB
FUNCTION hasMemo() AS INTEGER
result = (h.memo = &H083)
END FUNCTION
FUNCTION dataOffset() AS INTEGER
result = h.frecp
END FUNCTION
SUB dbgotop
openStr.position = h.frecp
END SUB
SUB dbgoto(n AS LONG)
IF n > h.nrecs THEN n = h.nrecs
IF n < 1 THEN n=1
openStr.position = (n-1) * (h.recsize) + h.frecp
END SUB
FUNCTION recno() AS LONG
result = 0
IF (openStr.position - h.frecp) < 0 THEN EXIT FUNCTION
result = 1+(openStr.position - h.frecp)/h.recsize
END FUNCTION
SUB dbSkip(n AS LONG)
here& = openStr.position
there& = openStr.position + n * h.recsize
IF there& < h.frecp THEN
openStr.position = h.frecp : EXIT SUB
END IF
IF there& > openStr.size THEN
openStr.position = openStr.size-1 : EXIT SUB
END IF
openStr.position = there&
END SUB
SUB dbgobottom
openStr.position = h.frecp + IIF(h.nrecs = 0, 0, h.nrecs-1) * h.recsize
END SUB
FUNCTION bof() AS INTEGER
result = (openStr.position = h.frecp)
END FUNCTION
FUNCTION eof() AS INTEGER
here& = openStr.position
openStr.READ(i?)
openStr.position = here&
result = ( i? = &H1A)
END FUNCTION
FUNCTION recsize() AS WORD
result = h.recsize
END FUNCTION
FUNCTION reccount() AS LONG
result = h.nrecs
END FUNCTION
FUNCTION fCount() AS INTEGER
result = fldStr.size / SIZEOF(f)
END FUNCTION
SUB dbAppend
IF openstr.size = 0 THEN
EXIT SUB
END IF
openStr.position = openStr.size - 1
openStr.writeStr(STRING$(recsize(), 32), recsize())
openStr.WriteNUM(&H1A, 1)
h.nrecs = h.nrecs + 1
h.updty = VAL( MID$(DATE$, 9,2) )
h.updtm = VAL( MID$(DATE$, 1,2) )
h.updtd = VAL( MID$(DATE$, 4,2) )
openStr.position = 0
openStr.writeUDT(h)
dbgoBottom
END SUB
SUB dbZap
DIM auxStr AS QMEMORYSTREAM
openStr.position = 0
h.nrecs=0
h.updty = VAL( MID$(DATE$, 9,2) )
h.updtm = VAL( MID$(DATE$, 1,2) )
h.updtd = VAL( MID$(DATE$, 4,2) )
openStr.writeUDT(h)
openStr.position = 0
auxStr.CopyFrom(openStr, h.frecp)
auxStr.WriteNUM(&H1A, 1)
openStr.CLOSE
KILL openDbf
openStr.OPEN(OpenDbf, fmCreate)
openStr.CopyFrom(auxStr, 0)
openStr.position = openStr.size - 1
IF h.memo = &H83 THEN
dbtClose
dbt$ = REPLACESUBSTR$(openDbf, "dbf", "dbt")
KILL dbt$
dbtCreate(dbt$)
dbtOpen(dbt$, fmOpenReadWrite)
END IF
END SUB
FUNCTION fieldGet( i AS WORD) AS VARIANT
result = ""
IF i <= 0 OR i > fCount() THEN EXIT FUNCTION
POS& = openStr.position
fldStr.position = 0
null$ = openStr.readStr(1)
FOR j__ = 1 TO i
fldStr.readUDT(f)
SELECT CASE f.ftype
CASE "C"
__lon = f.flen + 256 * f.decimals
CASE ELSE
__lon = f.flen
END SELECT
__r$ = OpenStr.ReadStr(__lon)
NEXT
SELECT CASE f.ftype
CASE "C"
result = __r$
CASE "D"
result = stod(__r$)
CASE "N"
result = floatVal(__r$)
CASE "M"
result = ""
IF VAL(__r$) > 0 THEN
result = memoget( VAL(__r$) )
END IF
CASE "L"
result = IIF( __r$ = "F", .F., .T.)
END SELECT
openStr.position= POS&
END FUNCTION
SUB fieldput(index AS WORD, $value AS STRING, #value AS SINGLE )
IF index <= 0 OR index > fCount() THEN EXIT SUB
POS& = openStr.position
fldStr.position = 0
lon?? = 0
null$ = openStr.ReadStr(1)
__j=0
DO
INC(__j)
fldStr.ReadUDT(f)
SELECT CASE f.ftype
CASE "C"
lon?? = f.flen + 256 * f.decimals
CASE ELSE
lon?? = f.flen
IF f.ftype = "M" AND #value = FORCE_UPDATE THEN
currentRecID = VAL( openStr.readStr(lon??) )
openStr.position = openStr.position - lon??
END IF
END SELECT
IF __j = index THEN EXIT DO
openStr.position = openStr.position + lon??
LOOP
SELECT CASE f.ftype
CASE "C"
__s$ = Format$("%-"+STR$(f.flen + 256 * f.decimals)+"s", $value)
CASE "D"
__s$ = Format$("%"+STR$(f.flen)+"s", dtos($value))
CASE "N"
__s$ = Format$("%"+STR$(f.flen-f.decimals-1)+"."+STR$(f.decimals)+"f", #value)
CASE "M"
__s$ = Format$("%10d", memoUpdate($value))
CASE "L"
__s$ = IIF(#value = .F., "F", "T")
END SELECT
openStr.Write(__s$)
openStr.position = POS&
END SUB
FUNCTION fieldname(i AS WORD) AS STRING
result = ""
IF i <= 0 OR i > fCount() THEN EXIT FUNCTION
fldstr.position = (i-1) * SIZEOF(f)
fldstr.readUDT(f)
result = sz10Unconvert(f.fname)
END FUNCTION
FUNCTION fieldpos(fldname AS STRING) AS INTEGER
result = 0
j__% = 1
fldstr.position = 0
DO
fldstr.readUDT(f)
IF sz10Uncovert(f.fname)= name THEN
result = j__%
EXIT DO
END IF
INC(j__%)
LOOP
END FUNCTION
FUNCTION TypeOf( fnum AS WORD) AS STRING
result = "U"
IF fnum <= 0 OR fnum > fCount() THEN EXIT FUNCTION
fldStr.position = (fnum - 1) * SIZEOF(f)
result = f.ftype
END FUNCTION
FUNCTION DecimalsOf( fnum AS WORD ) AS INTEGER
result = 0
IF fnum <= 0 OR fnum > fCount() THEN EXIT FUNCTION
fldStr.position = (fnum - 1) * SIZEOF(f)
fldstr.ReadUDT(f)
result = f.decimals
END FUNCTION
FUNCTION LengthOf( fnum AS WORD ) AS INTEGER
result = 0
IF fnum <= 0 OR fnum > fCount() THEN EXIT FUNCTION
fldStr.position = (fnum - 1) * SIZEOF(f)
fldstr.ReadUDT(f)
SELECT CASE f.ftype
CASE "C"
result = f.flen + 256 * f.decimals
CASE ELSE
result = f.flen
END SELECT
END FUNCTION
SUB Delete
POS& = openStr.position
openStr.WriteStr("*", 1)
openStr.position = POS&
END SUB
SUB Recall
POS& = openStr.position
openStr.WriteStr(" ", 1)
openStr.position = POS&
END SUB
FUNCTION dbDeleted AS INTEGER
POS& = openStr.position
c$ = openStr.ReadStr(1)
openStr.position = POS&
result = ( c$ = "*" )
END FUNCTION
SUB dbPack
DIM buf AS QMEMORYSTREAM
openStr.position = h.frecp
count& = 0
WHILE NOT eof()
IF NOT dbDeleted() THEN
buf.WriteBinStr(openStr.ReadBinStr(h.recsize), h.recsize)
INC count&
ELSE
dbSkip 1
END IF
WEND
openStr.position = h.frecp
openStr.copyFrom(buf, 0)
openStr.WriteNUM(&H1A, 1)
openStr.position = 0
h.nrecs = count&
h.updty = VAL( MID$(DATE$, 9,2) )
h.updtm = VAL( MID$(DATE$, 1,2) )
h.updtd = VAL( MID$(DATE$, 4,2) )
openStr.writeUDT(h)
openStr.position = h.frecp
END SUB
FUNCTION dblocate(key AS VARIANT) AS INTEGER
result = .F.
current& = recno()
keyType? = VARTYPE(key)
DIM fvalue AS VARIANT
FOR i% = 1 TO fCount()
fvalue = fieldget(i%)
IF VARTYPE(fvalue) = keyType? THEN
SELECT CASE keyType?
CASE 2
IF LEN(key) > LEN(fvalue) THEN
EXIT FUNCTION
END IF
IF INSTR( UCASE$(fvalue), UCASE$(key)) > 0 THEN
result = .T.
EXIT FOR
END IF
CASE 0,1
IF key = fvalue THEN
result = .T.
EXIT FOR
END IF
END SELECT
END IF
NEXT
dbgoto(current&)
END FUNCTION
FUNCTION dbscan(key AS VARIANT, fname AS STRING, mode AS INTEGER) AS INTEGER
result = .F.
DIM value AS VARIANT
ftype = typeOf( fname )
value = fieldget( fieldpos(fname) )
SELECT CASE mode
CASE 0
SELECT CASE ftype
CASE "N", "D"
IF key = value THEN
result = .T.
END IF
CASE "C"
IF LEN(key) > LEN(value) THEN
EXIT FUNCTION
END IF
IF UCASE$(MID$(value, 1, LEN(key))) = UCASE$(Key) THEN
result = .T.
END IF
END SELECT
CASE ELSE
END SELECT
END FUNCTION
SUB dbCopyto(targetFileName AS STRING, sourceFieldName AS STRING, thisValue AS VARIANT)
DIM tmpStr AS QFILESTREAM
IF NOT tmpStr.OPEN(targetFileName, fmcreate) THEN
PRINT "Cannot create target table " + targetFileName
EXIT SUB
END IF
POS& = openStr.position
openStr.position = 0
tmpStr.CopyFrom(openStr, h.frecp)
count& = 0
openStr.position = h.frecp
WHILE NOT eof()
IF dbScan(thisValue, sourceFieldname, 0) THEN
tmpStr.WriteBinStr(openStr.ReadBinStr(h.recsize), h.recsize)
INC count&
ELSE
dbSkip 1
END IF
WEND
tmpStr.position = 0
DIM head AS dbCont
head.nrecs = count&
head.updty = VAL( MID$(DATE$, 9,2) )
head.updtm = VAL( MID$(DATE$, 1,2) )
head.updtd = VAL( MID$(DATE$, 4,2) )
tmpStr.WriteUDT(head)
tmpStr.CLOSE
openStr.position = POS&
END SUB
|
|