/*****************************************************************************
 *                                                                           *
 * DH_DIR.C                                                                  *
 *                                                                           *
 * Freely redistributable and modifiable.  Use at your own risk.             *
 *                                                                           *
 * Copyright 1994 The Downhill Project                                       *
 *                                                                           *
 *****************************************************************************/


/* Include stuff *************************************************************/
#include "INCLUDE/DH.H"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <io.h>
#include <sys/dirent.h>


/* Function stuff ************************************************************/

/* Open a directory ======================================================== */
DIR* opendir(char* dir_Name)
{
	DIR*        dir_Info;
	struct stat dir_Stat;

	/* Make sure directory is actually a directory */
	if (stat(dir_Name,&dir_Stat) != 0)
	{
		errno = ENOENT;
		return NULL;
	}
	if ((dir_Stat.st_mode&_S_IFDIR) == 0)
	{
		errno = ENOTDIR;
		return NULL;
	}

	/* Get some memory */
	dir_Info = (DIR*)calloc(1,sizeof(DIR));
	if (dir_Info == NULL)
	{
		return NULL;
	}

	/* Save some info about the directory */
	strcpy(dir_Info->dir_Name,dir_Name);
	if ((dir_Info->dir_Name[strlen(dir_Info->dir_Name)-1] != '/') &&
	 (dir_Info->dir_Name[strlen(dir_Info->dir_Name)-1] != '\\'))
	{
		strcat(dir_Info->dir_Name,"/");
	}
	strcat(dir_Info->dir_Name,"*");
	dir_Info->dir_Handle = INVALID_HANDLE_VALUE;
	dir_Info->dir_FileCount = 0;

	/* And return the directory info */
	return dir_Info;
}

/* Read the next file in a directory ======================================= */
struct dirent* readdir(DIR* dir_Info)
{
	WIN32_FIND_DATA dir_FileWin;

	/* Get the info about the next file */
	if (dir_Info->dir_FileCount == 0)
	{
		dir_Info->dir_Handle = FindFirstFile(dir_Info->dir_Name,
		 &dir_FileWin);
		if (dir_Info->dir_Handle == INVALID_HANDLE_VALUE)
		{
			return NULL;
		}
	}
	else
	{
		if (!FindNextFile(dir_Info->dir_Handle,&dir_FileWin))
		{
			return NULL;
		}
	}

	/* Dummy up a UNIX file */
	dir_Info->dir_FileUnix.d_fileno = dir_Info->dir_FileCount;
	dir_Info->dir_FileUnix.d_reclen = sizeof(struct dirent);
	dir_Info->dir_FileUnix.d_namlen = strlen(dir_FileWin.cFileName);
	strcpy(dir_Info->dir_FileUnix.d_name,dir_FileWin.cFileName);

	/* Bump the number we've read */
	dir_Info->dir_FileCount++;

	/* And return the UNIX file info */
	return &(dir_Info->dir_FileUnix);
}

/* Rewind a directory ====================================================== */
void rewinddir(DIR* dir_Info)
{
	/* Re-set to the beginning */
	dir_Info->dir_Handle = INVALID_HANDLE_VALUE;
	dir_Info->dir_FileCount = 0;
}

/* Close a directory ======================================================= */
int closedir(DIR* dir_Info)
{
	/* Close down the directory */
	if (!FindClose(dir_Info->dir_Handle))
	{
		errno = EBADF;
		return -1;
	}

	/* Free up the memory */
	free(dir_Info);

	/* And return that everything went fine */
	return 0;
}

/* Tell our position in a directory ======================================== */
#if (_DOWNHILL_POSIX_SOURCE == 0)
long telldir(DIR* dir_Info)
{
	/* Return our last position */
	return dir_Info->dir_FileCount;
}
#endif

/* Seek to a position in a directory ======================================= */
#if (_DOWNHILL_POSIX_SOURCE == 0)
void seekdir(DIR* dir_Info,long dir_Position)
{
	/* Jump back to the beginning of the file */
	rewinddir(dir_Info);

	/* And read to a specific position */
	while (--dir_Position > 0)
	{
		readdir(dir_Info);
	}
}
#endif

/* Make a directory ======================================================== */
int Downhill_Directory_Make(char* dir_Name,mode_t dir_Permissions)
{
	/* Make the directory */
	if (_mkdir(dir_Name) != 0)
	{
		return -1;
	}

	/* Set the permissions */
	return chmod(dir_Name,dir_Permissions);
}
