/***********************************

    Dir & File Select

**********************************/
#include    <stdio.h>
#include    <stdlib.h>
#include    <string.h>
#include    <ctype.h>
#include    <jctype.h>
#include    <dos.h>
#include    "dir.h"

#define TRUE		1
#define FALSE		0
#define ERR		(-1)

static	int	sort_mode = 0;
static	struct find_t	dma;

static	char	*strlowcpy(char *dis, register char *s)
{
    int     ch;
    register char *p;

    p = dis;
    while ( *s != '\0' ) {
	ch = *(s++);
	if ( iskanji(ch) && iskanji2(*s) ) {
	    *(p++) = ch;
	    *(p++) = *(s++);
	} else if ( isupper(ch) )
	    *(p++) = tolower(ch);
	else
	    *(p++) = ch;
    }
    *p = '\0';
    return dis;
}
static	char	*subname(char *name)
{
    while ( *name != '.' && *name != '\0' )
	name += (iskan(name) ? 2 : 1);
    return name;
}
static	int	path_cmp(DIRECT *sp, DIRECT *dp)
{
    int cd;

    if ( (sp->d_att & AT_DIR) != (dp->d_att & AT_DIR) )
	return ((sp->d_att & AT_DIR) != 0 ? (-1) : 1);

    switch(sort_mode) {
    case 0:
	cd = strcmp(sp->d_name,dp->d_name);
	break;
    case 1:
	if ( (cd = strcmp(subname(sp->d_name), subname(dp->d_name))) != 0 )
	    break;
	cd = strcmp(sp->d_name,dp->d_name);
	break;
    case 2:
	if ( sp->d_size < dp->d_size )
	    cd = (-1);
	else if ( sp->d_size > dp->d_size )
	    cd = 1;
	else
	    cd = 0;
	break;
    case 3:
	if ( sp->d_date < dp->d_date )
	    cd = (-1);
	else if ( sp->d_date > dp->d_date )
	    cd = 1;
	else if ( sp->d_time < dp->d_time )
	    cd = (-1);
	else if ( sp->d_time > dp->d_time )
	    cd = 1;
	else
	    cd = 0;
	break;
    }

    return cd;
}
static	DIRECT	*dir_sort(DIRECT *np)
{
    DIRECT    *tp, *bp;
    DIRECT    *lp, *rp;

    if ( np == NULL || np->d_next == NULL )
	return np;

    lp = rp = NULL;
    tp = np->d_next;

    while ( tp != NULL ) {
	bp = tp->d_next;
	if ( path_cmp(np, tp) >= 0 ) {
	    tp->d_next = lp;
	    lp = tp;
	} else {
	    tp->d_next = rp;
	    rp = tp;
	}
	tp = bp;
    }

    lp = dir_sort(lp);
    rp = dir_sort(rp);

    if ( lp != NULL ) {
	tp = lp;
	while ( lp->d_next != NULL )
	    lp = lp->d_next;
	lp->d_next = np;
    } else
	tp = np;

    np->d_next = rp;

    return tp;
}
int	dos_stat(char *name, DIRECT *st)
{
    if ( _dos_findfirst(name, 0x31, &dma) )
	return ERR;

    st->d_att  = dma.attrib;
    st->d_time = dma.wr_time;
    st->d_date = dma.wr_date;
    st->d_size = dma.size;
    strcpy(st->d_name, dma.name);

    while ( !_dos_findnext(&dma) )
	;

    return FALSE;
}
static DIRECT  *dir_get(char *sdir, int *st)
{
    register DIRECT *np;
    char *dir;
    DIRECT *top = NULL;
    DIRECT *root = NULL;

    *st = FALSE;
    dir = path_make(sdir, "*.*");

    if ( _dos_findfirst(dir, 0x31, &dma) )
	goto ENDOF;

    do {
	if ( strcmp(dma.name, ".") == 0 )
	    continue;

	if ( (np = (DIRECT *)malloc(sizeof(DIRECT))) == NULL ) {
	    message("opendir %s memory alloc error", sdir);

	    while ( !_dos_findnext(&dma) )
		;
	    while ( top != NULL ) {
		np = top->d_next;
		free(top);
		top = np;
	    }
	    *st = ERR;
	    return NULL;
	}

	np->d_next = NULL;
	np->d_mark = FALSE;
	np->d_att  = dma.attrib;
	np->d_time = dma.wr_time;
	np->d_date = dma.wr_date;
	np->d_size = dma.size;
	strcpy(np->d_name, dma.name);

	if ( strcmp(dma.name, "..") == 0 ) {
	    if ( root != NULL )
		free(root);
	    root = np;
	} else {
	    np->d_next = top;
	    top = np;
	}

    } while ( !_dos_findnext(&dma) );

    top = dir_sort(top);

ENDOF:

    if ( root != NULL ) {
	root->d_next = top;
	top = root;

    } else if ( strcmp(dir + 1, ":\\*.*") != 0 &&
	(np = (DIRECT *)malloc(sizeof(DIRECT))) != NULL ) {
/**********************************************
	np->d_mark = FALSE;
	np->d_att  = 0x10;
	np->d_time = 0;
	np->d_date = 0;
	np->d_size = 0;
	strcpy(np->d_name, "..");
	np->d_next = top;
	top = np;
************************************************/
	if ( dos_stat(sdir, np) )
	    free(np);
	else {
	    np->d_mark = FALSE;
	    strcpy(np->d_name, "..");
	    np->d_next = top;
	    top = np;
	}
    }

    return top;
}
DIR	*opendir(char *dir, int mode)
{
    int     st;
    DIR     *dirp;
    register DIRECT *np;

    sort_mode = mode;

    if ( (dirp = (DIR *)malloc(sizeof(DIR))) == NULL ) {
	message("opendir %s ptr memory alloc error", dir);
	return NULL;
    }

    if ( (dirp->dd_top = dirp->dd_now = dir_get(dir, &st)) == NULL ) {
	if ( st == ERR || !isdir(dir) ) {
	    free(dirp);
	    return NULL;
	}
    }

    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 n;
    DIRECT *np;

    np = dirp->dd_top;
    for ( n = 0 ; np != NULL ; n++ )
	np = np->d_next;
    return n;
}
void	closedir(DIR *dirp)
{
    DIRECT *np,*tp;

    np = dirp->dd_top;
    while ( np != NULL ) {
	tp = np->d_next;
	free(np);
	np = tp;
    }
    free(dirp);
}
int	isdir(char *dir)
{
    unsigned attr;

    if ( dir[0] != '\0' && dir[1] == ':' &&
		(dir[2] == '\0' || (dir[2] == '\\' && dir[3] == '\0')) )
	return TRUE;

    if ( _dos_getfileattr(dir, &attr) )
	return FALSE;

    return ((attr & 0x10) != 0 ? TRUE:FALSE);
}
char	*path_make(char *dir, char *file)
{
    char    *p;
    static char tmp[256];

    for ( p = dir ; *p != '\0' ; p++ )
	;
    if ( *file == '\\' || *dir == '\0' ||
	(p != dir && (*(p - 1) == ':' || *(p - 1) == '\\')) )
	sprintf(tmp, "%s%s", dir, file);
    else
	sprintf(tmp, "%s\\%s", dir, file);
    return tmp;
}
static	int	getone(char **ptr)
{
    int c;
    char *p;

    p = *ptr;
    c = *(p++);
    if ( iskanji(c) && iskanji2(*p) )
	c = (c << 8) | (unsigned char)*(p++);
    *ptr = p;
    return c;
}
static  char    *wild_rang(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(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;
    }
}
