/***********************************

    Dir & File Select

**********************************/
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <ctype.h>
#include    <msdos.cf>
#include    "dir.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;
    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);
}
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	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)
{
    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 )
	return NULL;

    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 );

    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;

    if ( (dirp = (DIR *)malloc(sizeof(DIR))) != NULL )
	dirp->dd_top = dirp->dd_now = 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);
}
char	*joint_path(char *dir,char *file)
{
    int     n;
    char    *p;

    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);
}

******************/
