/* dir.c - wrapper for Windows to support opendir/readdir/closedir api */
/* telldir(), seekdir() and scandir() are not supported. but scandir() would be
 * easy to add. */
/* August 10, 2007 - Jon Mayo - PUBLIC DOMAIN */

/** start of dir.h **/
#include <limits.h>
struct dirent {
	char d_name[PATH_MAX];
};
typedef struct _dir_c DIR;
void rewinddir(DIR *dir);
DIR *opendir(const char *name);
struct dirent *readdir(DIR *dir);
int closedir(DIR *dir);
/** end of dir.h **/

/** start of dir.c **/
#include <assert.h>
#include <string.h>
#define _WIN32_WINNT 0x0400
#include <windows.h>
/* #include "dir.h" */

struct _dir_c {
	char name[PATH_MAX];
	struct dirent curr;
	WIN32_FIND_DATA ff_data;
	int result;
	HANDLE h;
};

void rewinddir(DIR *dir) {
	DWORD dwError;
	assert(dir!=NULL);
	if(dir->h!=INVALID_HANDLE_VALUE)
		FindClose(dir->h);
	dir->h=FindFirstFileA(dir->name, &dir->ff_data);
	dir->result=dir->h!=INVALID_HANDLE_VALUE;
	if(!dir->result) {
		dwError=GetLastError();
		switch(dwError) {
			case ERROR_FILE_NOT_FOUND:
			case ERROR_PATH_NOT_FOUND:
				printf(TEXT("FindFirstFile(): File/Path not found.\n"));
			break;
			default:
				printf(TEXT("FindFirstFile() error. error=%u\n"), dwError);
			break;
			case ERROR_NO_MORE_FILES:
				/* do nothing */
				;
		}
	}
}

/* note: don't use backslashes in the name. windows supports forward slash just
 * fine. this will make your programs easier to port and have fewer bugs from
 * porting. */
DIR *opendir(const char *name) {
	DIR *ret;
	size_t len;
	assert(name!=NULL);
	ret=malloc(sizeof *ret);
	if(!ret)
		return 0;
	ret->h=INVALID_HANDLE_VALUE;
	/* copy name - truncate it if too long */
	strncpy(ret->name, name, sizeof ret->name-1-2);
	ret->name[sizeof ret->name-1]=0;
	/* TODO: handle truncation as an error */

	/* put "/*" on the end of the string */
	len=strlen(ret->name);
	if(len && (ret->name[len-1]!='/' && ret->name[len-1]!='\\')) {
	ret->name[len++]='/';
	ret->name[len]=0;
	}
	ret->name[len++]='*';
	ret->name[len]=0;
	printf("name='%s'", ret->name);

	rewinddir(ret); /* initialize with FindFirstFile() */
	return ret;
}

struct dirent *readdir(DIR *dir) {
	assert(dir!=NULL);
	if(!dir->result) {
		return 0; /* no more results */
	}
	/* store previous result and return it */
	strcpy(dir->curr.d_name, dir->ff_data.cFileName);
	/* load future result */
	dir->result=FindNextFile(dir->h, &dir->ff_data);
	if(!dir->result && GetLastError()!=ERROR_NO_MORE_FILES) {
		printf(TEXT("FindNextFile() error.\n"));
		/* we'll still return the previous result even if we have an error */
	}
	return &dir->curr;
}

int closedir(DIR *dir) {
	assert(dir!=NULL);
	if(dir->h!=INVALID_HANDLE_VALUE) {
		FindClose(dir->h);
	}
	free(dir);
}
/** end of dir.c **/

/** Test/Example code **/
#define STAND_ALONE
#ifdef STAND_ALONE
#include <stdio.h>
int main() {
	DIR *d;
	struct dirent *de;
	d=opendir("..");
	while((de=readdir(d))) {
		printf("%s\n", de->d_name);
	}
	closedir(d);
}
#endif