From: Martin Stromberg Message-Id: <200110091305.PAA22981@lws256.lu.erisoft.se> Subject: Re: _findfirst() patch To: djgpp-workers AT delorie DOT com Date: Tue, 9 Oct 2001 15:05:05 +0200 (MET DST) In-Reply-To: <01e801c150bc$beb39b40$118824d5@zephyr> from "Eric Botcazou" at Oct 09, 2001 02:19:45 PM X-Mailer: ELM [version 2.5 PL3] MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Reply-To: djgpp-workers AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk > I've uploaded a patch again the CVS code of yesterday that adds the three > Watcom/MinGW/MSVC compatible _findfirst(), _findnext() and _findclose() > functions to the libc, as Eli Zaretskii suggested a few days ago on the > comp.os.msdos.djgpp newsgroup, at the address: > http://www.multimania.com/ebotcazou/dev/djgpp_findfirst.zip May I suggest you post the diffs yourself next time. It makes it much easier to discuss them. findfirst.diff: diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findclo.c /djgpp-cvs/src/libc/dos/io/_findclo.c --- /cvsroot/djgpp/src/libc/dos/io/_findclo.c Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findclo.c Tue Oct 9 11:36:30 2001 @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + +int +_findclose(long handle) +{ + __dpmi_regs r; + + if (_USE_LFN) { + + r.x.ax = 0x71a1; + r.x.bx = handle; + __dpmi_int(0x21, &r); + + if (!(r.x.flags & 1)) + return 0; + } + else { + + free((struct ffblk*)handle); + return 0; + } + + errno = __doserr_to_errno(r.x.ax); + return -1; +} + diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findclo.txh /djgpp-cvs/src/libc/dos/io/_findclo.txh --- /cvsroot/djgpp/src/libc/dos/io/_findclo.txh Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findclo.txh Tue Oct 9 11:52:16 2001 @@ -0,0 +1,21 @@ +@node _findclose, file system +@subheading Syntax + +@example +#include + +int _findclose(long handle); +@end example + +@subheading Description + +This closes the search started by @code{_findfirst}. + +@subheading Return Value + +Zero on success, -1 on error (and sets @var{errno}). + +@subheading Portability + +@portability !ansi, !posix + diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findfir.c /djgpp-cvs/src/libc/dos/io/_findfir.c --- /cvsroot/djgpp/src/libc/dos/io/_findfir.c Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findfir.c Tue Oct 9 10:29:10 2001 @@ -0,0 +1,113 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern time_t __dostime_to_time_t(unsigned short dosdate, unsigned short dostime); + +time_t __dostime_to_time_t(unsigned short dosdate, unsigned short dostime) +{ + struct tm t; + + memset(&t, 0, sizeof(struct tm)); + t.tm_sec = (dostime & 0x1F) * 2; + t.tm_min = (dostime >> 5) & 0x3F; + t.tm_hour = (dostime >> 11) & 0x1F; + t.tm_mday = (dosdate & 0x1F); + t.tm_mon = ((dosdate >> 5) & 0x0F) - 1; + t.tm_year = (dosdate >> 9) + 80; + t.tm_isdst = -1; + + return mktime(&t); +} + +long +_findfirst(const char *pathname, struct _finddata_t *fileinfo) +{ + __dpmi_regs r; + int pathlen; + + if (!pathname || !fileinfo) { + errno = EACCES; + return -1; + } + + pathlen = strlen(pathname) + 1; + _put_path(pathname); + + if (_USE_LFN) { + + r.x.ax = 0x714e; + r.x.cx = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_VOLID | _A_SUBDIR | _A_ARCH; + r.x.dx = __tb_offset; + r.x.ds = __tb_segment; + r.x.di = __tb_offset + pathlen; + r.x.es = r.x.ds; + r.x.si = 1; /* DOS style date */ + __dpmi_int(0x21, &r); + + if (!(r.x.flags & 1)) { + struct ffblklfn ffblk32; + + /* Recover results */ + dosmemget(__tb+pathlen, sizeof(struct ffblklfn), &ffblk32); + + fileinfo->attrib = (unsigned)ffblk32.fd_attrib; + fileinfo->time_create = __dostime_to_time_t(ffblk32.fd_ctime>>16, ffblk32.fd_ctime); + fileinfo->time_access = __dostime_to_time_t(ffblk32.fd_atime>>16, ffblk32.fd_atime); + fileinfo->time_write = __dostime_to_time_t(ffblk32.fd_mtime>>16, ffblk32.fd_mtime); + fileinfo->size = (_fsize_t)ffblk32.fd_size; + strcpy(fileinfo->name, ffblk32.fd_longname); + + return (long)r.x.ax; + } + } + else { + + #define _sizeof_dos_ffblk 44 + /* There will be a _sizeof_dos_ffblk character return value from findfirst + * in the DTA. Put the file name before this. First set the DTA to be + * transfer buffer. + */ + r.h.ah = 0x1a; + r.x.dx = __tb_offset + pathlen; + r.x.ds = __tb_segment; + __dpmi_int(0x21, &r); + + r.h.ah = 0x4e; + r.x.dx = __tb_offset; + r.x.ds = __tb_segment; + r.x.cx = _A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_VOLID | _A_SUBDIR | _A_ARCH; + __dpmi_int(0x21, &r); + + if (!(r.x.flags & 1)) { + struct ffblk *ffblk16 = malloc(_sizeof_dos_ffblk); + if (!ffblk16) { + errno = ENOMEM; + return -1; + } + + /* Recover results */ + dosmemget(__tb+pathlen, _sizeof_dos_ffblk, ffblk16); + + fileinfo->attrib = (unsigned)ffblk16->ff_attrib; + fileinfo->time_create = -1; + fileinfo->time_access = -1; + fileinfo->time_write = __dostime_to_time_t(ffblk16->ff_fdate, ffblk16->ff_ftime); + fileinfo->size = (_fsize_t)ffblk16->ff_fsize; + strcpy(fileinfo->name, ffblk16->ff_name); + + return (long)ffblk16; + } + } + + errno = __doserr_to_errno(r.x.ax); + return -1; +} diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findfir.txh /djgpp-cvs/src/libc/dos/io/_findfir.txh --- /cvsroot/djgpp/src/libc/dos/io/_findfir.txh Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findfir.txh Tue Oct 9 11:54:04 2001 @@ -0,0 +1,119 @@ +@node _findfirst, file system +@subheading Syntax + +@example +#include + +long _findfirst(const char *pathname, struct _finddata_t *fileinfo); +@end example + +@subheading Description + +This function and the related @code{_findnext} (@pxref{_findnext}) and +@code{_findclose} (@pxref{_findclose}) are used to scan directories for the +list of files therein. The @var{pathname} is a wildcard that specifies the +directory and files to search for (such as @code{subdir/*.c}) and +@var{fileinfo} is a structure to hold the results of the search. + +The results are returned in a @code{struct _finddata_t} defined in +@code{} as follows: + +@example +struct _finddata_t @{ + unsigned attrib; + time_t time_create; + time_t time_access; + time_t time_write; + _fsize_t size; + char name[260]; +@}; +@end example + +The @var{attrib} field is a combination of the following: + +@table @code + +@item _A_NORMAL (0x00) + +Normal file (no read/write restrictions) + +@item _A_RDONLY (0x01) + +Read only file + +@item _A_HIDDEN (0x02) + +Hidden file + +@item _A_SYSTEM (0x04) + +System file + +@item _A_VOLID (0x08) + +Volume ID file + +@item _A_SUBDIR (0x10) + +Subdirectory + +@item _A_ARCH (0x20) + +Archive file + +@end table + +This function supports long file names. + +@subheading Return Value + +If a match is found, @code{_findfirst} returns an unique handle identifying +the search that can be used in subsequent calls to @code{_findnext} and to +@code{_findclose}. Otherwise, @code{_findfirst} returns -1 (and sets +@var{errno}). + +@subheading Portability + +@portability !ansi, !posix + +@subheading Example + +@example +#include +#include + +struct _finddata_t fileinfo; +long handle; +char attrib_str[7], time_str[32]; +int c = 0; + +handle = _findfirst("*.dat", &fileinfo); + +if (handle<0) +@{ + printf("no matching file.\n"); +@} +else +@{ + do + @{ + attrib_str[0] = (fileinfo.attrib&_A_RDONLY ? 'r' : '-'); + attrib_str[1] = (fileinfo.attrib&_A_HIDDEN ? 'h' : '-'); + attrib_str[2] = (fileinfo.attrib&_A_SYSTEM ? 's' : '-'); + attrib_str[3] = (fileinfo.attrib&_A_VOLID ? 'l' : '-'); + attrib_str[4] = (fileinfo.attrib&_A_SUBDIR ? 'd' : '-'); + attrib_str[5] = (fileinfo.attrib&_A_ARCH ? 'a' : '-'); + attrib_str[6] = '\0'; + + strftime(time_str, sizeof(time_str), "%m/%d/%Y %H:%M ", localtime(&fileinfo.time_write)); + + printf("%-14s %5ld kb %s %s\n", fileinfo.name, 1 + fileinfo.size/1024, attrib_str, time_str); + + c++; + @} while (_findnext(handle, &fileinfo) == 0); + + _findclose(handle); + + printf("%d matching file%s\n", c, c>1 ? "s." : "."); +@} +@end example diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findnex.c /djgpp-cvs/src/libc/dos/io/_findnex.c --- /cvsroot/djgpp/src/libc/dos/io/_findnex.c Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findnex.c Tue Oct 9 10:29:26 2001 @@ -0,0 +1,84 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern time_t __dostime_to_time_t(unsigned short dosdate, unsigned short dostime); + +int +_findnext(long handle, struct _finddata_t *fileinfo) +{ + __dpmi_regs r; + + if (!fileinfo) { + errno = EACCES; + return -1; + } + + if (_USE_LFN) { + + r.x.ax = 0x714f; + r.x.bx = handle; + r.x.di = __tb_offset; + r.x.es = __tb_segment; + r.x.si = 1; /* DOS style date */ + __dpmi_int(0x21, &r); + + if (!(r.x.flags & 1)) { + struct ffblklfn ffblk32; + + /* Recover results */ + dosmemget(__tb, sizeof(struct ffblklfn), &ffblk32); + + fileinfo->attrib = (unsigned)ffblk32.fd_attrib; + fileinfo->time_create = __dostime_to_time_t(ffblk32.fd_ctime>>16, ffblk32.fd_ctime); + fileinfo->time_access = __dostime_to_time_t(ffblk32.fd_atime>>16, ffblk32.fd_atime); + fileinfo->time_write = __dostime_to_time_t(ffblk32.fd_mtime>>16, ffblk32.fd_mtime); + fileinfo->size = (_fsize_t)ffblk32.fd_size; + strcpy(fileinfo->name, ffblk32.fd_longname); + + return 0; + } + } + else { + + #define _sizeof_dos_ffblk 44 + /* The 43 character ff block must be put to the DTA, + * make the call, then recover the ff block. + */ + r.h.ah = 0x1a; + r.x.dx = __tb_offset; + r.x.ds = __tb_segment; + __dpmi_int(0x21, &r); + + dosmemput((struct ffblk *)handle, sizeof(struct ffblk), __tb); + + r.h.ah = 0x4f; + __dpmi_int(0x21, &r); + + if (!(r.x.flags & 1)) { + struct ffblk *ffblk16 = (struct ffblk *)handle; + + /* Recover results */ + dosmemget(__tb, _sizeof_dos_ffblk, ffblk16); + + fileinfo->attrib = (unsigned)ffblk16->ff_attrib; + fileinfo->time_create = -1; + fileinfo->time_access = -1; + fileinfo->time_write = __dostime_to_time_t(ffblk16->ff_fdate, ffblk16->ff_ftime); + fileinfo->size = (_fsize_t)ffblk16->ff_fsize; + strcpy(fileinfo->name, ffblk16->ff_name); + + return 0; + } + } + + errno = __doserr_to_errno(r.x.ax); + return -1; +} diff -Nu /cvsroot/djgpp/src/libc/dos/io/_findnex.txh /djgpp-cvs/src/libc/dos/io/_findnex.txh --- /cvsroot/djgpp/src/libc/dos/io/_findnex.txh Thu Jan 1 00:00:00 1970 +++ /djgpp-cvs/src/libc/dos/io/_findnex.txh Tue Oct 9 11:46:16 2001 @@ -0,0 +1,24 @@ +@node _findnext, file system +@subheading Syntax + +@example +#include + +int _findnext(long handle, struct _finddata_t *fileinfo); +@end example + +@subheading Description + +This finds the next file in the search started by @code{_findfirst}. +See @ref{_findfirst}, for the description of @code{struct _finddata_t}. + +This function supports long file names. + +@subheading Return Value + +Zero if a match is found, -1 if not found (and sets @var{errno}). + +@subheading Portability + +@portability !ansi, !posix + diff -Nu /cvsroot/djgpp/src/libc/dos/io/makefile /djgpp-cvs/src/libc/dos/io/makefile --- /cvsroot/djgpp/src/libc/dos/io/makefile Wed Mar 7 06:34:26 2001 +++ /djgpp-cvs/src/libc/dos/io/makefile Mon Oct 8 21:44:18 2001 @@ -8,6 +8,9 @@ SRC += _close.c SRC += _creat.c SRC += _creat_n.c +SRC += _findclo.c +SRC += _findfir.c +SRC += _findnex.c SRC += _open.c SRC += _read.c SRC += _write.c --- /cvsroot/djgpp/include/io.h Thu Feb 1 20:39:54 2001 +++ /djgpp-cvs/include/io.h Tue Oct 9 11:00:12 2001 @@ -14,8 +14,20 @@ #ifndef _POSIX_SOURCE +#include /* for the _A_* flags */ #include +typedef unsigned long _fsize_t; + +struct _finddata_t { + unsigned attrib __attribute__((packed)); + time_t time_create __attribute__((packed)); + time_t time_access __attribute__((packed)); + time_t time_write __attribute__((packed)); + _fsize_t size __attribute__((packed)); + char name[260] __attribute__((packed)); +}; + int chsize(int handle, long size); int _close(int _fd); int _creat(const char *_path, int _attrib); @@ -24,6 +36,9 @@ int _dos_lock(int _fd, long _offset, long _length); int _dos_lk64(int _fd, long long _offset, long long _length); long filelength(int _handle); +long _findfirst(const char *pathname, struct _finddata_t *fileinfo); +int _findnext(long handle, struct _finddata_t *fileinfo); +int _findclose(long handle); short _get_dev_info(int _arg); long long lfilelength(int _handle); int lock(int _fd, long _offset, long _length); > The zip file also contains a little program (findfile.c) that exercises the > three functions, tested under Win95 OSR2 and MS-DOS 7. Note that the program > compiles unmodified under MinGW. findfile.c: #include #include #include int main(int argc, char *argv[]) { struct _finddata_t fileinfo; long handle; char attrib_str[7], time_str[32]; int c = 0; if (argc < 2) return 1; handle = _findfirst(argv[1], &fileinfo); if (handle<0) { printf("no matching file.\n"); } else { do { attrib_str[0] = (fileinfo.attrib&_A_RDONLY ? 'r' : '-'); attrib_str[1] = (fileinfo.attrib&_A_HIDDEN ? 'h' : '-'); attrib_str[2] = (fileinfo.attrib&_A_SYSTEM ? 's' : '-'); attrib_str[3] = (fileinfo.attrib&_A_VOLID ? 'l' : '-'); attrib_str[4] = (fileinfo.attrib&_A_SUBDIR ? 'd' : '-'); attrib_str[5] = (fileinfo.attrib&_A_ARCH ? 'a' : '-'); attrib_str[6] = '\0'; strftime(time_str, sizeof(time_str), "%m/%d/%Y %H:%M ", localtime(&fileinfo.time_write)); printf("%-14s %5ld kb %s %s\n", fileinfo.name, 1 + fileinfo.size/1024, attrib_str, time_str); c++; } while (_findnext(handle, &fileinfo) == 0); _findclose(handle); printf("%d matching file%s\n", c, c>1 ? "s." : "."); } return 0; } Right, MartinS