Remove Structural CDX or Memo flag from a table

The VFP low level file functions (LLFF) can be used to open a table as a file and read/write its header. The Table Header Record Structure is documented in VFP help under Table File Structure.


Note 1 Removing Structural CDX flag will effectively disassociate CDX file from the table but not delete the CDX file.

Note 2 Removing Memo flag will allow to open a table and access all fields excluding memo fields. Attempt to access the memo fields will generate an error.

This is sample code. Add error handling and adjust to your requirements as necessary.

* Test code
CREATE TABLE temp (pk i, cc C(20), mm M)
INDEX on pk TAG pk
lcTableFileName = DBF()
USE
 
* Remove both
*? RemoveCdxMemoFlag(lcTableFileName, "CDX MEMO")
* Remove CDX flag
? RemoveCdxMemoFlag(lcTableFileName, "CDX")
* Remove Memo flag
? RemoveCdxMemoFlag(lcTableFileName, "MEMO")
FUNCTION RemoveCdxMemoFlag
	LPARAMETERS tcTableFileName, tcFlagToRemove
	* tcTableFileName - Full file name including extension
	* tcFlagToRemove - CDX or/and MEMO
	LOCAL lcBuffer, llRemoveCdx, llRemoveMemo, lnCdxFlag, lnMemoFlag, lnByte28, lnFlags2remove
 
	IF VARTYPE(tcTableFileName) <> "C" OR VARTYPE(tcFlagToRemove) <> "C"
		* Invalid parameter(s)
		ERROR 11
	ENDIF
 
	IF NOT FILE(tcTableFileName)
		* File does not exist
		ERROR 1, tcTableFileName
	ENDIF
 
	llRemoveCdx  = "CDX" $ UPPER(tcFlagToRemove)
	llRemoveMemo = "MEMO" $ UPPER(tcFlagToRemove)
 
	IF NOT llRemoveCdx AND NOT llRemoveMemo
		* Invalid 2nd parameter
		ERROR 11
	ENDIF
 
	lnCdxFlag  = 0x01
	lnMemoFlag = 0x02
 
	* Open table low-level as a text file
	lnFh1 = FOPEN(tcTableFileName,2)
	IF lnFh1 < 0
		ERROR 101, tcTableFileName
	ENDIF
 
	* Make sure that's FoxPro table
	lcBuffer = FREAD(lnFh1, 1)
	IF NOT INLIST(ASC(lcBuffer), 0x03, 0x83, 0xF5, 0x30, 0x31, 0x32)
		* Not a FoxPro table
		= FCLOSE(lnFh1)
		ERROR 15, tcTableFileName
	ENDIF
 
	* Flags at offset 28: CDX-0x01, Memo-0x02
	= FSEEK(lnFh1, 28, 0)
	lcBuffer = FREAD(lnFh1,1)
 
	lnFlags2remove = 0
	lnByte28 = ASC(lcBuffer)
	* Remove CDX flag if it's set
	IF llRemoveCdx AND BITAND(lnByte28, lnCdxFlag) <> 0
		lnFlags2remove = lnFlags2remove + lnCdxFlag
	ENDIF
	* Remove Memo flag if it's set
	IF llRemoveMemo AND BITAND(lnByte28, lnMemoFlag) <> 0
		lnFlags2remove = lnFlags2remove + lnMemoFlag
	ENDIF
 
	IF lnFlags2remove <> 0
		* Remove cdx and/or memo flag
		lcBuffer = CHR(BITAND(lnByte28, 0xFF - lnFlags2remove))
		* Write new byte 28 value back
		= FSEEK(lnFh1, 28, 0)
		= FWRITE(lnFh1, lcBuffer)
	ENDIF	
	= FCLOSE(lnFh1)
	* Return combination of the flags that have been removed 0x01, 0x02 or 0x03
	RETURN lnFlags2remove
ENDFUNC	
No votes yet