/***********************************

    Dir & File Select

**********************************/
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <ctype.h>
#include    <msdos.cf>
#include    "dir.h"
#include    "graphic.h"

#define TRUE		1
#define FALSE		0
#define ERR		(-1)

static struct {
    unsigned char	dd_dmy[21];
    unsigned char	dd_att;
    unsigned short int	dd_time,dd_date;
    unsigned long	dd_size;
    char		dd_name[14];
} dma;

extern int	errno;

char	*strdup();

static int dos_err_chk(void)
{
    if ( (Registers.Flags & 0x0001) != 0 ) {
	errno = Registers.AX.R;
	return ERR;
    } else
	return FALSE;
}
int	chdrv(int no)
{
    Registers.AX.R = 0x0E00;
    Registers.DX.R = no;		/* A=0, B=1 ... */
    calldos();
    return dos_err_chk();
}
int	mkdir(char *name)
{
    Registers.AX.R = 0x3900;
    Registers.DX.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    return dos_err_chk();
}
int	rmdir(char *name)
{
    Registers.AX.R = 0x3A00;
    Registers.DX.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    return dos_err_chk();
}
int	chdir(char *name)
{
    Registers.AX.R = 0x3B00;
    Registers.DX.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    return dos_err_chk();
}
int	getdrv(void)
{
    Registers.AX.R = 0x1900;
    calldos();
    if ( dos_err_chk() != 0 )
	return ERR;
    return (Registers.AX.R & 0xFF);	/* A=0, B=1 ... */
}
int	getdir(char *name)
{
    *(name++) = '\\';
    Registers.AX.R = 0x4700;
    Registers.DX.R = 0x0000;
    Registers.SI.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    if ( dos_err_chk() )
	*name = '\0';
    return dos_err_chk();
}
int	getattr(char *name)
{
    Registers.AX.R = 0x4300;
    Registers.DX.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    if ( dos_err_chk() )
	return ERR;
    return Registers.CX.R;
}
int	disk_free(int drv, unsigned long *fr, unsigned long *ta)
{
    unsigned long sz;

    Registers.AX.R = 0x3600;
    Registers.DX.R = drv + 1;		/* A=0, B=1 ... */
    calldos();

    if ( dos_err_chk() ||
	(unsigned short)(Registers.AX.R) == 0xFFFF ||
	(unsigned short)(Registers.DX.R) == 0 )
	return ERR;

    sz = (unsigned short)(Registers.AX.R) *
	 (unsigned short)(Registers.CX.R);	/* byte */

    if ( sz > 1024UL ) {
	*fr = (sz / 1024UL) * (unsigned short)(Registers.BX.R);
	*ta = (sz / 1024UL) * (unsigned short)(Registers.DX.R);
    } else {
	*fr = (sz * (unsigned short)(Registers.BX.R)) / 1024UL;
	*ta = (sz * (unsigned short)(Registers.DX.R)) / 1024UL;
    }

    return FALSE;
}
int	drvsts(int no)
{
    Registers.AX.R = 0x4409;
    Registers.BX.R = no + 1;		/* A=1, B=2 ...*/
    calldos();

    if ( (Registers.Flags & 0x0001) != 0 )
	return (-1);
    if ( (Registers.DX.R & 0x1000) != 0 )
	return 0;			/* NET */

    Registers.AX.R = 0x4408;
    Registers.BX.R = no + 1;		/* A=1, B=2 ...*/
    calldos();
    if ( (Registers.Flags & 0x0001) != 0 )
	return 1;			/* LOCAL */
    if ( Registers.AX.R != 0 )
	return 2;			/* HDD */
    else
	return 3;			/* MO or FDD */
}
int	isdir(char *file)
{
    int     at;

    if ( (at = getattr(file)) == ERR )
	return FALSE;

    return ((at & 0x10) != 0 ? TRUE:FALSE);
}
static char    *subname(register char *name)
{
    char    *p;

    if ( strcmp(name,".") == 0 ||
	 strcmp(name,"..") == 0 ||
	 (p = strrchr(name,'.')) == NULL )
	while ( *name != '\0' ) name++;
    else
	name = p + 1;
    return name;
}
static int     dir_cmp(DIRECT *sp,DIRECT *dp)
{
    int     cd;

    if ( IS_DIR(sp) != IS_DIR(dp) )
	return IS_DIR(sp) ? ERR:TRUE;
    if ( (cd = strcmp(subname(sp->d_name),subname(dp->d_name))) != 0 )
	return cd;
    return strcmp(sp->d_name,dp->d_name);
}
static DIRECT  *dir_sort(DIRECT *sp,DIRECT *dp)
{
    register DIRECT *tp;
    DIRECT tmp;

    tp = &tmp;
    if ( (tp->d_next = sp) == NULL )
	return dp;
    while ( tp->d_next != NULL ) {
	if ( dir_cmp(tp->d_next,dp) >= 0 )
	    break;
	tp = tp->d_next;
    }
    dp->d_next = tp->d_next;
    tp->d_next = dp;
    return tmp.d_next;
}
static DIRECT  *dir_apend(DIRECT *sp,DIRECT *dp)
{
    register DIRECT *tp;
    DIRECT tmp;

    tp = &tmp;
    if ( (tp->d_next = sp) == NULL )
	return dp;
    while ( tp->d_next != NULL )
	tp = tp->d_next;
    dp->d_next = tp->d_next;
    tp->d_next = dp;
    return tmp.d_next;
}
static DIRECT  *dir_get(char *dir,int sw)
{
    int n;
    register DIRECT  *np;
    DIRECT  *tp=NULL;

    Registers.AX.R = 0x1A00;
    Registers.DX.R = (int)&dma;
    Registers.DS.R = getds();
    calldos(); 

    Registers.AX.R = 0x4E00;
    Registers.CX.R = 0x31;
    Registers.DX.R = (int)dir;
    Registers.DS.R = getds();
    calldos();

    if ( (Registers.Flags & 0x0001) != 0 )
	goto SKIP;

    do {
	if ( (sw == FALSE || (dma.dd_att & 0x10) != 0) &&
	     strcmp(dma.dd_name,".") != 0 ) {

	    if ( (np = (DIRECT *)
		       malloc(sizeof(DIRECT)+strlen(dma.dd_name))) == NULL )
		break;

	    np->d_next = np->d_child = NULL;
	    np->d_att  = dma.dd_att;
	    np->d_time = dma.dd_time;
	    np->d_date = dma.dd_date;
	    np->d_size = dma.dd_size;
	    strcpy(np->d_name,dma.dd_name);
	    tp = dir_sort(tp,np);
	}
	Registers.AX.R = 0x4F00;
	calldos();
    } while ( (Registers.Flags & 0x0001) == 0 );

SKIP:

    if ( tp == NULL || strcmp(tp->d_name, "..") != 0 ) {
	if ( strcmp(dir + 1, ":\\*.*") == 0 ||
	     strcmp(dir, "\\*.*") == 0 )
	    return tp;

	if ( (n = strlen(dir) - 3) >= 0 && strcmp(dir + n, "*.*") != 0 )
	    return tp;

	if ( (np = (DIRECT *)malloc(sizeof(DIRECT)+2)) == NULL )
	    return tp;

	np->d_next = np->d_child = NULL;
	np->d_att  = 0x10;
	np->d_time = np->d_date = 0;
	np->d_size = 0;
	strcpy(np->d_name, "..");
	tp = dir_sort(tp, np);
    }

    return tp;
}

/*******************************************
static DIRECT  *dir_map(char *dir,int sw)
{
    FILE    *fp;
    register DIRECT  *np;
    DIRECT  *tp=NULL;
    char    *p;
    char    tmp[BUFSIZ];

    if ( (p = strchr(dir,'\\')) == NULL )
	p = dir;

    if ( (p = strrchr(p,'.')) == NULL ||
	 strcmp(p,".QQQ") != 0 ||
	 (fp = fopen(dir,"r")) == NULL )
	return dir_get(dir,sw);

    while ( fgets(tmp,BUFSIZ,fp) != NULL ) {
	if ( (p = strchr(tmp,'\n')) != NULL )
	    *p = '\0';

	if ( tmp[0] == '\0' || tmp[0] == '#' )
	    continue;

	if ( (np = (DIRECT *)malloc(sizeof(DIRECT)+strlen(tmp))) == NULL )
	    break;

	np->d_next = np->d_child = NULL;
	np->d_att  = 0;
	strcpy(np->d_name,tmp);
	tp = dir_apend(tp,np);
    }

    fclose(fp);
    return tp;
}
************************************************/

DIR	*opendir(char *dir)
{
    DIR    *dirp;
    DIRECT *np;

    if ( (dirp = (DIR *)malloc(sizeof(DIR))) != NULL )
	dirp->dd_top = dirp->dd_now = np = dir_get(dir,FALSE);

    return dirp;
}
DIRECT	*readdir(DIR *dirp)
{
    DIRECT *np;

    if ( (np = dirp->dd_now) != NULL )
	dirp->dd_now = np->d_next;
    return np;
}
void	seekdir(DIR *dirp,int n)
{
    DIRECT *np;

    np = dirp->dd_top;
    while ( n-- > 0 && np != NULL )
	np = np->d_next;
    dirp->dd_now = np;
}
int	countdir(DIR *dirp)
{
    int    i;
    DIRECT *np;

    i = 0;
    np = dirp->dd_top;
    while ( np != NULL ) {
	i++;
	np = np->d_next;
    }
    return i;
}
void	closedir(DIR *dirp)
{
    DIRECT *np,*tp;

    np = dirp->dd_top;
    while ( np != NULL ) {
	tp = np->d_next;
	free(np);
	np = tp;
    }
    free(dirp);
}
void	stripdir(DIR *dir)
{
    DIRECT *dp, *tp;

    dp = dir->dd_top;
    dir->dd_top = NULL;
    while ( dp != NULL ) {
	tp = dp->d_next;
	dp->d_next = NULL;
	if ( IS_DIR(dp) )
	    dir->dd_top = dir_sort(dir->dd_top, dp);
	else
	    free(dp);
	dp = tp;
    }
    dir->dd_now = dir->dd_top;
}
unsigned long	sizedir(char *dir)
{
    DIRECT *np, *tp;
    unsigned long sz = 0;
    char *p;
    char tmp[128];

    np = dir_get(dir, FALSE);
    while ( np != NULL ) {
	if ( np->d_name[0] != '.' ) {
	    if ( IS_DIR(np) ) {
	        strcpy(tmp, dir);
	        if ( (p = strrchr(tmp, '\\')) != NULL ||
		     (p = strrchr(tmp, ':')) != NULL )
		    *(p + 1) = '\0';
	        joint_path(tmp, np->d_name);
	        strcat(tmp, "\\*.*");
	        sz += sizedir(tmp);
	    } else
	        sz += np->d_size;
	}
	tp = np;
	np = np->d_next;
	free(tp);
    }
    return sz;
}
char	*joint_path(char *dir,char *file)
{
    int     n;
    char    *p;

    if ( file[1] == ':' || file[0] == '\\' )
	dir[0] = '\0';
    else {
        p = dir;
        while ( *p != '\0' ) p++;
        if ( p != dir && *(p-1) != ':' && *(p-1) != '\\' )
	    strcat(dir,"\\");
    }
    strcat(dir,file);
    return dir;
}
char	*file_serch(char *dir,char *wild)
{
    DIR     *dirp;
    DIRECT  *dp;
    char    tmp[256];

    strcpy(tmp,dir);
    joint_path(tmp,wild);

    if ( (dirp = opendir(tmp)) == NULL )
	return NULL;

    if ( (dp = readdir(dirp)) == NULL ) {
	closedir(dirp);
	return NULL;
    }

    strcpy(tmp,dir);
    joint_path(tmp,dp->d_name);
    closedir(dirp);

    return strdup(tmp);
}
/********************

DIRECT	*alldir(char *dir)
{
    DIRECT *tp;
    DIRECT *np;
    char   tmp[128];

    tp = np = dir_get(dir,TRUE);
    while ( np != NULL ) {
	if ( IS_DIR(np) ) {
	    sprintf(tmp,"%s\\%s",dir,np->d_name);
	    np->d_child = alldir(tmp);
	}
	np = np->d_next;
    }
    return tp;
}
void	allclose(DIRECT *np)
{
    DIRECT *tp;

    while ( np != NULL ) {
	tp = np->d_next;
	if ( IS_DIR(np) )
	    allclose(np->child);
	free(np);
	np = tp;
    }
}

typedef struct _DIRP {
    struct _DIRP	*next;
    char		*nes;
    char		*dir;
} DIRPTR;

char	*strdup(char *str);

       DIRPTR	*dir_top=NULL;
static DIRPTR	*dir_btm=NULL;

void	dir_tree(char *nes,char *dir,DIRECT *np)
{
    DIRPTR  *dp;
    char    *p,*s;

    for ( p = nes ; *p != '\0' ; p++ );
    for ( s = dir ; *s != '\0' ; s++ );
    while ( np != NULL ) {
	sprintf(tmp,"%s\x1b%c\x1b\x95%s",nes,
			(np->d_next == NULL ? '\x9A':'\x93'),np->d_name);
	strcpy(p,np->d_next == NULL ? "   ":"\x1b\x96  ");
	sprintf(s,"\\%s",np->d_name);
	if ( (dp = (DIRPTR *)malloc(sizeof(DIRPTR))) != NULL ) {
	    dp->next = NULL;
	    dir_btm->next = dp;
	    dir_btm = dp;

	    dp->nes = strdup(tmp);
	    dp->dir = strdup(dir);
	}
	dir_tree(nes,dir,np->child);
	*p = '\0';
	*s = '\0';
	np = np->d_next;
    }
}
void	chengdir(int drive)
{
    DIRECT *tp;
    DIRPTR *np;
    char   nes[128];
    char   dir[128];

    sprintf(dir,"%c:",drive+'A');
    tp = alldir(dir);

    if ( (np = dir_top) != NULL ) {
	do {
	    dir_top = np->next;
	    free(np->nes);
	    free(np->dir);
	    free(np);
	    np = dir_top;
	} while ( np != NULL );
    }

    if ( (dp = (DIRPTR *)malloc(sizeof(DIRPTR))) != NULL ) {
	sprintf(dir,"%c:\\",drive+'A');
	strcpy(nes,"  ");
	dir_top = dir_btm = dp;
	dp->next = NULL;
	dp->nes = strdup(dir);
	dp->dir = strdup(dir);
	dir_tree(nes,dir,tp);
    }

    allclose(tp);
}

******************/

static	int	GETONE(char **str)
{
    int ch;
    char *p;

    p = *str;
    ch = (unsigned char)(*(p++));
    if ( islower(ch) )
	ch = toupper(ch);
    else if ( iskanji(ch) && iskanji2(*p) )
	ch = (ch << 8) | (unsigned char)(*(p++));
    *str = p;
    return ch;
}

static  char    *wild_rang(wild, fc)
char    *wild;
int     fc;
{
    int     wc, ch;

    while ( *wild != '\0' ) {
        wc = GETONE(&wild);

        if ( wc == ']' )
            return NULL;

        if ( *wild == '-' ) {
            wild++;
            ch = GETONE(&wild);
            if ( ch == ']' ) {
                if ( wc <= fc )
                    goto ENDOF;
            } else if ( ch == '\0' )
                return NULL;

            if ( wc <= fc && fc <= ch )
                goto ENDOF;

        } else if ( wc == fc )
            goto ENDOF;
    }
    return NULL;

ENDOF:
    while ( *wild != '\0' ) {
        if ( *(wild++) == ']' )
            return wild;
    }
    return NULL;
}
int     wild_mach(wild, file)
char    *wild;
char    *file;
{
    int     wc, fc;

    for ( ; ; ) {
        wc = GETONE(&wild);
        fc = GETONE(&file);

        if ( wc == '\0' )
            return (fc == '\0' ? TRUE:FALSE);

        else if ( wc == '*' ) {
            if ( *wild == '\0' )
                return TRUE;
            for ( file-- ; *file != '\0' ; file++ ) {
                if ( wild_mach(wild, file) )
                    return TRUE;
            }
            return FALSE;

        } else if ( wc == '[' ) {
            if ( (wild = wild_rang(wild, fc)) == NULL )
                return FALSE;

        } else if ( wc != '?' && wc != fc )
            return FALSE;
    }
}
