Q41447: QB 4.x Example to Load MS-DOS Directory Listing into an Array
Article: Q41447
Product(s): See article
Version(s): 4.00 4.00b 4.50
Operating System(s): MS-DOS
Keyword(s): ENDUSER | B_BasicCom | mspl13_basic
Last Modified: 15-JAN-1991
This article discusses three methods to put an MS-DOS disk directory
listing into a string array. This article applies to Microsoft
QuickBASIC versions 4.00, 4.00b, and 4.50 for MS-DOS, to Microsoft
BASIC Compiler versions 6.00 and 6.00b for MS-DOS, and to Microsoft
BASIC Professional Development System (PDS) versions 7.00 and 7.10 for
MS-DOS and MS OS/2.
Example 1 shows a simple method to SHELL to the MS-DOS DIR command,
redirect the output to a file, and input from the file into string
variables.
Example 2 shows how to use the CALL INTERRUPT routine to invoke MS-DOS
function calls (SetDTA, FindFirst, and FindNext) to retrieve a disk
directory into string variables in a compiled BASIC program.
A third method is to use the DIR$ function introduced in Microsoft
BASIC PDS version 7.00/7.10 for MS-DOS and MS OS/2. For an example of
using the DIR$ function (which works both in MS-DOS and MS OS/2),
search for a separate article by querying on the following words:
7.00 and "DIR$" and DIRECTORY and LISTING
For an example of calling the MS-DOS interrupt functions to obtain
disk directory information in QuickBASIC Version 2.00, 2.01, or 3.00,
query on the following words:
INT86.OBJ and FINDFIRST
For a Microsoft BASIC PDS 7.00 or 7.10 or BASIC compiler version 6.00
or 6.00b example that displays directory information in MS OS/2
protected mode, query on the following words:
DosFindFirst or DosFindNext
Example 1 (a technique simpler than the next example)
---------
' Works in QuickBASIC 2.00, 2.01, 3.00, 4.00, 4.00b, 4.50, and
' Microsoft BASIC Compiler 6.00 and 6.00b, and BASIC PDS 7.00, 7.10
nf = 200 ' Handles directory listing up to 200 lines.
DIM buffer$(nf)
INPUT "Enter Search Path: ", path$ ' Enter path such as c:
SHELLSTRING$ = "dir " + path$ + " >dirfile.dat"
SHELL SHELLSTRING$ ' SHELL to the MS-DOS DIRectory command.
OPEN "dirfile.dat" FOR INPUT AS #1
pntr% = 0
WHILE NOT EOF(1) AND pntr% < nf
pntr% = pntr% + 1
INPUT #1, buffer$(pntr%) ' Inputs one directory line at a time.
PRINT buffer$(pntr%)
WEND
CLOSE #1
KILL "dirfile.dat"
END
Example 2
---------
Example 2 below shows how to load an MS-DOS disk directory listing
into a string array, using the CALL INTERRUPT statement to invoke the
MS-DOS operating-system interrupt 21 hex, with functions 1A hex
(SetDTA), 4E hex (FindFirst), and 4F hex (FindNext). Example 2 below
applies to QuickBASIC versions 4.00, 4.00b, and 4.50 and Microsoft
BASIC Compiler versions 6.00 and 6.00b running under MS-DOS (or OS/2
real mode, which emulates DOS versions 3.x).
To make this example work in BASIC PDS 7.00, modify the Firstfm
FUNCTION in the example further below as follows:
1. DIM inreg AS RegTypex and outreg AS RegTypex
2. Change CALL INTERRUPT to CALL INTERRUPTX
3. Add the following line in between the assignment for inreg.dx and
the CALL INTERRUPTX: inreg.ds = SSEG(FileName$)
REM DIR.BAS
'$INCLUDE: 'QB.BI' '<-- look at what is in this file
' QB.BI contains the TYPE definitions for "Outreg" and "Inreg"
' and the declarations for both INTERRUPT and INTERRUPTX.
TYPE FileFindBuf
dos AS STRING * 21
Attributes AS STRING * 1
CreateTime AS INTEGER
AccessDate AS INTEGER
FileSize AS LONG
FileName AS STRING * 13
END TYPE
TYPE FileInfo
FileName AS STRING * 13
Size AS STRING * 8
Seconds AS STRING * 4
Minutes AS STRING * 4
Hours AS STRING * 4
Day AS STRING * 4
Month AS STRING * 4
Year AS STRING * 5
END TYPE
DIM BUFFER AS FileFindBuf
DIM FileInfoBlock(100) AS FileInfo
DECLARE SUB intbuf (BUFFER AS FileFindBuf)
DECLARE SUB setdta (BUFFER AS FileFindBuf)
DECLARE FUNCTION firstfm! (path$, fa%)
DECLARE FUNCTION nextfm ()
DECLARE SUB CalculateAssign (FileInfoBlock() AS ANY, BUFFER AS ANY,_
counter!)
DECLARE SUB PrintDirList (FileInfoBlock() AS ANY, i!)
CLS : CALL setdta(BUFFER)
INPUT "Enter the files spec: "; path$
fa% = 0 ' A value of 16 includes directory names.
counter = 0
IF (firstfm(path$, fa%) = 0) THEN
DO
counter = counter + 1
CalculateAssign FileInfoBlock(), BUFFER, counter
CALL setdta(BUFFER)
LOOP WHILE (nextfm = 0)
END IF
CLS
FOR i = 1 TO counter
PrintDirList FileInfoBlock(), i
NEXT i
END
SUB CalculateAssign (FileInfoBlock() AS FileInfo, _
BUFFER AS FileFindBuf, counter)
FileInfoBlock(counter).FileName = BUFFER.FileName
FileInfoBlock(counter).Size = STR$(BUFFER.FileSize)
FileInfoBlock(counter).Seconds = STR$(BUFFER.CreateTime AND &H1F)
FileInfoBlock(counter).Minutes = _
STR$((BUFFER.CreateTime AND &H7E0) \ 32)
'If BUFFER.CreateTime is negative add 64K to make unsigned integer:
IF BUFFER.CreateTime < 0 THEN
FileInfoBlock(counter).Hours = _
STR$(((BUFFER.CreateTime + 2 ^ 16) AND &HF800) \ 2048)
ELSE
FileInfoBlock(counter).Hours = _
STR$((BUFFER.CreateTime AND &HF800) \ 2048)
END IF
FileInfoBlock(counter).Day = STR$(BUFFER.AccessDate AND &H1F)
FileInfoBlock(counter).Month = _
STR$((BUFFER.AccessDate \ 32) AND &HF)
FileInfoBlock(counter).Year = _
STR$((BUFFER.AccessDate \ 512) + 1980)
END SUB
FUNCTION firstfm (path$, fa%)
DIM inreg AS regtype, outreg AS regtype '1. Use regtypex for BASIC 7.00
inreg.ax = &H4E00
inreg.cx = fa%
FileName$ = path$ + CHR$(0)
inreg.dx = SADD(FileName$)
' 2. Add this here for BASIC 7.00: inreg.ds=SSEG(FileName$)
CALL INTERRUPT (&H21, inreg, outreg) '3. Use INTERRUPTX in BASIC 7.00
firstfm = (outreg.ax AND &HF)
END FUNCTION
SUB intbuf (BUFFER AS FileFindBuf) STATIC
' The first 20 bytes are reserved for DOS and are unchanged
BUFFER.CreateTime = 0
BUFFER.Attributes = " "
BUFFER.AccessDate = 0
BUFFER.FileSize = 0
BUFFER.FileName = STRING$(13, 32)
END SUB
FUNCTION nextfm
DIM inreg AS regtype, outreg AS regtype
inreg.ax = &H4F00
CALL interrupt(&H21, inreg, outreg)
nextfm = outreg.ax AND &HF
END FUNCTION
SUB PrintDirList (FileInfoBlock() AS FileInfo, i)
PRINT FileInfoBlock(i).FileName;
PRINT TAB(15); FileInfoBlock(i).Size;
PRINT TAB(25); RTRIM$(LTRIM$(FileInfoBlock(i).Month)) + "-";
IF LEN(RTRIM$(LTRIM$(FileInfoBlock(i).Day))) = 1 THEN
FileInfoBlock(i).Day = "0" + LTRIM$(FileInfoBlock(i).Day)
END IF
PRINT RTRIM$(LTRIM$(FileInfoBlock(i).Day)) + "-";
PRINT RTRIM$(LTRIM$(FileInfoBlock(i).Year));
IF VAL(FileInfoBlock(i).Hours) = 0 THEN
FileInfoBlock(i).Hours = STR$(12) 'Change midnight from 0 to 12.
END IF
IF VAL(FileInfoBlock(i).Hours) > 12 THEN
x% = VAL(FileInfoBlock(i).Hours) - 12
FileInfoBlock(i).Hours = STR$(x%)
suffix$ = "p"
ELSE
suffix$ = "a"
END IF
IF VAL(FileInfoBlock(i).Hours) = 12 AND _
VAL(FileInfoBlock(i).Minutes) > 0 THEN suffix$ = "p"
IF LEN(RTRIM$(LTRIM$(FileInfoBlock(i).Hours))) = 1 THEN
t% = 39
ELSE
t% = 38
END IF
PRINT TAB(t%); RTRIM$(LTRIM$(FileInfoBlock(i).Hours)) + ":";
IF LEN(RTRIM$(LTRIM$(FileInfoBlock(i).Minutes))) = 1 THEN
FileInfoBlock(i).Minutes = "0" + LTRIM$(FileInfoBlock(i).Minutes)
END IF
PRINT RTRIM$(LTRIM$(FileInfoBlock(i).Minutes));
PRINT suffix$
END SUB
SUB setdta (BUFFER AS FileFindBuf) STATIC
DIM inreg AS regtypex, outreg AS regtypex
CALL intbuf(BUFFER)
inreg.ax = &H1A00
inreg.ds = VARSEG(BUFFER)
inreg.dx = VARPTR(BUFFER)
CALL interruptx(&H21, inreg, outreg)
END SUB
THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.
Copyright Microsoft Corporation 1986-2002.