jrm@cblpe.ATT.COM (John Miller) (02/11/88)
Hi, in a UNIX environment (using the 'C' language), it is possible to "open" a directory. The result is a list of the files that are in the particular directory - very straightforward. I would like obtain a list of files that are in a DOS directory using Microsoft 'C', version 4 or 5. Near as I can tell, you are not permitted to "open" a directory in dos. Further, I have not been able to find a function in the MSC library, or a function in the DOS or BIOS library that will permit me to find out what files are in a given directory. This seems like a gross oversight on Microsoft's part. The best method I know of so far (and this is more of an attack plan than a sure and tried solution) - is to use a DOS interrupt function to gain information about the FAT. From that information, I should be able to calculate the location, on disk, of the beginning sector containing the DOS directory table. Once in the table, I should be able to traverse through the chains to find all the files that are in the directory I am interested in. Yuuck! There has to be a better way! I could see where, after weeks of work, I could make this scheme work - for all disk types and formats. The price is very high! Does anyone know of a better way? More direct? I would be more that willing to attach an assembler routine to the 'C' product I am building (I have 2 already part of the product). But from what I can tell, there is nothing available anywhere, at any level that can help - have I overlooked something? -- J.R. Miller, AT&T Bell Labs, Columbus, OH CB 1C-339 (614) 860-4314 ihnp4!cblpe!jrm
psfales@ihlpe.ATT.COM (Pete Fales) (02/12/88)
In article <902@cblpe.ATT.COM>, jrm@cblpe.ATT.COM (John Miller) writes: > I would like obtain a list of files that are in a DOS directory using > Microsoft 'C', version 4 or 5. Near as I can tell, you are not permitted > to "open" a directory in dos. Further, I have not been able to find a > function in the MSC library, or a function in the DOS or BIOS library > that will permit me to find out what files are in a given directory. > > The best method I know of so far (and this is more of an attack plan than > a sure and tried solution) - is to use a DOS interrupt function to gain > information about the FAT. From that information, I should be able to > calculate the location, on disk, of the beginning sector containing > the DOS directory table. Once in the table, I should be able to traverse > through the chains to find all the files that are in the directory I > am interested in. There is a better way! Some compilers have library routines to do this (my Ecosoft compiler, for example) but that doesn't help you much if yours doesn't. Take a look at the DOS functions "find first" and "find next." These functions take a complete path name (including wild cards) and return all files that match the template. If you give it a path name terminating in *.*, it will find all the files in the directory. There are bits you can set in the paramter block to include/exclude subdirectories and hidden or system files. This should do what you want in a much more device independent manner. Pete -- Peter Fales UUCP: ...ihnp4!ihlpe!psfales work: (312) 979-7784 AT&T Information Systems, IW 1Z-243 1100 E. Warrenville Rd., IL 60566
allbery@axcess.UUCP (Brandon S. Allbery) (02/17/88)
In article <902@cblpe.ATT.COM>, jrm@cblpe.ATT.COM (John Miller) writes: +--------------- | Hi, in a UNIX environment (using the 'C' language), it is possible to "open" | a directory. The result is a list of the files that are in the particular | directory - very straightforward. | | I would like obtain a list of files that are in a DOS directory using | Microsoft 'C', version 4 or 5. Near as I can tell, you are not permitted | to "open" a directory in dos. Further, I have not been able to find a | function in the MSC library, or a function in the DOS or BIOS library | that will permit me to find out what files are in a given directory. +--------------- First -- System V allows you to open a directory as a file, and acts as you say. While you can open a BSD directory as a file, it's less than useful; so there are special directory-reading calls available. These have been ported to System V and even to DOS; they went through comp.sources.misc a few months ago. Second -- You can emulate directory reading by using the "find first" and "find next" system calls (DOS FC 4EH and 4FH, respectively) with a filename of "*.*". This is how the BSD-compatible library is done. -- ___ ________________, Brandon S. Allbery cbosgd \ ' \/ __ __, __, aXcess Company mandrill| __ | /__> <__ <__ 6615 Center St. #A1-105 !ncoast! / ` | \__. .__> .__> Mentor, OH 44060-4101 necntc | axcess!allbery \___/\________________. Moderator, comp.sources.misc hoptoad/
mouse@mcgill-vision.UUCP (der Mouse) (03/14/88)
In article <902@cblpe.ATT.COM>, jrm@cblpe.ATT.COM (John Miller) writes: > I would like obtain a list of files that are in a DOS directory using > Microsoft 'C', version 4 or 5. > The best method I know of so far [...] is to use a DOS interrupt > function to gain information about the FAT. [and then read the disk > to find the directory] One of the DOS interrupts expands a wildcard name. Tell it to expand *.* and you should get a list of everything. (Actually, one entry tells it "get the first name matching this" and another says "get the next name matching the last thing I told you to look for", as I recall.) Unfortunately, the match routine is rather badly broken. Asking for *C.*, for example, will return the same thing as *.*, regardless of whether the names in the directory contain `C'. Or at least it did for me. But for what you are doing, it should work to just give *.*. der Mouse uucp: mouse@mcgill-vision.uucp arpa: mouse@larry.mcrcim.mcgill.edu
jep@oink.UUCP (James E. Prior) (03/26/88)
In article <1001@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >In article <902@cblpe.ATT.COM>, jrm@cblpe.ATT.COM (John Miller) writes: >> I would like obtain a list of files that are in a DOS directory using >> Microsoft 'C', version 4 or 5. Sample code is included further down in this article. I don't remember whether it was for Turbo C or usoft C. It's very similar either way. >> The best method I know of so far [...] is to use a DOS interrupt >> function to gain information about the FAT. [and then read the disk >> to find the directory] > >One of the DOS interrupts expands a wildcard name. Tell it to expand >*.* and you should get a list of everything. (Actually, one entry >tells it "get the first name matching this" and another says "get the >next name matching the last thing I told you to look for", as I >recall.) Unfortunately, the match routine is rather badly broken. >Asking for *C.*, for example, will return the same thing as *.*, >regardless of whether the names in the directory contain `C'. Or at >least it did for me. But for what you are doing, it should work to >just give *.*. MS-DOS (and its predecessor CP/M) treat wildcard characters differently than UNIX. This has bitten many a programmer learning one after the other. MS-DOS and CP/M filenames have a first name and a last name. The first name can be up to eight characters. The last name can be up to three characters long. The dot is always present whether you like it or not. i.e. writing to file "abcd" will be the same as file "abcd." . An asterisk will match any character (including void chars) from its position in a name until the end of that name. The first name is treated separately from the last name in this matter. Here's the code a friend gave me to do wildcard searches on a PC. I've never used it, so don't ask me anything about it. Instead ask Steve Crawford {ihnp4|osu-cis}!n8emr!oink!snc about it. File readme.jim: *********************************************************** Hey, find_first and find_next are in file find3.asm dofind.c is a little test program I wrote to see that it does indeed work. Note in the beginning of find3.asm the db string called "fcb". This is where the search pattern is defined; the ????????ASM matching all files of type .ASM. You must change this to be whatever you want. There's probably a better way to do search patterns (like passing a search string to the find_ routines), but this is exactly what I needed for my purposes. If either find_first or find_next don't find anything, they return a 0. The find_ routines were written for assembly under Microsoft Macro Assembler V4.0 (or something like that). The C program is for msc. Enjoy, and remember me in your will. Thanks for your help!!! c'bag File dofind.c: ************************************************************* #include <stdio.h> #include <string.h> char *fnames[20]; main() { int i; char *ff,*sf; /* storage for file names */ char *malloc(),*find_first(), *find_next(); sf=malloc(13); ff=find_first(); strcpy(sf,ff); fnames[0]=sf; for(i=1; (ff=find_next()); i++) { sf=malloc(13); /* get pointer to string */ strcpy(sf,ff); /* copy file name */ fnames[i]=sf; /* store pointer */ } for(i=0; (fnames[i]); i++) { printf("file %d = %s\n", i, fnames[i]); } } File find3.asm: ************************************************************** ; ; find3.asm - find a file in the current directory ; 1/29/88 snc ; ; This is the third attempt. This routine is callable from C, fills ; an external array with the found names, and returns a pointer to the ; last array element filled. ; DGROUP GROUP _DATA ASSUME DS:DGROUP _DATA SEGMENT WORD PUBLIC 'DATA' sf db "NOT FOUND ON INT 11.$" no db "FILE DOES NOT EXIST.$" fcb db 0,"????????ASM" db 25 dup(?) buffer db 128 dup(?) fbuf db 12 dup(?) ;file name buffer _DATA ENDS P_ENTER MACRO PUSH BP MOV BP,SP push si push di PUSH ES push ds mov ax,DGROUP mov ds,ax ENDM P_EXIT MACRO pop ds POP ES pop di pop si mov sp,bp POP BP ENDM _TEXT SEGMENT BYTE PUBLIC 'CODE' ASSUME CS:_TEXT PUBLIC _find_first, _find_next _find_first PROC NEAR P_ENTER lea dx,buffer ;create a DTA mov ah,1ah ;set DTA function int 21h lea dx,fcb ;do the search mov ah,11h int 21h cmp al,0ffh ;find it? jz short not_found ;exit if not call output ;else, fix up file name lea ax,fbuf jmp short done not_found: xor ax,ax ;if no match, return 0 done: P_EXIT ret _find_first ENDP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _find_next PROC NEAR P_ENTER lea dx,fcb mov ah,12h ;get next file int 21h cmp al,0ffh ;no more files? jz short no_more ;exit routine if so call output lea ax,fbuf jmp short go_back no_more: xor ax,ax ;if no files, return 0 go_back: P_EXIT ret _find_next ENDP ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; output PROC NEAR mov si,1 lea bx,buffer lea di,fbuf outchar: mov dl,[bx][si] cmp dl,20h ;blank space? jz short skip ;skip it if so mov [di],dl ;store character inc di skip: inc si cmp si,9 ;9 is 8 characters later from starting si jz short period jmp short outchar period: mov dl,2eh ;a period mov [di],dl ;store character inc di outext: mov dl,[bx][si] mov [di],dl ;store character inc di inc si cmp si,12 jnz short outext mov [di],byte ptr 00 ;null terminate string ret output ENDP _TEXT ENDS END End of files **************************************************************** Remember to thank/flame Steve Crawford for the code. -- Jim Prior {ihnp4|osu-cis}!n8emr!oink!jep jep@oink.UUCP Pointers are my friend.
jwg@duke.cs.duke.edu (Jeffrey William Gillette) (03/28/88)
[] Actually, reading a DOS directory is a bit more involved than simply setting up a set of Find First / Find Next calls (int 21h, AH = 4Eh / 4Fh). Whoever set up the Find First / Find Next interface (perhaps a disgruntled employee in his last week at Microsoft :-) decided that the logical portion of memory to exchange directory information was the Disk Transfer Area (DTA - starts out as bytes 80h - FFh in the Program Segment Prefix). Since your compiler may well change the location of the DTA, you will need to get the current Disk Transfer Address (int 21h, AH = 2Fh) and declare a data structure like "FCB far *fcb = dta_address". FCB is the File Control Block which DOS will set up, but expects *you* to keep track of! If you intend to do any disk activity while searching the directory, you will need to assume responsibility for the integrity of the FCB buffer. You will need either to preserve a copy of the FCB after each Find First / Find Next call (and place a current image of the FCB in the DTA immediately before the next call), or you will need to change the DTA temporarily every time you make a Find First / Find Next call. N.B. Perhaps this mess is the reason Microsoft didn't bother including a reasonable directory search routine in Windows 1.x. Given the obvious dangers in playing with the Disk Transfer Address in a quasi- multitasking environment, I sent a TAR to Microsoft. The response translated to, "We're going to bury our heads in the sand until the problem goes away, or until we can't ignore it any longer." Peace, Jeff Jeffrey William Gillette uucp: jwg at duke.edu Duke University bitnet: DYBBUK at TUCCVM -- Jeffrey William Gillette uucp: jwg at duke.edu Duke University bitnet: DYBBUK at TUCCVM
leonard@bucket.UUCP (Leonard Erickson) (03/28/88)
In article <1001@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
<recall.) Unfortunately, the match routine is rather badly broken.
<Asking for *C.*, for example, will return the same thing as *.*,
<regardless of whether the names in the directory contain `C'. Or at
It is behaving correctly. MS-DOS wildcards are not like UNIX wildcards.
"*" is translated as "fill rest of [filename,extension] with "?". So
*C* becomes ???????.
anything after a * is ignored...
--
Leonard Erickson ...!tektronix!reed!percival!bucket!leonard
CIS: [70465,203]
"I used to be a hacker. Now I'm a 'microcomputer specialist'.
You know... I'd rather be a hacker."
des@uucsbb.UUCP (Don Shope) (04/01/88)
In article <902@cblpe.ATT.COM>, jrm@cblpe.ATT.COM (John Miller) writes: > I would like obtain a list of files that are in a DOS directory using > Microsoft 'C', version 4 or 5. > > The best method I know of so far [...] is to use a DOS interrupt > function to gain information about the FAT. [and then read the disk > to find the directory] > Following is a little program I wrote to illustrate the use of two new functions in level 5.0 of the Microsoft C compiler: /* Directory functions. The second argument to _dos_findfirst() * specifies the necessary attributes needed for a file to be * selected (whose name also matches the pattern). Values * for attribute are: _A_NORMAL, _A_RDONLY, _A_HIDDEN, _A_SYSTEM, * _A_VOLID, _A_SUBDIR, _A_ARCH (which can be or'd together). * Return value is 0 upon success, errno is set on failure to ENOENT. * * Following is the function prototype and struct definition: * * unsigned _dos_findfirst(path,attributes,buffer); * unsigned _dos_findnext(buffer); * char *path; - target filename (* and ? allowed) * unsigned attributes; - target attributes * struct find_t { * char reserved[21]; - reserved for use by MS-DOS * char attrib; - attribute byte for matched path * unsigned wr_time; - Time of last write to file * unsigned wr_date; - Date of last write to file * long size; - Length of file in bytes * char name[13]; - filename/directory name * } *buffer; */ #include <dos.h> main(argc, argv) int argc; char *argv[]; { struct find_t dosfile; char pattern[81]; if( argc != 2 ) { printf( "Enter DOS search pattern: " ); scanf( "%s", pattern ); } else strcpy( pattern, argv[1] ); printf( "Directory listing of '%s':\n\n", pattern ); if( _dos_findfirst( pattern, _A_NORMAL, &dosfile ) == 0 ) { printf( "Size: %6ld File: %s\n", dosfile.size, dosfile.name ); while( _dos_findnext( &dosfile ) == 0 ) printf( "Size: %6ld File: %s\n", dosfile.size, dosfile.name ); } else printf( "Pattern '%s' not found.\n", pattern ); } I hope this helps you out. Also, I am a new user, and I hope I have done things correctly in this posting.