Microsoft KB Archive/250300: Difference between revisions
m (Text replacement - "&" to "&") |
m (Text replacement - """ to """) |
||
Line 78: | Line 78: | ||
Two possible workarounds are described in this section. The first workaround uses the '''ADIR''' function to provide basic information about the tables. This code can be modified to return information on all files and not just FoxPro tables. Copy this code into a program and execute it: | Two possible workarounds are described in this section. The first workaround uses the '''ADIR''' function to provide basic information about the tables. This code can be modified to return information on all files and not just FoxPro tables. Copy this code into a program and execute it: | ||
<pre class="codesample">nCnt=ADIR(aFileList, | <pre class="codesample">nCnt=ADIR(aFileList,"*.DBF") | ||
FOR x = 1 TO nCnt | FOR x = 1 TO nCnt | ||
? aFileList[x,1], aFileList[x,2], aFileList[x,3] | ? aFileList[x,1], aFileList[x,2], aFileList[x,3] | ||
Line 92: | Line 92: | ||
</div></li> | </div></li> | ||
<li><pre class="codesample">DO Zdir with | <li><pre class="codesample">DO Zdir with "*.DBF"</pre> | ||
<div class="indent"> | <div class="indent"> | ||
Line 98: | Line 98: | ||
</div></li> | </div></li> | ||
<li><pre class="codesample">=Zdir( | <li><pre class="codesample">=Zdir("*.DBF")</pre> | ||
<p>To retrieve a list of any file type, use the following syntax:</p> | <p>To retrieve a list of any file type, use the following syntax:</p> | ||
<pre class="codesample">DO Zdir WITH | <pre class="codesample">DO Zdir WITH "*.*" | ||
</pre></li></ul> | </pre></li></ul> | ||
Line 116: | Line 116: | ||
PRIVATE lCancel | PRIVATE lCancel | ||
IF SET('TALK') = | IF SET('TALK') = "ON" | ||
SET TALK OFF | SET TALK OFF | ||
cSetTalk = | cSetTalk = "ON" | ||
ELSE | ELSE | ||
cSetTalk = | cSetTalk = "OFF" | ||
ENDIF | ENDIF | ||
cOnError = ON( | cOnError = ON("ERROR") | ||
cSetEscape = SET('ESCAPE') | cSetEscape = SET('ESCAPE') | ||
Line 139: | Line 139: | ||
* Is this VFP - used in determining table type on Fox 2.x | * Is this VFP - used in determining table type on Fox 2.x | ||
lVFP = ( | lVFP = ( "VISUAL" $ UPPER(VERSION()) ) | ||
IF TYPE( | IF TYPE("cFileMask") <> "C" | ||
cFileMask = | cFileMask = "*.dbf" | ||
ENDIF | ENDIF | ||
Line 149: | Line 149: | ||
cJustPath = ADDBS(IIF(EMPTY(cJustPath), SYS(5) + SYS(2003), cJustPath)) | cJustPath = ADDBS(IIF(EMPTY(cJustPath), SYS(5) + SYS(2003), cJustPath)) | ||
lDBF = ( UPPER(JUSTEXT(cFileMask)) = | lDBF = ( UPPER(JUSTEXT(cFileMask)) = "DBF" ) | ||
nFileCnt = ADIR(aFileList, cFileMask) | nFileCnt = ADIR(aFileList, cFileMask) | ||
Line 156: | Line 156: | ||
nFileSize = 0 | nFileSize = 0 | ||
ELSE | ELSE | ||
*** NOTE -- DIR puts '_' first, ASORT puts | *** NOTE -- DIR puts '_' first, ASORT puts "_" last | ||
=ASORT(aFileList) | =ASORT(aFileList) | ||
ENDIF | ENDIF | ||
Line 164: | Line 164: | ||
? && Start with a blank line | ? && Start with a blank line | ||
IF lDBF | IF lDBF | ||
? | ? "Database Table/DBF files" | ||
?? | ?? " # Records" AT 25 | ||
?? | ?? "Last Update" AT 37 | ||
?? | ?? " Size" AT 50 | ||
ENDIF | ENDIF | ||
IF nFileCnt = 0 | IF nFileCnt = 0 | ||
? | ? "None" | ||
ENDIF | ENDIF | ||
Line 185: | Line 185: | ||
* Nobody has the table exclusive, so check the header for record count | * Nobody has the table exclusive, so check the header for record count | ||
cByte1 = dec2hex(str2long(FREAD(hdl, 1))) && Table type | cByte1 = dec2hex(str2long(FREAD(hdl, 1))) && Table type | ||
cReadStr = | cReadStr = "" | ||
FOR nCnt = 7 TO 4 STEP -1 | FOR nCnt = 7 TO 4 STEP -1 | ||
nIdx = FSEEK(hdl, nCnt, 0) | nIdx = FSEEK(hdl, nCnt, 0) | ||
Line 195: | Line 195: | ||
* Check to see if the table is Fox 2.x or VFP or Not a table | * Check to see if the table is Fox 2.x or VFP or Not a table | ||
DO CASE | DO CASE | ||
CASE INLIST(cByte1, | CASE INLIST(cByte1, "02", "03", "43", "63", "83", "8B", "CB", "F5", "FB") | ||
* FoxPro 2.x table | * FoxPro 2.x table | ||
nTableType = 1 | nTableType = 1 | ||
CASE INLIST(cByte1, | CASE INLIST(cByte1, "30") | ||
* Visual FoxPro Table | * Visual FoxPro Table | ||
nTableType = 2 | nTableType = 2 | ||
Line 207: | Line 207: | ||
IF nTableType = 0 ; | IF nTableType = 0 ; | ||
OR (nTableType = 2 AND NOT lVFP) | OR (nTableType = 2 AND NOT lVFP) | ||
cFileName = cFileName + | cFileName = cFileName + " Not a Fox database" | ||
cRecCount = | cRecCount = "" | ||
ENDIF | ENDIF | ||
ELSE | ELSE | ||
* File cannot be opened at all. | * File cannot be opened at all. | ||
cRecCount = | cRecCount = "Can't read file" | ||
cFileDate = | cFileDate = "" | ||
ENDIF | ENDIF | ||
Line 250: | Line 250: | ||
ENDFOR | ENDFOR | ||
IF lCancel | IF lCancel | ||
? | ? "*** INTERRUPTED ***" | ||
ELSE | ELSE | ||
? | ? | ||
? TRANSFORM(nFileSize, | ? TRANSFORM(nFileSize, "999999999") + " bytes in " + ALLTRIM(STR(nFileCnt)) + " files." | ||
? TRANSFORM(DISKSPACE(), | ? TRANSFORM(DISKSPACE(), "999999999") + " bytes remaining on drive." | ||
ENDIF | ENDIF | ||
IF cSetTalk = | IF cSetTalk = "ON" | ||
SET TALK ON | SET TALK ON | ||
ENDIF | ENDIF | ||
IF cSetEscape = | IF cSetEscape = "ON" | ||
SET ESCAPE ON | SET ESCAPE ON | ||
ENDIF | ENDIF | ||
IF cSetResource = | IF cSetResource = "ON" | ||
SET RESOURCE ON | SET RESOURCE ON | ||
ENDIF | ENDIF | ||
RETURN | RETURN "" | ||
FUNCTION Hex2Dec | FUNCTION Hex2Dec | ||
Line 276: | Line 276: | ||
* example: | * example: | ||
* nDecimal = 111 | * nDecimal = 111 | ||
* cHex = dec2hex(nDecimal) returns | * cHex = dec2hex(nDecimal) returns "6F" | ||
PARAMETER cHexStr | PARAMETER cHexStr | ||
PRIVATE nDecimal | PRIVATE nDecimal | ||
Line 295: | Line 295: | ||
* example: | * example: | ||
* nDecimal = 111 | * nDecimal = 111 | ||
* cHex = dec2hex(nDecimal) returns | * cHex = dec2hex(nDecimal) returns "6F" | ||
PARAMETER nDecimal | PARAMETER nDecimal | ||
PRIVATE cBit1, cBit2, cHexStr | PRIVATE cBit1, cBit2, cHexStr | ||
Line 310: | Line 310: | ||
* returns: long integer value | * returns: long integer value | ||
* example: | * example: | ||
* m.longstr = | * m.longstr = "1111" | ||
* m.longval = str2long(m.longstr) | * m.longval = str2long(m.longstr) | ||
Line 326: | Line 326: | ||
PARAMETERS m.FilName | PARAMETERS m.FilName | ||
m.FilName = ALLTRIM(UPPER(m.FilName)) | m.FilName = ALLTRIM(UPPER(m.FilName)) | ||
IF | IF "\" $ m.FilName | ||
m.FilName = SUBSTR(m.FilName,1,RAT( | m.FilName = SUBSTR(m.FilName,1,RAT("\",m.FilName)) | ||
IF RIGHT(m.FilName,1) = | IF RIGHT(m.FilName,1) = "\" AND LEN(m.FilName) > 1 ; | ||
AND SUBSTR(m.FilName,LEN(m.FilName)-1,1) <> | AND SUBSTR(m.FilName,LEN(m.FilName)-1,1) <> ":" | ||
FilName = SUBSTR(m.FilName,1,LEN(m.FilName)-1) | FilName = SUBSTR(m.FilName,1,LEN(m.FilName)-1) | ||
ENDIF | ENDIF | ||
RETURN m.FilName | RETURN m.FilName | ||
ELSE | ELSE | ||
RETURN | RETURN "" | ||
ENDIF | ENDIF | ||
FUNCTION JUSTEXT | FUNCTION JUSTEXT | ||
* Return just the extension from | * Return just the extension from "filname" | ||
PARAMETERS m.FilName | PARAMETERS m.FilName | ||
PRIVATE m.ext | PRIVATE m.ext | ||
m.FilName = JUSTFNAME(m.FilName) && prevents problems with ..\ paths | m.FilName = JUSTFNAME(m.FilName) && prevents problems with ..\ paths | ||
m.ext = | m.ext = "" | ||
IF AT( | IF AT(".", m.FilName) > 0 | ||
m.ext = SUBSTR(m.FilName, AT( | m.ext = SUBSTR(m.FilName, AT(".", m.FilName) + 1, 3) | ||
ENDIF | ENDIF | ||
RETURN UPPER(m.ext) | RETURN UPPER(m.ext) | ||
FUNCTION JUSTFNAME | FUNCTION JUSTFNAME | ||
* Return just the filename (i.e., no path) from | * Return just the filename (i.e., no path) from "filname" | ||
PARAMETERS m.FilName | PARAMETERS m.FilName | ||
IF RAT( | IF RAT("\",m.FilName) > 0 | ||
m.FilName = SUBSTR(m.FilName,RAT( | m.FilName = SUBSTR(m.FilName,RAT("\",m.FilName)+1,255) | ||
ENDIF | ENDIF | ||
IF AT( | IF AT(":",m.FilName) > 0 | ||
m.FilName = SUBSTR(m.FilName,AT( | m.FilName = SUBSTR(m.FilName,AT(":",m.FilName)+1,255) | ||
ENDIF | ENDIF | ||
RETURN ALLTRIM(UPPER(m.FilName)) | RETURN ALLTRIM(UPPER(m.FilName)) | ||
Line 363: | Line 363: | ||
PARAMETER m.pathname | PARAMETER m.pathname | ||
PRIVATE m.separator | PRIVATE m.separator | ||
m.separator = IIF(_MAC, | m.separator = IIF(_MAC,":","\") | ||
m.pathname = ALLTRIM(UPPER(m.pathname)) | m.pathname = ALLTRIM(UPPER(m.pathname)) | ||
IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname) | IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname) | ||
Line 428: | Line 428: | ||
</div> | </div> | ||
Microsoft FoxPro Help, topic: | Microsoft FoxPro Help, topic: "LUPDATE() Function"<br /> | ||
<br /> | <br /> | ||
Microsoft FoxPro Help, topic: | Microsoft FoxPro Help, topic: "FDATE() Function"<br /> | ||
<br /> | <br /> | ||
Microsoft FoxPro Help, topic: | Microsoft FoxPro Help, topic: "ADIR() Function" | ||
</div> | </div> |
Latest revision as of 13:51, 21 July 2020
Article ID: 250300
Article Last Modified on 5/10/2003
APPLIES TO
- Microsoft FoxPro 2.0
- Microsoft FoxPro 2.5b for MS-DOS
- Microsoft FoxPro 2.5a
- Microsoft FoxPro 2.5b for MS-DOS
- Microsoft FoxPro 2.6 for MS-DOS
- Microsoft FoxPro 2.6a Standard Edition
- Microsoft FoxPro 2.5b
- Microsoft FoxPro 2.5a
- Microsoft FoxPro 2.5b
- Microsoft FoxPro 2.6 Standard Edition
- Microsoft FoxPro 2.6a Standard Edition
- Microsoft Visual FoxPro 3.0 Standard Edition
- Microsoft Visual FoxPro 3.0b Standard Edition
- Microsoft Visual FoxPro 5.0 Standard Edition
- Microsoft Visual FoxPro 5.0a
- Microsoft FoxPro 2.5b for Macintosh
- Microsoft Visual FoxPro 2.5c for Macintosh
- Microsoft FoxPro 2.6a Professional Edition for Macintosh
- Microsoft Visual FoxPro 3.0 for Macintosh
- Microsoft FoxPro 2.6 for SCO/UNIX
This article was previously published under Q250300
SYMPTOMS
The FoxPro DIR command returns the century portion of the date in the Last Update column as 19xx for any table modified after 12/31/1999.
CAUSE
The date of the last update is stored in the header of the .dbf file. The DIR command looks at the table header to retrieve the last update information. Because this information is stored in YYMMDD format, FoxPro can not determine the century and assumes the 1900s.
RESOLUTION
Two possible workarounds are described in this section. The first workaround uses the ADIR function to provide basic information about the tables. This code can be modified to return information on all files and not just FoxPro tables. Copy this code into a program and execute it:
nCnt=ADIR(aFileList,"*.DBF") FOR x = 1 TO nCnt ? aFileList[x,1], aFileList[x,2], aFileList[x,3] ENDFOR
The second code example provides a more extensive workaround that also uses the ADIR function. Copy the code sample into a program named Zdir.prg and run it with one of the following commands:
DO Zdir
-or-
DO Zdir with "*.DBF"
-or-
=Zdir("*.DBF")
To retrieve a list of any file type, use the following syntax:
DO Zdir WITH "*.*"
Here is the code sample:
PARAMETERS cFileMask * Output strings PRIVATE cFileName, cRecCount, cFileDate, cFileSize * Environment Settings PRIVATE cSetTalk, cSetEscape, cOnError, cSetResource PRIVATE nFileCnt, nFileSize, cReadStr, x, hdl, nIdx, lVFP, cByte1, cTempAlias, cFileToOpen PRIVATE nCol, nSRows, nSCols, cJustPath, lDBF, nLen, aFileList[1], nTableType, nCnt PRIVATE lCancel IF SET('TALK') = "ON" SET TALK OFF cSetTalk = "ON" ELSE cSetTalk = "OFF" ENDIF cOnError = ON("ERROR") cSetEscape = SET('ESCAPE') SET ESCAPE OFF cSetResource = SET('RESOURCE') SET RESOURCE OFF * Status of the cancel key lCancel = .F. * Used for scaling the rows and columns to the current desktop nSRows = SROWS() nSCols = SCOLS() * Is this VFP - used in determining table type on Fox 2.x lVFP = ( "VISUAL" $ UPPER(VERSION()) ) IF TYPE("cFileMask") <> "C" cFileMask = "*.dbf" ENDIF cJustPath = JUSTPATH(cFileMask) * Set the path to either the path passed in or the current folder cJustPath = ADDBS(IIF(EMPTY(cJustPath), SYS(5) + SYS(2003), cJustPath)) lDBF = ( UPPER(JUSTEXT(cFileMask)) = "DBF" ) nFileCnt = ADIR(aFileList, cFileMask) IF nFileCnt = 0 DIMENSION aFileList[1,5] nFileSize = 0 ELSE *** NOTE -- DIR puts '_' first, ASORT puts "_" last =ASORT(aFileList) ENDIF nFileSize = 0 nCol = 0 ? && Start with a blank line IF lDBF ? "Database Table/DBF files" ?? " # Records" AT 25 ?? "Last Update" AT 37 ?? " Size" AT 50 ENDIF IF nFileCnt = 0 ? "None" ENDIF cTempAlias = SYS(2015) FOR x = 1 TO nFileCnt cFileName = aFileList[x,1] cFileToOpen = ALLTRIM(cJustPath + cFileName) cFileDate = PADL(DTOC(aFileList[x,3]), 11) IF lDBF hdl = FOPEN(cFileToOpen, 0) IF hdl > 0 * Nobody has the table exclusive, so check the header for record count cByte1 = dec2hex(str2long(FREAD(hdl, 1))) && Table type cReadStr = "" FOR nCnt = 7 TO 4 STEP -1 nIdx = FSEEK(hdl, nCnt, 0) cReadStr = cReadStr + dec2hex(str2long(FREAD(hdl, 1))) ENDFOR cRecCount = PADL(STR(Hex2Dec(cReadStr)), 10) && Convert the Hex string to numeric and then format =FCLOSE(hdl) * Check to see if the table is Fox 2.x or VFP or Not a table DO CASE CASE INLIST(cByte1, "02", "03", "43", "63", "83", "8B", "CB", "F5", "FB") * FoxPro 2.x table nTableType = 1 CASE INLIST(cByte1, "30") * Visual FoxPro Table nTableType = 2 OTHERWISE * Not a table nTableType = 0 ENDCASE IF nTableType = 0 ; OR (nTableType = 2 AND NOT lVFP) cFileName = cFileName + " Not a Fox database" cRecCount = "" ENDIF ELSE * File cannot be opened at all. cRecCount = "Can't read file" cFileDate = "" ENDIF cFileSize = PADL(STR(aFileList[x,2]), 11) ? cFileName ?? cRecCount AT 25 ?? cFileDate AT 37 ?? cFileSize AT 50 ELSE * Format the output to fit columns on the desktop. IF nCol = 0 ? cFileName AT nCol*14 ELSE ?? cFileName AT nCol*14 ENDIF nLen = INT(LEN(ALLTRIM(cFileName)) / 13) IF nLen > 0 nCol = nCol + nLen ENDIF nCol = IIF((nCol + 2) * 14 > nSCols, 0, nCol + 1) ENDIF nFileSize = nFileSize + aFileList[x,2] IF INT(ROW()) >= INT(nSRows) - 2 ; AND nCol = 0 WAIT WINDOW lCancel = ( LASTKEY() = 27 ) && User hit the escape key IF NOT lCancel CLEAR ENDIF ENDIF IF lCancel EXIT ENDIF ENDFOR IF lCancel ? "*** INTERRUPTED ***" ELSE ? ? TRANSFORM(nFileSize, "999999999") + " bytes in " + ALLTRIM(STR(nFileCnt)) + " files." ? TRANSFORM(DISKSPACE(), "999999999") + " bytes remaining on drive." ENDIF IF cSetTalk = "ON" SET TALK ON ENDIF IF cSetEscape = "ON" SET ESCAPE ON ENDIF IF cSetResource = "ON" SET RESOURCE ON ENDIF RETURN "" FUNCTION Hex2Dec ****************************************************************************** * passed: 1-byte integer (up to 255) * returns: 1-byte hex string (up to FF) * example: * nDecimal = 111 * cHex = dec2hex(nDecimal) returns "6F" PARAMETER cHexStr PRIVATE nDecimal cHexStr = UPPER(cHexStr) nDecimal = 0 FOR i=1 TO LEN(cHexStr) nDecimal = nDecimal + IIF(ISDIGIT(SUBSTR(cHexStr, i, 1)), ; VAL(SUBSTR(cHexStr, i, 1)), ; ASC(SUBSTR(cHexStr, i, 1)) - ASC('A') + 10) * 16 ^ (LEN(cHexStr) - i) ENDFOR RETURN nDecimal FUNCTION dec2hex ****************************************************************************** * passed: 1-byte integer (up to 255) * returns: 1-byte hex string (up to FF) * example: * nDecimal = 111 * cHex = dec2hex(nDecimal) returns "6F" PARAMETER nDecimal PRIVATE cBit1, cBit2, cHexStr cBit1 = INT(nDecimal/16) cBit2 = nDecimal - (cBit1 * 16) cHexStr = CHR(IIF(cBit1 > 9, 55, 48) + cBit1) + ; CHR(IIF(cBit2 > 9, 55, 48) + cBit2) RETURN cHexStr FUNCTION str2long ****************************************************************************** * passed: 4-byte character string (m.longstr) in low-high ASCII format * returns: long integer value * example: * m.longstr = "1111" * m.longval = str2long(m.longstr) PARAMETERS cLongStr PRIVATE i, nDecimal nDecimal = 0 FOR i = 0 TO 24 STEP 8 nDecimal = nDecimal + (ASC(cLongStr) * (2^i)) cLongStr = RIGHT(cLongStr, LEN(cLongStr) - 1) NEXT RETURN nDecimal FUNCTION JUSTPATH * Returns just the pathname. PARAMETERS m.FilName m.FilName = ALLTRIM(UPPER(m.FilName)) IF "\" $ m.FilName m.FilName = SUBSTR(m.FilName,1,RAT("\",m.FilName)) IF RIGHT(m.FilName,1) = "\" AND LEN(m.FilName) > 1 ; AND SUBSTR(m.FilName,LEN(m.FilName)-1,1) <> ":" FilName = SUBSTR(m.FilName,1,LEN(m.FilName)-1) ENDIF RETURN m.FilName ELSE RETURN "" ENDIF FUNCTION JUSTEXT * Return just the extension from "filname" PARAMETERS m.FilName PRIVATE m.ext m.FilName = JUSTFNAME(m.FilName) && prevents problems with ..\ paths m.ext = "" IF AT(".", m.FilName) > 0 m.ext = SUBSTR(m.FilName, AT(".", m.FilName) + 1, 3) ENDIF RETURN UPPER(m.ext) FUNCTION JUSTFNAME * Return just the filename (i.e., no path) from "filname" PARAMETERS m.FilName IF RAT("\",m.FilName) > 0 m.FilName = SUBSTR(m.FilName,RAT("\",m.FilName)+1,255) ENDIF IF AT(":",m.FilName) > 0 m.FilName = SUBSTR(m.FilName,AT(":",m.FilName)+1,255) ENDIF RETURN ALLTRIM(UPPER(m.FilName)) FUNCTION ADDBS * Add a backslash unless there is one already there. PARAMETER m.pathname PRIVATE m.separator m.separator = IIF(_MAC,":","\") m.pathname = ALLTRIM(UPPER(m.pathname)) IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname) m.pathname = m.pathname + m.separator ENDIF RETURN m.pathname
STATUS
Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.
MORE INFORMATION
Steps to Reproduce the Behavior
- Change the system date of the computer to 02/01/2000. The specific date is not critical as long as the year is 2000 or later.
In the FoxPro Command window, type the following without the comments:
SET CENTURY ON USE <tablename> && Name of the table. APPEND BLANK && Appends a blank record to the table.DIR USE && This closes the table. DIR
An incorrect answer is listed for the modified table: 02/01/1900.
NOTE: Remember to reset the system date of your computer back to today.
REFERENCES
For additional information about the LUPDATE(), the FDATE(), and the ADIR() functions, click the article numbers below to view the articles in the Microsoft Knowledge Base:
176481 FIX: LUPDATE() Does Not Report Correct Century for Year 2000
130165 PRB: LUPDATE() Does Not Return Date of Last Update
113943 INFO: New and Enhanced Commands and Functions in FoxPro Ver 2.6
100554 INFO: Using ADIR() Function to Obtain MS-DOS File Information
Microsoft FoxPro Help, topic: "LUPDATE() Function"
Microsoft FoxPro Help, topic: "FDATE() Function"
Microsoft FoxPro Help, topic: "ADIR() Function"
Additional query words: Y2K DIR
Keywords: kbxbase kbcodesnippet kbprb kbpending KB250300