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.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
* 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")

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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	

Comments

As a sidenote or additional info:
If you need to remove the memo-flag due to a corrupt memofield, you may first try my memo-rescue tool which can be found at http://code.msdn.microsoft.com/FoxPro. It copies the corrupt table and tries to read each memofield of each record. That way you loose only the corrupt ones. It also creates a log of those records with bad data.

Hello wOOdy,
Many times your posts have helped me over a great many years!! Thanks.
BUT the code.msdn.microsoft.com link to the memo-rescue tool appears to have been eleminated!
Is there another place to get it??
thanks, Clyde

This code worked perfectly. I have DBF files that are copied into an archive folder . The corresponding CDX files are not being copied. Periodically a secondary program runs to open and use the data in the DBF files. An error ( CDX not found ) would occur when the DBF was used or records selected by the program. The above code allowed the program to test each DBF as it was called and remove the CDX flag as needed. The secondary program now runs without error.

Thanks very much

An old post. but still replying.
You can just use SET SAFETY OFF and USE the table. it will automatically remove the INDEX link if its not available.