#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>

#define ReadOnly	0x01
#define Hidden		0x02
#define SysFile		0x04
#define VolumeID	0x08
#define Directory	0x10
#define Archive		0x20
#define AnyFile		0x3f

#define SEPARATOR	'/'

struct SearchRec {
	uint64_t Time;
	uint64_t Size;
	uint32_t name_max;
	uint32_t name_len;
	char name[13];
	char match[11];
	uint8_t Attr;
	char path[NAME_MAX+1];
	char longname[NAME_MAX+1];
	struct stat st;
};

static DIR * dir;
static struct SearchRec * dirsr;
static char * dirname;

uint32_t Doserror;

#define DENOENT 2;
#define DENOMOREFILES 18;

int match(char * s, char * t)
{
	int i,c,d;
	char *p,*q,*r;
	for(i=8;i;i--,s++){
		if(((c=*s) != (d=*t)) && (c!=SEPARATOR) ) {
			if(c || d!='.')return 0;
			else {
				s+=i;
				break;				
			}
		}
		if(!d) {
			if(!c) {
				s+=i;
				break;
			}
		} else t++;
	}
	p=t;
	while(*p)if(*p++=='.')t=p;
	for(i=3;i;i--,s++){
		if(((c=*s) != (d=*t)) && (c!=SEPARATOR) ) return 0;
		if(!d) {
			if(!c) return 1;
		} else t++;
	}
	return 1;
}

void FindFirst(char * path, uint32_t attr, struct SearchRec * s)
{
	char *p=path-1;
	char *q,*r,*fn;
	ssize_t l;
	struct dirent * de;
	int err,i;
	
	while(*(++p));
	while((--p>=path)&&(*p!=SEPARATOR));
	if((l=p-path+1)>0){
		if(l>NAME_MAX){
			Doserror=DENOENT;
			return;
		}
		memcpy(s->path,path,l);
		s->path[l]=0;
		fn=path+l;
	} else {
		s->path[0]='.';
		s->path[1]='/';
		s->path[2]=0;
		l=2;
		fn=path;
	}
	if(dirname&&(!strcmp(s->path,dirname))) {
		rewinddir(dir);
	} else {
		if(dir)closedir(dir);
		if(dirname)free(dirname);
		if(! (dirname=malloc(l+1)) ) exit(126);
		memcpy(dirname,s->path,l+1);
		dir=opendir(s->path);
	}
	dirsr=s;
	{// make match
		int c;
		p=fn-1;
		q=s->match-1;
		for(i=8;i&&*++p;){
			i--;
			if((c=(*++q=*p))=='.'){
				*q=0;
				for(;i;i--)*++q=0;
			} else if(c=='*'){
				*q=SEPARATOR;
				for(;i;i--)*++q=SEPARATOR;
			};
		}
		r=p;
		while(*r)if(*r++=='.') p=r-1;
		for(i=3;i&&*++p;){
			i--;
			if((c=(*++q=*p))=='.'){
				*q=0;
				for(;i;i--)*++q=0;
			} else if(c=='*'){
				*q=SEPARATOR;
				for(;i;i--)*++q=SEPARATOR;
			};
		}
	}
	if(dir) {		
		while(de=readdir(dir)) {
			if(match(s->match,de->d_name)) {
				strcpy(s->path+l,de->d_name);
				err=stat(s->path,&s->st);
				s->path[l]=0;
				if(!err) {
					s->Time=s->st.st_mtime;
					s->Size=s->st.st_size;
					s->Attr=(s->st.st_mode&S_IWUSR==0);
					strcpy(s->longname,de->d_name);
					p=de->d_name;
					q=s->name;
					for(i=8;i&&*p;){
						i--;
						if((*q++=*p++)=='.')break;
					}
					r=p;
					while(*r)if(*r++=='.') p=r;
					for(i=3;i&&*p;i--)*q++=*p++;
					s->name_max=12;
					s->name_len=q-s->name;
					Doserror=0;
					return;
				}
			}
			strcpy(s->longname,de->d_name);
		}
		Doserror=DENOMOREFILES;
		return;
	} else {
		Doserror=DENOENT;
		return;
	}
}

void FindNext(struct SearchRec * s)
{
	char *p;
	char *q,*r,*fn;
	ssize_t l;
	struct dirent * de;
	int err,i;
	
	l=strlen(s->path);

	if(!dirname||strcmp(s->path,dirname)) {
		if(dir)closedir(dir);
		if(dirname)free(dirname);
		if(! (dirname=malloc(l+1)) ) exit(126);
		memcpy(dirname,s->path,l+1);
		dir=opendir(s->path);
		while((de=readdir(dir))&&strcmp(de->d_name,s->longname));
	} else if(dirsr!=s) {
		rewinddir(dir);
		while((de=readdir(dir))&&strcmp(de->d_name,s->longname));
	}
	dirsr=s;
	if(dir) {		
		while(de=readdir(dir)) {
			if(match(s->match,de->d_name)) {
				strcpy(s->path+l,de->d_name);
				err=stat(s->path,&s->st);
				s->path[l]=0;
				if(!err) {
					s->Time=s->st.st_mtime;
					s->Size=s->st.st_size;
					s->Attr=(s->st.st_mode&S_IWUSR==0);
					p=de->d_name;
					strcpy(s->longname,de->d_name);
					p=de->d_name;
					q=s->name;
					for(i=8;i&&*p;){
						i--;
						if((*q++=*p++)=='.')break;
					}
					r=p;
					while(*r)if(*r++=='.') p=r;
					for(i=3;i&&*p;i--)*q++=*p++;
					s->name_max=12;
					s->name_len=q-s->name;
					Doserror=0;
					return;
				}
			}
			strcpy(s->longname,de->d_name);
		}
		Doserror=DENOMOREFILES;
		return;
	} else {
		Doserror=DENOENT;
		return;
	}
}

/*
int main(){
	struct SearchRec sr;
	struct SearchRec sr2;
	FindFirst("Master/*.hst",AnyFile,&sr);
	FindFirst("Master/*.msg",AnyFile,&sr2);
	while(Doserror==0) {
		printf("%lld\t%s\t%lld\t%s\n",sr.Size, sr.name,sr2.Size, sr2.name);
		FindNext(&sr);
		FindNext(&sr2);
	}
}
*/