[sword-devel] GTK+ for Windows

Jeremy Bettis sword-devel@crosswire.org
Mon, 5 Aug 2002 17:14:55 -0500


If you can't find it in some library, here is the implementation of the
dirent functions.  This is my code and is also what mingw32 includes (or
included at some point).
--- cut ---
/*
 * DIRENT.H (formerly DIRLIB.H)
 *
 * by M. J. Weinstein   Released to public domain 1-Jan-89
 *
 * Because I have heard that this feature (opendir, readdir, closedir)
 * it so useful for programmers coming from UNIX or attempting to port
 * UNIX code, and because it is reasonably light weight, I have included
 * it in the Mingw32 package. I have also added an implementation of
 * rewinddir, seekdir and telldir.
 *   - Colin Peters <colin@bird.fu.is.saga-u.ac.jp>
 *
 *  This code is distributed in the hope that is will be useful but
 *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
 *  DISCLAMED. This includeds but is not limited to warranties of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * $Revision: 1.1 $
 * $Author: taniwha $
 * $Date: 2001/02/22 04:10:23 $
 *
 */

#ifndef	__STRICT_ANSI__

#ifndef _DIRENT_H_
#define _DIRENT_H_

/* All the headers include this file. */
//#include <_mingw.h>

// ugly hack for MSVC
#if defined(_POSIX_)
 #undef _POSIX_
 #include <io.h>
 #define _POSIX_
#else
 #include <io.h>
#endif


#ifndef RC_INVOKED

#ifdef __cplusplus
extern "C" {
#endif

struct dirent
{
	long		d_ino;		/* Always zero. */
	unsigned short	d_reclen;	/* Always zero. */
	unsigned short	d_namlen;	/* Length of name in d_name. */
	char*		d_name;		/* File name. */
	/* NOTE: The name in the dirent structure points to the name in
the
	 *       finddata_t structure in the DIR. */
};

/*
 * This is an internal data structure. Good programmers will not use it
 * except as an argument to one of the functions below.
 */
typedef struct
{
	/* disk transfer area for this dir */
	struct _finddata_t	dd_dta;

	/* dirent struct to return from dir (NOTE: this makes this
thread
	 * safe as long as only one thread uses a particular DIR struct
at
	 * a time) */
	struct dirent		dd_dir;

	/* _findnext handle */
	long			dd_handle;

	/*
         * Status of search:
	 *   0 = not started yet (next entry to read is first entry)
	 *  -1 = off the end
	 *   positive = 0 based index of next entry
	 */
	short			dd_stat;

	/* given path for dir with search pattern (struct is extended)
*/
	char			dd_name[1];
} DIR;


DIR*		opendir (const char*);
struct dirent*	readdir (DIR*);
int		closedir (DIR*);
void		rewinddir (DIR*);
long		telldir (DIR*);
void		seekdir (DIR*, long);

#ifdef	__cplusplus
}
#endif

#endif	/* Not RC_INVOKED */

#endif	/* Not _DIRENT_H_ */

#endif	/* Not __STRICT_ANSI__ */


--- cut ---
/*
 * dirent.c
 *
 * Derived from DIRLIB.C by Matt J. Weinstein 
 * This note appears in the DIRLIB.H
 * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
 *
 * Updated by Jeremy Bettis <jeremy@hksys.com>
 * Significantly revised and rewinddir, seekdir and telldir added by
Colin
 * Peters <colin@fu.is.saga-u.ac.jp>
 *
 *
 */
static const char rcsid[] = 
	"$Id: dirent.c,v 1.4 2002/06/02 05:27:31 taniwha Exp $";

#include <direct.h>
#include <dirent.h>
#include <errno.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#define SUFFIX	"*"
#define	SLASH	"\\"

#ifndef S_ISDIR
#define S_ISDIR(m)	((m & S_IFMT) == S_IFDIR)	/* is a
directory */
#endif//S_ISDIR


/*
  opendir

  Returns a pointer to a DIR structure appropriately filled in to begin
  searching a directory.
*/
DIR        *
opendir (const char *szPath)
{
	DIR        *nd;
	struct _stat statDir;

	errno = 0;

	if (!szPath) {
		errno = EFAULT;
		return (DIR *) 0;
	}

	if (szPath[0] == '\0') {
		errno = ENOTDIR;
		return (DIR *) 0;
	}

	/* Attempt to determine if the given path really is a directory.
*/
	if (_stat (szPath, &statDir)) {
		/* Error, stat should have set an error value. */
		return (DIR *) 0;
	}

	if (!S_ISDIR (statDir.st_mode)) {
		/* Error, stat reports not a directory. */
		errno = ENOTDIR;
		return (DIR *) 0;
	}

	/* Allocate enough space to store DIR structure and the complete
*
	   directory path given. */
	nd = (DIR *) calloc (1, sizeof (DIR) + strlen (szPath) + strlen
(SLASH) +
						 strlen (SUFFIX));

	if (!nd) {
		/* Error, out of memory. */
		errno = ENOMEM;
		return (DIR *) 0;
	}

	/* Create the search expression. */
	strcpy (nd->dd_name, szPath);

	/* Add on a slash if the path does not end with one. */
	if (nd->dd_name[0] != '\0' &&
		nd->dd_name[strlen (nd->dd_name) - 1] != '/' &&
		nd->dd_name[strlen (nd->dd_name) - 1] != '\\') {
		strcat (nd->dd_name, SLASH);
	}

	/* Add on the search pattern */
	strcat (nd->dd_name, SUFFIX);

	/* Initialize handle to -1 so that a premature closedir doesn't
try * to
	   call _findclose on it. */
	nd->dd_handle = -1;

	/* Initialize the status. */
	nd->dd_stat = 0;

	/* Initialize the dirent structure. ino and reclen are invalid
under *
	   Win32, and name simply points at the appropriate part of the
*
	   findfirst_t structure. */
	nd->dd_dir.d_ino = 0;
	nd->dd_dir.d_reclen = 0;
	nd->dd_dir.d_namlen = 0;
	nd->dd_dir.d_name = nd->dd_dta.name;

	return nd;
}

/*
  readdir

  Return a pointer to a dirent structure filled with the information on
the
  next entry in the directory.
*/
struct dirent *
readdir (DIR * dirp)
{
	errno = 0;

	/* Check for valid DIR struct. */
	if (!dirp) {
		errno = EFAULT;
		return (struct dirent *) 0;
	}

	if (dirp->dd_dir.d_name != dirp->dd_dta.name) {
		/* The structure does not seem to be set up correctly.
*/
		errno = EINVAL;
		return (struct dirent *) 0;
	}

	if (dirp->dd_stat < 0) {
		/* We have already returned all files in the directory *
(or the
		   structure has an invalid dd_stat). */
		return (struct dirent *) 0;
	} else if (dirp->dd_stat == 0) {
		/* We haven't started the search yet. */
		/* Start the search */
		dirp->dd_handle = _findfirst (dirp->dd_name,
&(dirp->dd_dta));

		if (dirp->dd_handle == -1) {
			/* Whoops! Seems there are no files in that *
directory. */
			dirp->dd_stat = -1;
		} else {
			dirp->dd_stat = 1;
		}
	} else {
		/* Get the next search entry. */
		if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) {
			/* We are off the end or otherwise error. */
			_findclose (dirp->dd_handle);
			dirp->dd_handle = -1;
			dirp->dd_stat = -1;
		} else {
			/* Update the status to indicate the correct *
number. */
			dirp->dd_stat++;
		}
	}

	if (dirp->dd_stat > 0) {
		/* Successfully got an entry. Everything about the file
is * already
		   appropriately filled in except the length of the *
file name. */
		dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name);
		return &dirp->dd_dir;
	}

	return (struct dirent *) 0;
}

/*
  closedir

  Frees up resources allocated by opendir.
*/
int
closedir (DIR * dirp)
{
	int         rc;

	errno = 0;
	rc = 0;

	if (!dirp) {
		errno = EFAULT;
		return -1;
	}

	if (dirp->dd_handle != -1) {
		rc = _findclose (dirp->dd_handle);
	}

	/* Delete the dir structure. */
	free (dirp);

	return rc;
}

/*
  rewinddir

  Return to the beginning of the directory "stream". We simply call
findclose
  and then reset things like an opendir.
*/
void
rewinddir (DIR * dirp)
{
	errno = 0;

	if (!dirp) {
		errno = EFAULT;
		return;
	}

	if (dirp->dd_handle != -1) {
		_findclose (dirp->dd_handle);
	}

	dirp->dd_handle = -1;
	dirp->dd_stat = 0;
}

/*
  telldir

  Returns the "position" in the "directory stream" which can be used
with
  seekdir to go back to an old entry. We simply return the value in
stat.
*/
long
telldir (DIR * dirp)
{
	errno = 0;

	if (!dirp) {
		errno = EFAULT;
		return -1;
	}
	return dirp->dd_stat;
}

/*
  seekdir

  Seek to an entry previously returned by telldir. We rewind the
directory
  and call readdir repeatedly until either dd_stat is the position
number
  or -1 (off the end). This is not perfect, in that the directory may
  have changed while we weren't looking. But that is probably the case
with
  any such system.
*/
void
seekdir (DIR * dirp, long lPos)
{
	errno = 0;

	if (!dirp) {
		errno = EFAULT;
		return;
	}

	if (lPos < -1) {
		/* Seeking to an invalid position. */
		errno = EINVAL;
		return;
	} else if (lPos == -1) {
		/* Seek past end. */
		if (dirp->dd_handle != -1) {
			_findclose (dirp->dd_handle);
		}
		dirp->dd_handle = -1;
		dirp->dd_stat = -1;
	} else {
		/* Rewind and read forward to the appropriate index. */
		rewinddir (dirp);

		while ((dirp->dd_stat < lPos) && readdir (dirp));
	}
}