#include    <stdio.h>
#include    <stdlib.h>
#include    <ctype.h>
#include    <msdos.cf>
#include    "defs.h"

#define DSP_X   36
#define DSP_Y   0
#define MAX     22

#define DIR_FLG 0x10

typedef struct _WCBUF {
    struct _WCBUF       *next;
    short int           att;
    unsigned short int  time,date;
    unsigned long       size;
    char                name[14];
} WCBUF;

static short int	cmp_mode=0;
static WCBUF		*topwp=NULL;

void	chdrv(no)
int	no;
{
    Registers.AX.R = 0x0E00;
    Registers.DX.R = no;
    calldos();
}
void	chdir(char *name)
{
    Registers.AX.R = 0x3B00;
    Registers.DX.R = (int)name;
    Registers.DS.R = getds();
    calldos();
    if ( name[1] == ':' ) {
	Registers.AX.R = 0x0E00;
	Registers.DX.R = (*name & 0xDF) - 'A';
	calldos();
    }
}
int	retdir(char *name)
{
    Registers.AX.R = 0x4700;
    Registers.DX.R = 0x0000;
    Registers.SI.R = (int)name+3;
    Registers.DS.R = getds();
    calldos();

    Registers.AX.R = 0x1900;
    calldos();

    *(name++) = 'A' + (Registers.AX.R & 0xFF);
    *(name++) = ':';
    *(name++) = '\\';
    if ( *name != '\0' )
	strcat(name,"\\");
    return (Registers.AX.R & 0xFF);
}
char    *subname(name)
register char   *name;
{
    if ( *name == '.' ) {
	while ( *name != '\0' ) name++;
	return name;
    }
    while ( *name != '\0' ) {
	if ( *(name++) == '.' )
	    break;
    }
    return name;
}
int	name_cmp(sp,dp)
char	*sp,*dp;
{
    int     cd;

    if ( (cd = strcmp(subname(sp),subname(dp))) != 0 )
	return cd;
    return strcmp(sp,dp);
}
int	size_cmp(sl,dl)
unsigned long *sl,*dl;
{
    if ( *sl == *dl ) return 0;
    if ( *sl > *dl )  return (-1);
    return 1;
}
int     date_cmp(swp,dwp)
WCBUF   *swp,*dwp;
{
    int     cd;

    if ( (cd = dwp->date - swp->date) != 0 )
	return cd;
    return (int)(dwp->time - swp->time);
}
int     cmpname(swp,dwp)
WCBUF   *swp,*dwp;
{
    if ( (swp->att & DIR_FLG) != (dwp->att & DIR_FLG) )
	return (swp->att & DIR_FLG ? (-1):1);
    switch(cmp_mode) {
	case 0: return name_cmp(swp->name,dwp->name);
	case 1: return size_cmp(&swp->size,&dwp->size);
	case 2: return date_cmp(swp,dwp);
    }
}
WCBUF   *wc_read(arg,mode)
char    *arg;
int     mode;
{
    static int   opflg=FALSE;
    static struct {
	unsigned char      dd_dmy[22];
	unsigned short int dd_time,dd_date;
	unsigned long      dd_size;
	char               dd_name[13];
    } dma;
    WCBUF    *wp;

    if ( opflg == FALSE ) {
        Registers.AX.R = 0x1A00;
        Registers.DX.R = (int)&dma;
        Registers.DS.R = getds();
        calldos(); 
        Registers.AX.R = 0x4E00;
        Registers.CX.R = mode;
        Registers.DX.R = (int)arg;
        Registers.DS.R = getds();
        opflg = TRUE;
    } else
        Registers.AX.R = 0x4F00;

    calldos();
    if ( (Registers.Flags & 0x0001) != 0 ) {
        opflg = FALSE;
	return NULL;
    }
    if ( (wp = (WCBUF *)malloc(sizeof(WCBUF))) != NULL ) {
	wp->next = NULL;
	wp->att = dma.dd_dmy[21];
	wp->date = dma.dd_date;
	wp->time = dma.dd_time;
	wp->size = dma.dd_size;
	strcpy(wp->name,dma.dd_name);
    }
    return wp;
}
WCBUF   *wc_sort(sp,dp)
WCBUF   *sp,*dp;
{
    if ( sp == NULL )
	return dp;
    if ( cmpname(sp,dp) >= 0 ) {
	dp->next = sp;
	return dp;
    }
    sp->next = wc_sort(sp->next,dp);
    return sp;
}
void    wc_del(wp)
WCBUF   *wp;
{
    if ( wp->next != NULL )
	wc_del(wp->next);
    free(wp);
}
int     wc_open(wild)
char    *wild;
{
    int     max;
    WCBUF   *wp;

    if ( topwp != NULL )
	wc_del(topwp);
    topwp = NULL;

    for ( max = 0 ; (wp = wc_read("*.*",DIR_FLG)) != NULL ; ) {
	if ( (wp->att & DIR_FLG) != 0 ) {
	    topwp = wc_sort(topwp,wp);
	    max++;
	} else
	    free(wp);
    }
    for ( ; (wp = wc_read(wild,0x21)) != NULL ; max++ )
	topwp = wc_sort(topwp,wp);
    return max;
}
void    list_file(no,wp,sw)
int     no;
WCBUF   *wp;
int	sw;
{
    char    *p,tmp[20];

    strcpy(tmp,wp->name);
    p = subname(tmp);
    if ( *p != '\0' ) {
	*(p-1) = '\0';
	p = subname(wp->name);
    }
    locate(DSP_X+2,DSP_Y+1+no);
    color(sw == FALSE ? STD_COL:(cmp_mode == 0 ? CMP_COL:HIT_COL));
    printf("%-8s %-3s ",tmp,p);
    color(sw == FALSE ? STD_COL:(cmp_mode == 1 ? CMP_COL:HIT_COL));
    if ( wp->att & DIR_FLG )
	printf("<DIR>    ");
    else
	printf("%8ld ",wp->size);
    color(sw == FALSE ? STD_COL:(cmp_mode == 2 ? CMP_COL:HIT_COL));
    printf("%02d-%02d-%02d %02d:%02d",
	80+(wp->date >> 9),
	(wp->date >> 5) & 0x0F,
	wp->date & 0x1F,
	wp->time >> 11,
	(wp->time >> 5) & 0x3F);
    color(STD_COL);
}
char    *sel_file(file)
char	*file;
{
    int     ch,i,x=DSP_X,y=DSP_Y;
    int     top,max,no,no_old;
    WCBUF   *wp,*wpb[22];
    char    *p,tmp[80];
    char    where[80];

    if ( *file != '\0' && *(file+1) == ':' ) {
	chdrv(toupper(*file)-'A');
	file += 2;
    }
    strcpy(tmp,file);
    p = tmp;
    while ( *p != '\0' ) p++;
    while ( p > tmp ) {
        if ( *(--p) == '\\' ) {
            *(p++) = '\0';
            break;
	}
    }
    if ( p != tmp ) {
        file = p;
	if ( tmp[0] == '\0' )
	    strcpy(tmp,"\\");
        chdir(tmp);
    }
    if ( *file == '\0' )
	file = "*.*";

    G_era();
    wind(DSP_X,DSP_Y,38,MAX);
/************************
    locate(DSP_X,DSP_Y);
    repchr(1,0x98); repchr(38,0x95); repchr(1,0x99);
    for ( i = 1 ; i <= MAX ; i++ ) {
	locate(DSP_X,DSP_Y+i);
	repchr(1,0x96); repchr(38,0x20); repchr(1,0x96);
    }
    locate(DSP_X,DSP_Y+MAX+1);
    repchr(1,0x9a); repchr(38,0x95); repchr(1,0x9b);
*************************/
REDIR:
    retdir(where); strcat(where,file);
    locate(1,1); printf("%-34s",where);

    if ( (max = wc_open(file)) == 0 ) {
	file = NULL;
	goto ENDOF;
    }
    for ( i = 0,wp = topwp ; i < MAX ; i++ ) {
	wpb[i] = wp;
	if ( wp != NULL ) {
	    list_file(i,wp,FALSE);
	    wp = wp->next;
	} else {
	    locate(DSP_X+2,DSP_Y+1+i);
	    repchr(36,0x20);
	}
    }
    top = no = 0; no_old = (-1);
    for ( ; ; ) {
	if ( no < top || no >= (top+MAX) ) {
	    while ( no < top || no >= (top+MAX) )
	        top += (no < top ? (-MAX):MAX);
	    wp = topwp;
	    for ( i = 0 ; i < top && wp != NULL ; i++,wp = wp->next );
	    for ( i = 0 ; i < MAX ; i++ ) {
		wpb[i] = wp;
		if ( wp != NULL ) {
		    list_file(i,wp,FALSE);
		    wp = wp->next;
		} else {
		    locate(DSP_X+2,DSP_Y+1+i);
		    repchr(36,0x20);
		}
	    }
	    no_old = (-1);
	}
	if ( no != no_old ) {
	    if ( no_old >= 0 )
		list_file(no_old-top,wpb[no_old-top],FALSE);
	    list_file(no-top,wpb[no-top],TRUE);
	    no_old = no;
	}
	ch = get_key();
	if ( ch == '\x0D' ) {
	    if ( wpb[no-top]->att & DIR_FLG ) {
		chdir(wpb[no-top]->name);
		goto REDIR;
	    }
	    file = wpb[no-top]->name;
	    break;
	} else if ( ch == '\x1B' ) {
	    file = NULL;
	    break;
	} else if ( ch == '\x1E' ) {
	    if ( --no < 0 )
		no = max-1;
	} else if ( ch == '\x1F' ) {
	    if ( ++no >= max )
		no = 0;
	} else if ( ch == ' ' ) {
	    if ( ++cmp_mode > 2 )
		cmp_mode = 0;
	    goto REDIR;
	}
    }
ENDOF:
    for ( i = 0 ; i <= MAX+1 ; i++ ) {
	locate(DSP_X,DSP_Y+i);
	repchr(40,0x20);
    }
    pp_box(0,0);
    dsp_flg = FALSE;
    return file;
}
