/***************
          1         2         3         4         5         6         7
01234567890123456789012345678901234567890123456789012345678901234567890123456789+--------------------------------------+--------------------------------------+
|A:\ABC\DEF\GHI                        |F:\T_OS                               |
|DIR 12345 / FILE 12345 SIZE 123456789 |                                      |
+--------------------------------------+--------------------------------------+
|12345678.123 12345678 94/10/25 11:15 *|12345678.123 12345678 94/10/25 11:15 *|
|12345678.123    <DIR> 94/10/25 11:15 *|                                      |
|                                      |                                      |
|                                      |                                      |
|                                      |                                      |
|                                      |                                      |
+--------------------------------------+--------------------------------------+
01234567890123456789012345678901234567890123456789012345678901234567890123456789****************/
#include    <stdio.h>
#include    <stdlib.h>
#include    <stdarg.h>
#include    <string.h>
#include    <malloc.h>
#include    <direct.h>
#include    "defs.h"
#include    "dir.h"
#include    "key.h"

#define	VERSION	"FWCP version 0.02 1995.03.03 Nanno-NET(Ken)"

	char	*config_file  = "\\lib\\fwcp.def";
	char	*termcap_file = NULL;
	char	*term_name    = NULL;

typedef	struct	{
	int	drv;
	DIR	*dir;
	int	top, otop;
	int	pos, opos;
	int	max;
	int	que;
	int	mode, stat;
	char	cwd[128];
} WIND;

static	WIND	wind_buf[2];
static	int	dir_menu_ent = 0;
static	int	dir_menu_max = 0;
static	char	**dir_menu_vct;

static	int		scale_pos = 0;
static	unsigned long	scale_total = 0;
static	unsigned long	scale_size = 0;

#define	HISDIRMAX	16
static	char	*chdir_vct[HISDIRMAX + 1];

	char	*stralloc(char *str);
	unsigned long dir_size(char *dir);

char	*strform(char *tmp, char *str, int max)
{
    int n, i;
    char *p;

    if ( strlen(str) < max )
	return strcpy(tmp, str);

    p = tmp;
    for ( n = 0 ; n < 3 ; ) {
	if ( iskan(str) ) {
	    *(p++) = *(str++);
	    *(p++) = *(str++);
	    n += 2;
	} else {
	    *(p++) = *(str++);
	    n += 1;
	}
    }

    *(p++) = '.';
    *(p++) = '.';
    *(p++) = '.';
    n += 3;

    i = strlen(str) - (max - n);
    while ( i > 0 ) {
	if ( iskan(str) ) {
	    str += 2;
	    i -= 2;
	} else {
	    str += 1;
	    i -= 1;
	}
    }

    while ( *str != '\0' )
	*(p++) = *(str++);
    *p = '\0';

    return tmp;
}
void	message(char *form, ...)
{
    int n;
    int len;
    int line = 1;
    int sx, sy;
    char *p, *s;
    va_list arg;
    char tmp[BUFSIZ];

    va_start(arg, form);
    vsprintf(tmp, form, arg);
    va_end(arg);

    n = len = 0;
    for ( p = tmp ; *p != '\0' ; ) {
	if ( *p == '\n' ) {
	    *(p++) = '\0';
	    line++;
	    n = 0;
	} else if ( iskanji(p[0]) && iskanji(p[1]) ){
	    n += 2;
	    p += 2;
	} else {
	    n++;
	    p++;
	}

	if ( n > len )
	    len = n;

	if ( n >= 70 ) {
	    for ( s = p ; *s != '\0' ; s++ )
		;
	    while ( s >= p ) {
		*(s + 1) = *s;
		s--;
	    }
	    *(p++) = '\0';
	    line++;
	    n = 0;
	}
    }

    sx = (SCR_X - len) / 2;
    sy = (SCR_Y - line) / 2;

    SAVESCREEN();
    CUROFF();
    ERRCOL();
    BLINKCOL();
    wind(sx - 1, sy, len + 2, line);
    NOMCOL();
    p = tmp;
    for ( n = 0 ; n < line ; n++ ) {
	LOCATE(sx, sy + n);
	PUTS(p);
	while ( *(p++) != '\0' )
	    ;
    }
    STDCOL();
    BEEP();
    FLUSH();

    while ( KBHIT() )
	GETCH();

    GETCH();

    LOADSCREEN();
    LOCATE(0, SCR_Y - 1);
    CURON();
    FLUSH();
}
void	scale(unsigned long sz)
{
    int n;    
    static char scl_char[]={ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x87 };

    if ( scale_total <= 0 )
	return;

    scale_size += sz;
    if ( scale_size >= 0x000FFFFFL )
	n = scale_size / (scale_total / 320L);
    else
	n = scale_size * 320L / scale_total;

    if ( scale_pos > n ) {
	LOCATE(20, 14);
	REPCHR(' ', 40);
	scale_pos = 0;
    }

    while ( scale_pos < n ) {
	LOCATE(20 + (scale_pos / 8), 14);
	PUTANK(scl_char[scale_pos % 8]);
	scale_pos++;
    }

    LOCATE(38, 12);
    if ( scale_size >= 0x00FFFFFFL )
	n = scale_size / (scale_total / 100L);
    else
	n = scale_size * 100L / scale_total;
    FPUTS("%3d%%", n);
    FLUSH();
}
void	init_scale(unsigned long sz)
{
    scale_total = sz;
    scale_pos = 0;
    scale_size = 0;
    CUROFF();
    SAVESCREEN();
    wind(20, 12, 40, 3);
    FLUSH();
}
void	apend_scale(unsigned long sz)
{
    scale_total += sz;
    scale(0);
}
void	finis_scale()
{
    scale_total = 0;
    LOADSCREEN();
    BEEP();
    LOCATE(0, SCR_Y - 1);
    CURON();
    FLUSH();
}
int	abort_check()
{
    int ch;

    if ( KBHIT() == 0 )
	return FALSE;
    ch = GETCH();
    switch(ch) {
    case K_ABORT:
    case K_END_OF:
	message("Copy Abort...");
	return ERR;
    }
    return FALSE;
}
void    verbose(char *form, ...)
{
    int n;
    va_list arg;
    char    tmp[128];

    va_start(arg, form);
    vsprintf(tmp, form, arg);
    va_end(arg);

    if ( strlen(tmp) > 78 )
	tmp[78] = '\0';

    SAVECUR();
    LOCATE(1, SCR_Y - 2);
    PUTS(tmp);
    REPCHR(' ', 77 - strlen(tmp));
    LOADCUR();
    FLUSH();
}
static	char	*file_name(char *name)
{
    int n = 0;
    static char tmp[16];

    if ( *name != '.' ) {
	while ( n < 8 && *name != '.' )
	    tmp[n++] = *(name++);
	while ( n < 8 )
	    tmp[n++] = ' ';
    }
    while ( n < 12 && *name != '\0' )
	tmp[n++] = *(name++);
    while ( n < 12 )
	tmp[n++] = ' ';
    tmp[n] = '\0';
    return tmp;
}
static	char	*file_time(int date, int time)
{
    static char tmp[24];

    sprintf(tmp, "%02d-%02d-%02d %02d:%02d",
                (((date >> 9) & 0x7F) + 80) % 100,
                (date >> 5) & 0x0F,
                date & 0x1F,
                (time >> 11) & 0x1F,
                (time >> 5) & 0x3F,
                time & 0x1F);
    return tmp;
}
static	int	file_check(char *p)
{
    while ( *p != '\n' && *p != '\0' ) {
        if ( !isdigit(*p) && !isalpha(*p) &&
                *p != '\\' && *p != '.' && *p != '_' )
            return ERR;
        p++;
    }
    return FALSE;
}
static	void	disp_attr(int mode)
{
    switch(mode) {
    case 0:		/* file name */
	MSGCOL();
	ATTSET(12);
	ACTCOL();
	ATTSET(26);
	break;
    case 1:		/* sub name */
	ACTCOL();
	ATTSET(8);
	MSGCOL();
	ATTSET(4);
	ACTCOL();
	ATTSET(26);
	break;
    case 2:		/* size */
	ACTCOL();
	ATTSET(13);
	MSGCOL();
	ATTSET(8);
	ACTCOL();
	ATTSET(17);
	break;
    case 3:		/* date & time */
	ACTCOL();
	ATTSET(22);
	MSGCOL();
	ATTSET(14);
	ACTCOL();
	ATTSET(2);
	break;
    }
}
static	void	disp_wind(int no)
{
    int n, x;
    int rc = FALSE;
    WIND *wp;
    DIRECT *dp;
    int dc = 0;
    int fc = 0;
    long sz = 0;
    char tmp[40];

    wp = &(wind_buf[no]);
    x = (no == 0 ? 1 : 40);

    if ( wp->dir == NULL )
	sprintf(tmp, "%c:", wp->drv + 'A' - 1);
    else
	strform(tmp, wp->cwd, 38);

    SAVECUR();
    LOCATE(x, 1);
    FPUTS("%-38.38s", tmp);

    if ( wp->dir == NULL ) {
	LOCATE(x, 2);
	PUTS("DIR ----- / FILE ----- SIZE --------- ");

	for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	    LOCATE(x, n);
	    REPCHR(' ', 38);
	}

    } else {
	seekdir(wp->dir, 0);
	while ( (dp = readdir(wp->dir)) != NULL ) {
	    if ( IS_DIR(dp) )
		dc++;
	    else {
		fc++;
		sz += dp->d_size;
	    }
	}
	LOCATE(x, 2);
	FPUTS("DIR %5d / FILE %5d SIZE %9ld ", dc, fc, sz);

	seekdir(wp->dir, wp->top);
	for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	    LOCATE(x, n);
	    if ( (dp = readdir(wp->dir)) == NULL )
		REPCHR(' ', 38);
	    else {
		if ( dp->d_mark )
		    ACTCOL();

		FPUTS("%-12.12s ", file_name(dp->d_name));
		if ( IS_DIR(dp) )
		    PUTS("   <DIR> ");
		else
		    FPUTS("%8ld ", dp->d_size);
		FPUTS("%s ", file_time(dp->d_date, dp->d_time));
		FPUTS("%c", file_check(dp->d_name) ? '*':' ');

		if ( wp->pos == (n - 4) ) {
		    LOCATE(x, n);
		    if ( dp->d_mark )
			BOLDCOL();
		    REVCOL();
		    disp_attr(wp->mode);
		}

		STDCOL();
		NOMCOL();
	    }
	}

	wp->opos = wp->pos;
	wp->otop = wp->top;
    }

    LOADCUR();
    FLUSH();
}
static	void	update_wind(int no)
{
    int n, x;
    WIND *wp;
    DIRECT *dp;

    wp = &(wind_buf[no]);
    x = (no == 0 ? 1 : 40);

    if ( wp->otop != wp->top ) {
	seekdir(wp->dir, wp->top);
	for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	    LOCATE(x, n);
	    if ( (dp = readdir(wp->dir)) == NULL )
		REPCHR(' ', 38);
	    else {
		if ( dp->d_mark )
		    ACTCOL();

		FPUTS("%-12.12s ", file_name(dp->d_name));
		if ( IS_DIR(dp) )
		    PUTS("   <DIR> ");
		else
		    FPUTS("%8ld ", dp->d_size);
		FPUTS("%s ", file_time(dp->d_date, dp->d_time));
		FPUTS("%c", file_check(dp->d_name) ? '*':' ');

		if ( wp->pos == (n - 4) ) {
		    LOCATE(x, n);
		    if ( dp->d_mark )
			BOLDCOL();
		    REVCOL();
		    disp_attr(wp->mode);
		}

		STDCOL();
		NOMCOL();
	    }
	}

    } else if ( wp->opos != wp->pos ) {
	if ( wp->opos >= 0 ) {
	    seekdir(wp->dir, wp->top + wp->opos);
	    if ( (dp = readdir(wp->dir)) != NULL && dp->d_mark )
		ACTCOL();
	    LOCATE(x, 4 + wp->opos);
	    ATTSET(38);
	    STDCOL();
	}
	if ( wp->pos >= 0 ) {
	    seekdir(wp->dir, wp->top + wp->pos);
	    if ( (dp = readdir(wp->dir)) != NULL && dp->d_mark )
		BOLDCOL();
	    REVCOL();
	    LOCATE(x, 4 + wp->pos);
	    disp_attr(wp->mode);
	    NOMCOL();
	    STDCOL();
	}
    }

    wp->opos = wp->pos;
    wp->otop = wp->top;
}
static	void	select_wind(int no)
{
    int n, x;

    x = (no == 0 ? 39 : 0);
    LOCATE( 0 + x, 0); ATTSET(40);
    LOCATE( 0 + x, 1); ATTSET(1); LOCATE(39 + x, 1); ATTSET(1);
    LOCATE( 0 + x, 2); ATTSET(1); LOCATE(39 + x, 2); ATTSET(1);
    LOCATE( 0 + x, 3); ATTSET(40);
    for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	LOCATE( 0 + x, n); ATTSET(1);
	LOCATE(39 + x, n); ATTSET(1);
    }
    LOCATE( 0 + x, SCR_Y - 3); ATTSET(40);

    x = (no == 0 ? 0 : 39);
    REVCOL();
    LOCATE( 0 + x, 0); ATTSET(40);
    LOCATE( 0 + x, 1); ATTSET(1); LOCATE(39 + x, 1); ATTSET(1);
    LOCATE( 0 + x, 2); ATTSET(1); LOCATE(39 + x, 2); ATTSET(1);
    LOCATE( 0 + x, 3); ATTSET(40);
    for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	LOCATE( 0 + x, n); ATTSET(1);
	LOCATE(39 + x, n); ATTSET(1);
    }
    LOCATE( 0 + x, SCR_Y - 3); ATTSET(40);
    NOMCOL();

    FLUSH();
}
void	screen_init(int no)
{
    int n;

    LOCATE(0, 0); PUTANK(0x9C); REPCHR(0x95, 38);
    PUTANK(0x91); REPCHR(0x95, 38); PUTANK(0x9D);

    LOCATE(0, 1); PUTANK(0x96); REPCHR(0x20, 38);
    PUTANK(0x96); REPCHR(0x20, 38); PUTANK(0x96);

    LOCATE(0, 2); PUTANK(0x96); REPCHR(0x20, 38);
    PUTANK(0x96); REPCHR(0x20, 38); PUTANK(0x96);

    LOCATE(0, 3); PUTANK(0x93); REPCHR(0x95, 38);
    PUTANK(0x8F); REPCHR(0x95, 38); PUTANK(0x92);

    for ( n = 4 ; n < (SCR_Y - 3) ; n++ ) {
	LOCATE(0, n); PUTANK(0x96); REPCHR(0x20, 38);
	PUTANK(0x96); REPCHR(0x20, 38); PUTANK(0x96);
    }

#if 0
    LOCATE(0, SCR_Y - 3); PUTANK(0x9E); REPCHR(0x95, 38);
    PUTANK(0x90); REPCHR(0x95, 38); PUTANK(0x9F);

    LOCATE(0, SCR_Y - 2); ERALINE();
    LOCATE(0, SCR_Y - 1); ERALINE();
#else
    LOCATE(0, SCR_Y - 3); PUTANK(0x93); REPCHR(0x95, 38);
    PUTANK(0x90); REPCHR(0x95, 38); PUTANK(0x92);

    LOCATE(0, SCR_Y - 2); PUTANK(0x96);
    REPCHR(0x20, 77); PUTANK(0x96);

    LOCATE(0, SCR_Y - 1); PUTANK(0x9E);
    REPCHR(0x95, 77); PUTANK(0x9F);
#endif

    select_wind(no);
}
int	chcwdrv(int drv)
{
    if ( _chdrive(drv) ) {
	message("chdrive %c: %s", drv - 1 + 'A', strerror(errno));
	return ERR;
    }
    return FALSE;
}
int	chcwdir(char *dir)
{
    if ( chdir(dir) ) {
	message("chdir %s %s", dir, strerror(errno));
	return ERR;
    }
    return FALSE;
}
int	exec_wind(int no)
{
    WIND *wp;
    DIRECT *dp;

    wp = &(wind_buf[no]);

    seekdir(wp->dir, wp->top + wp->pos);
    if ( (dp = readdir(wp->dir)) == NULL )
	return ERR;

    if ( IS_DIR(dp) ) {
	if ( chcwdir(dp->d_name) )
	    return ERR;
	return TRUE;
    } else {
	if ( more(dp->d_name) )
	    return ERR;
	return FALSE;
    }
}
int	mark_wind(int no, int mode)
{
    WIND *wp;
    DIRECT *dp;

    wp = &(wind_buf[no]);
    if ( wp->dir == NULL || wp->pos < 0 )
	return ERR;

    seekdir(wp->dir, wp->top + wp->pos);
    if ( (dp = readdir(wp->dir)) == NULL || root_check(dp->d_name) )
	return ERR;

    switch(mode) {
    case ERR:
	dp->d_mark = (dp->d_mark == TRUE ? FALSE : TRUE);
	break;
    case FALSE:
	dp->d_mark = FALSE;
	break;
    case TRUE:
	dp->d_mark = TRUE;
	break;
    }

    return FALSE;
}
int	all_mark_wind(int no)
{
    WIND *wp;
    DIRECT *dp;

    wp = &(wind_buf[no]);
    if ( wp->dir == NULL )
	return ERR;

    seekdir(wp->dir, 0);
    while ( (dp = readdir(wp->dir)) != NULL ) {
	if ( root_check(dp->d_name) )
	    continue;
	dp->d_mark = TRUE;
    }
    return FALSE;
}
int	skip_wind(int no)
{
    int n;
    WIND *wp;
    DIRECT *dp;

    wp = &(wind_buf[no]);
    if ( wp->dir == NULL )
	return ERR;

    n = (wp->pos < 0 ? 0 : (wp->top + wp->pos + 1));
    seekdir(wp->dir, n);
    while ( (dp = readdir(wp->dir)) != NULL ) {
	if ( wild_mach("*.GGG", dp->d_name) ||
	     wild_mach("*.RRR", dp->d_name) ||
	     wild_mach("*.BAK", dp->d_name) ||
	     wild_mach("*.DOC", dp->d_name) ) {
	    if ( (wp->pos = (n - wp->top)) > (SCR_Y - 8) ) {
		wp->pos = (SCR_Y - 8);
		wp->top = n - (SCR_Y - 8);
	    }
	    break;
	}
	n++;
    }
    return FALSE;
}
int	open_wind(int no)
{
    int n, i;
    WIND *wp;
    DIR  *dir = NULL;
    int  max = 0;
    char *p;
    char tmp[128];
    DIRECT *dp, *np;

    wp = &(wind_buf[no]);

    if ( wp->dir != NULL ) {
	max = wp->max;
	strcpy(tmp, wp->cwd);
	dir = wp->dir;
	wp->dir = NULL;
    }

    if ( chcwdrv(wp->drv) ||
	 getcwd(wp->cwd, 127) == NULL ||
	 (wp->dir = opendir(wp->cwd, wp->mode)) == NULL ) {
	if ( dir != NULL )
	    closedir(dir);
	return ERR;
    }

    for ( n = 0 ; chdir_vct[n] != NULL && n < HISDIRMAX ; n++ ) {
	if ( strcmp(chdir_vct[n], wp->cwd) == 0 ) {
	    p = chdir_vct[n];
	    for ( i = n ; i > 0 ; i-- )
		chdir_vct[i] = chdir_vct[i - 1];
	    chdir_vct[i] = p;
	    n = i;
	    break;
	}
    }
    if ( chdir_vct[n] == NULL ) {
	if ( chdir_vct[HISDIRMAX - 1] != NULL )
	    free(chdir_vct[HISDIRMAX - 1]);
	for ( n = (HISDIRMAX - 1) ; n > 0 ; n-- )
	    chdir_vct[n] = chdir_vct[n - 1];
	chdir_vct[0] = stralloc(wp->cwd);
    }

    wp->max = countdir(wp->dir);
    if ( max == 0 || max != wp->max || strcmp(tmp, wp->cwd) != 0 ) {
	wp->top = 0;
	wp->pos = (-1);

    } else if ( dir != NULL ) {
	seekdir(dir, 0);
	while ( (np = readdir(dir)) != NULL ) {
	    if ( np->d_mark == FALSE )
		continue;
	    seekdir(wp->dir, 0);
	    while ( (dp = readdir(wp->dir)) != NULL ) {
		if ( strcmp(np->d_name, dp->d_name) == 0 ) {
		    dp->d_mark = TRUE;
		    break;
		}
	    }
	}
    }

    if ( dir != NULL )
	closedir(dir);

    wp->stat = FALSE;
    return FALSE;
}
void	close_wind(int no)
{
    WIND *wp;

    wp = &(wind_buf[no]);

    if ( wp->dir != NULL ) {
	closedir(wp->dir);
	wp->dir = NULL;
    }

    wp->stat = ERR;
}
int	get_wind(int no, int sw, int max, char *buf)
{
    WIND *wp;
    DIRECT *dp;
    char *p;
    int len = 0;

    wp = &(wind_buf[no]);
    if ( wp->dir == NULL )
	return 0;

    if ( wp->pos >= 0 ) {
	seekdir(wp->dir, wp->top + wp->pos);
	if ( (dp = readdir(wp->dir)) == NULL )
	    return 0;
	p = (sw ? path_make(wp->cwd, dp->d_name) : dp->d_name);
    } else
	p = wp->cwd;

    while ( len < max && *p != '\0' )
	buf[len++] = *(p++);

    return len;
}
int	yesno(int *rc)
{
    int ch;

    ch = GETCH();
    switch(ch) {
    case K_ABORT:
    case K_END_OF:
    case 'N':
    case 'n':
    case 'ﾐ':
	return ERR;

    case 'Y':
    case 'y':
    case 'ﾝ':
	return TRUE;

    case ' ':
    case K_BACK_SPC:
    case K_LEFT_CUR:
    case K_RIGHT_CUR:
    case K_UP_NODE:
    case K_DOWN_NODE:
	*rc = (*rc == 0 ? 1 : 0);
	return FALSE;

    case K_END_LINE:
	return (*rc == 0 ? TRUE : ERR);
    }

    return FALSE;
}
int	copy_wind()
{
    int n, ch, rc;
    int copy_type = 0;
    DIRECT *dp;
    char *file;
    char src[128];
    char dis[128];
    char tmp[128];
    unsigned long sz;

    if ( wind_buf[0].dir == NULL || wind_buf[1].dir == NULL ) {
	message("ドライブ選択がされていません");
	return ERR;
    }

    seekdir(wind_buf[0].dir, 0);
    while ( (dp = readdir(wind_buf[0].dir)) != NULL ) {
	if ( !root_check(dp->d_name) && dp->d_mark )
	    break;
    }

    if ( dp != NULL ) {
	strcpy(src, path_make(wind_buf[0].cwd, dp->d_name));
	strcat(src, "...");
	copy_type |= 004;
#ifdef	SELCPY
    } else if ( wind_buf[0].pos >= 0 ) {
	seekdir(wind_buf[0].dir, wind_buf[0].top + wind_buf[0].pos);
	if ( (dp = readdir(wind_buf[0].dir)) == NULL )
	    return ERR;
	if ( dp->d_name[0] == '.' ) {
	    strcpy(src, path_make(wind_buf[0].cwd, "*.*"));
	    copy_type |= 003;
	} else {
	    strcpy(src, path_make(wind_buf[0].cwd, dp->d_name));
	    copy_type |= (IS_DIR(dp) ? 002 : 001);
	    file = dp->d_name;
	}
    } else {
	strcpy(src, path_make(wind_buf[0].cwd, "*.*"));
	copy_type |= 003;
    }
#else
    } else {
	message("マ−クされたファイルがありません");
	return ERR;
    }
#endif

#ifdef	SELCPY
    if ( wind_buf[1].pos >= 0 ) {
	seekdir(wind_buf[1].dir, wind_buf[1].top + wind_buf[1].pos);
	if ( (dp = readdir(wind_buf[1].dir)) == NULL )
	    return ERR;
	if ( dp->d_name[0] == '.' ) {
	    strcpy(dis, wind_buf[1].cwd);
	    copy_type |= 020;
	} else {
	    strcpy(dis, path_make(wind_buf[1].cwd, dp->d_name));
	    copy_type |= (IS_DIR(dp) ? 020 : 010);
	}
    } else {
	strcpy(dis, wind_buf[1].cwd);
	copy_type |= 020;
    }
#else
    seekdir(wind_buf[1].dir, 0);
    while ( (dp = readdir(wind_buf[1].dir)) != NULL ) {
	if ( !root_check(dp->d_name) && dp->d_mark )
	    break;
    }
    if ( dp != NULL ) {
	strcpy(dis, path_make(wind_buf[1].cwd, dp->d_name));
	copy_type |= (IS_DIR(dp) ? 020 : 010);
	dp->d_mark = FALSE;
    } else {
	strcpy(dis, wind_buf[1].cwd);
	copy_type |= 020;
    }
#endif

    rc = 0;
    for ( ; ; ) {
	LOCATE(1, SCR_Y - 2);
	REPCHR(' ', 77);
	LOCATE(1, SCR_Y - 2);
	PUTS("COPY ");
	PUTS(strform(tmp, src, 26));
	PUTS(" -> ");
	PUTS(strform(tmp, dis, 26));
	if ( rc == 0 )
	    PUTS(" ([Yes]/No) ? ");
	else
	    PUTS(" (Yes/[No]) ? ");
	FLUSH();

	if ( (ch = yesno(&rc)) == TRUE )
	    break;
	else if ( ch == ERR )
	    return ERR;
    }

#ifndef	CPIRQ
    sz = 0L;
    switch(copy_type) {
    case 011:			/* file -> file */
    case 021:			/* file -> dir */
	seekdir(wind_buf[0].dir, wind_buf[0].top + wind_buf[0].pos);
	if ( (dp = readdir(wind_buf[0].dir)) != NULL )
	    sz = dp->d_size;
	break;

    case 022:			/* dir  -> dir */
	rc = dir_size(src);
	break;

    case 023:			/* wild -> dir */
    case 024:			/* select -> dir */
	seekdir(wind_buf[0].dir, 0);
	while ( (dp = readdir(wind_buf[0].dir)) != NULL ) {
	    if ( root_check(dp->d_name) )
		continue;
	    if ( copy_type == 024 && dp->d_mark == FALSE )
		continue;
	    if ( IS_DIR(dp) )
		sz += dir_size(strcpy(tmp,
			path_make(wind_buf[0].cwd, dp->d_name)));
	    else
		sz += dp->d_size;
	}
	break;
    }
    init_scale(sz);
#endif

    rc = FALSE;
    switch(copy_type) {
    case 011:			/* file -> file */
	rc = file_copy(src, dis);
	break;

    case 012:			/* dir  -> file */
    case 013:			/* wild -> file */
    case 014:			/* select -> file */
	message("コピ−先をディレクトリにしてください");
	rc = ERR;
	break;

    case 021:			/* file -> dir */
	rc = file_copy(src, strcpy(tmp, path_make(dis, file)));
	break;

    case 022:			/* dir  -> dir */
	rc = dir_copy(src, strcpy(tmp, path_make(dis, file)));
	break;

    case 023:			/* wild -> dir */
	seekdir(wind_buf[0].dir, 0);
	while ( (dp = readdir(wind_buf[0].dir)) != NULL ) {
	    if ( root_check(dp->d_name) )
		continue;
	    strcpy(src, path_make(wind_buf[0].cwd, dp->d_name));
	    strcpy(tmp, path_make(dis, dp->d_name));
	    if ( IS_DIR(dp) ) {
		if ( (rc = dir_copy(src, tmp)) )
		    break;
	    } else {
		if ( (rc = file_copy(src, tmp)) )
		    break;
	    }
	}
	break;

    case 024:			/* select -> dir */
	seekdir(wind_buf[0].dir, 0);
	while ( (dp = readdir(wind_buf[0].dir)) != NULL ) {
	    if ( root_check(dp->d_name) || dp->d_mark == FALSE )
		continue;
	    strcpy(src, path_make(wind_buf[0].cwd, dp->d_name));
	    strcpy(tmp, path_make(dis, dp->d_name));
	    if ( IS_DIR(dp) ) {
		if ( (rc = dir_copy(src, tmp)) )
		    break;
	    } else {
		if ( (rc = file_copy(src, tmp)) )
		    break;
	    }
	    dp->d_mark = FALSE;
	}
	break;
    }

#ifndef	CPIRQ
    finis_scale();
#endif

    return FALSE;
}
void	copy_wind_check(char *file)
{
    char *p;
    char tmp[256];

    strcpy(tmp, file);
    if ( (p = strrchr(tmp, '\\')) != NULL ) {
	if ( *(p - 1) == ':' )
	    p++;
	*p = '\0';
    }

    if ( wind_buf[0].dir != NULL &&
		strcmp(tmp, wind_buf[0].cwd) == 0 ) {
	open_wind(0);
	disp_wind(0);
    }

    if ( wind_buf[1].dir != NULL &&
		strcmp(tmp, wind_buf[1].cwd) == 0 ) {
	open_wind(1);
	disp_wind(1);
    }
}
void	prompt(char *cwd)
{
    char *p;

    if ( (p = getenv("PROMPT")) == NULL )
	p = "[$p] ";

    while ( *p != '\0' ) {
	if ( *p == '$' ) {
	    switch(*(++p)) {
	    case 'E': case 'e':
		p++;
		putchar('\033');
		break;
	    case 'P': case 'p':
		p++;
		fputs(cwd, stdout);
		break;
	    default:
		putchar(*(p++));
		break;
	    }
	} else
	    putchar(*(p++));
    }
    fflush(stdout);
}
int	command(int no, char *str)
{
    int n;
    int rc;
    int len = 0;
    DIRECT *dp;
    char *p;
    char *cmd;
    char tmp[128];

    wind_buf[0].que = wind_buf[1].que = 0;

LOOP:
    rc = FALSE;
    cmd = str;
    len = 0;
    while ( *cmd != '\0' ) {
	if ( *cmd == '%' ) {
	    switch(*(++cmd)) {
	    case '%':
		if ( len < 127 )
		    tmp[len++] = '%';
		cmd++;
		break;

	    case '*':
		n = no;
		goto GETMARK;
	    case '1':
		n = 0;
		goto GETMARK;
	    case '2':
		n = 1;
	    GETMARK:
		if ( wind_buf[n].dir == NULL )
		    return FALSE;
		seekdir(wind_buf[n].dir, wind_buf[n].que);
		while ( (dp = readdir(wind_buf[n].dir)) != NULL ) {
		    wind_buf[n].que++;
		    if ( dp->d_mark )
			break;
		}
		if ( dp == NULL )
		    return FALSE;
		p = path_make(wind_buf[n].cwd, dp->d_name);
		while ( len < 127 && *p != '\0' )
		    tmp[len++] = *(p++);
		rc = TRUE;
		cmd++;
		break;

	    case 'x': case 'X':
		n = no;
		goto GETCWD;
	    case 's': case 'S':
		n = 0;
		goto GETCWD;
	    case 'd': case 'D':
		n = 1;
	    GETCWD:
		if ( wind_buf[n].dir != NULL ) {
		    for ( p = wind_buf[n].cwd ; len < 127 && *p != '\0' ; )
			tmp[len++] = *(p++);
		}
		cmd++;
		break;

	    default:
		if ( len < 127 )
		    tmp[len++] = '%';
		break;
	    }

	} else {
	    if ( len < 127 )
		tmp[len++] = *cmd;
	    cmd++;
	}
    }
    tmp[len] = '\0';

    prompt(wind_buf[1].dir == NULL ? "?" : wind_buf[no].cwd);
    printf("%s\n", tmp);

    if ( system(tmp) )
	return ERR;

    if ( rc )
	goto LOOP;

    return FALSE;
}
void	wait_loop()
{
}
void	wind_cur_up(int no)
{
    if ( wind_buf[no].pos == 0 && wind_buf[no].top > 0 )
	wind_buf[no].top--;
    else if ( wind_buf[no].pos < 0 ) {
	if ( wind_buf[no].max <= (SCR_Y - 8) ) {
	    wind_buf[no].top = 0;
	    wind_buf[no].pos = wind_buf[no].max - 1;
	} else {
	    wind_buf[no].pos = (SCR_Y - 8);
	    wind_buf[no].top =
		(wind_buf[no].max - 1) - wind_buf[no].pos;
	}
    } else
	wind_buf[no].pos--;
}
void	wind_cur_down(int no)
{
    if ( (wind_buf[no].top + 
		wind_buf[no].pos + 1) >= wind_buf[no].max ) {
	wind_buf[no].top = 0;
	wind_buf[no].pos = (-1);
    } else if ( wind_buf[no].pos < (SCR_Y - 8) )
	wind_buf[no].pos++;
    else
	wind_buf[no].top++;
}
void	wind_init(int no)
{
    if ( chcwdrv(wind_buf[no].drv) )
	close_wind(no);
    else {
	chcwdir(wind_buf[no].cwd);
	open_wind(no);
    }
}
void	wind_chdir(int no, char *dir)
{
    if ( dir[1] == ':' )
	wind_buf[no].drv = toupper(dir[0]) - 'A' + 1;

    if ( chcwdrv(wind_buf[no].drv) )
	close_wind(no);
    else {
	chcwdir(dir);
	open_wind(no);
    }
}
void	wind_command(int no, char *buf)
{
    int n;

    if ( buf[0] == '\0' ) {
	if ( wind_buf[no].dir == NULL ) {
	    open_wind(no);
	} else if ( chcwdrv(wind_buf[no].drv) ) {
	    close_wind(no);
	} else if ( chcwdir(wind_buf[no].cwd) ) {
	    open_wind(no);
	} else {
	    if ( wind_buf[no].pos < 0 ) {
		wind_buf[no].max = 0;
		open_wind(no);
	    } else if ( exec_wind(no) )
		open_wind(no);
	}
	disp_wind(no);

    } else if ( buf[0] != '\0' && buf[1] == ':' &&
		buf[2] == '\0' ) {
	wind_buf[no].drv = toupper(buf[0]) - 'A' + 1;
	open_wind(no);
	disp_wind(no);

    } else {
	if ( wind_buf[no].dir != NULL && !chcwdrv(wind_buf[no].drv) )
	    chcwdir(wind_buf[no].cwd);

	LOCATE(0, SCR_Y - 1);
	FLUSH();

	Console_Load();
	command(no, buf);
	Console_Save();

	REFLUSH();
	wind_buf[no].drv = _getdrive();
	open_wind(no);
	disp_wind(no);

	n = (no == 0 ? 1 : 0);
	if ( wind_buf[n].dir == NULL )
	    open_wind(n);
	else
	    wind_init(n);
	disp_wind(n);
    }
}
int	fwcp()
{
    int n, i;
    int ch;
    int no = 0;
    char buf[128 + 2];

    screen_init(no);

    wind_buf[0].drv = wind_buf[1].drv = _getdrive();

    open_wind(0);
    disp_wind(0);

    open_wind(1);
    disp_wind(1);

    memset(buf, 0, 128);
    strcpy(buf, VERSION);

    for ( ; ; ) {
	ch = input(1, SCR_Y - 2, 77, 128, no, buf);

	switch(ch) {
	case K_END_OF:
	    if ( wind_buf[no].dir != NULL && !chcwdrv(wind_buf[no].drv) )
		chcwdir(wind_buf[no].cwd);
	    return ERR;

	case K_WIND_CNG:
	    no = (no == 0 ? 1 : 0);
	    select_wind(no);
	    break;

	case K_MARK_FILE:
	    if ( !mark_wind(no, ERR) )
		disp_wind(no);
	    break;

	case K_MARK_ALL:
	    if ( !all_mark_wind(no) )
		disp_wind(no);
	    break;

	case K_COPY_WIND:
	    if ( copy_wind() )
		break;
	    wind_init(0);
	    disp_wind(0);
	    wind_init(1);
	    disp_wind(1);
	    break;

	case K_DRV_MENU:
	    SAVESCREEN();
	    n = drv_menu((no == 0 ? 12 : 51), 5, wind_buf[no].drv);
	    LOADSCREEN();
	    FLUSH();

	    if ( n != wind_buf[no].drv ) {
		wind_buf[no].drv = n;
		open_wind(no);
		disp_wind(no);
	    }
	    break;

	case K_DIR_MENU:
	    if ( dir_menu_max <= 0 )
		break;

	    SAVESCREEN();
	    n = menu((no == 0 ? 10 : 49), 5, 0, dir_menu_vct);
	    LOADSCREEN();
	    FLUSH();

	    if ( n >= 0 ) {
		wind_chdir(no, dir_menu_vct[n]);
		disp_wind(no);
	    }
	    break;

	case K_HIS_DIR:
	    if ( chdir_vct[0] == NULL )
		break;

	    SAVESCREEN();
	    n = menu((no == 0 ? 8 : 47), 5, 0, chdir_vct);
	    LOADSCREEN();
	    FLUSH();

	    if ( n >= 0 ) {
		wind_chdir(no, chdir_vct[n]);
		disp_wind(no);
	    }
	    break;

	case K_TREE_DIR:
	    if ( chcwdrv(wind_buf[no].drv) )
		break;;

	    SAVESCREEN();
	    n = menutree((no == 0 ? 6 : 45), 5);
	    LOADSCREEN();
	    FLUSH();

	    if ( !n ) {
		open_wind(no);
		disp_wind(no);
	    }
	    break;

	case K_INIT_WIND:
	    wind_buf[no].max = 0;
	    if ( wind_buf[no].dir == NULL )
		open_wind(no);
	    else
		wind_init(no);
	    disp_wind(no);
	    break;

	case K_END_LINE:
	    wind_command(no, buf);
	    break;

	case K_UP_NODE:
	    if ( wind_buf[no].dir != NULL ) {
	        wind_cur_up(no);
	        update_wind(no);
	    }
	    break;

	case K_DOWN_NODE:
	    if ( wind_buf[no].dir != NULL ) {
	        wind_cur_down(no);
	        update_wind(no);
	    }
	    break;

	case K_UP_MARK:
	    if ( wind_buf[no].dir != NULL ) {
	        wind_cur_up(no);
		mark_wind(no, FALSE);
	        update_wind(no);
	    }
	    break;

	case K_DOWN_MARK:
	    if ( wind_buf[no].dir != NULL ) {
		mark_wind(no, TRUE);
	        wind_cur_down(no);
	        update_wind(no);
	    }
	    break;

	case K_SKIP_DOC:
	    if ( !skip_wind(no) )
		disp_wind(no);
	    break;

	case K_SCREEN_FLUSH:
	    REFLUSH();
	    FLUSH();
	    break;

	case K_CONSOLE:
	    Console_Load();
	    GETCH();
	    REFLUSH();
	    FLUSH();
	    break;

	case K_SORT_MODE:
	    if ( ++wind_buf[no].mode > 3 )
		wind_buf[no].mode = 0;
	    wind_init(no);
	    disp_wind(no);
	    break;

	case K_HELP:
	    SAVESCREEN();
	    CLS();
	    key_map();
	    FLUSH();
	    GETCH();
	    LOADSCREEN();
	    FLUSH();
	    break;
	}
    }

    return ERR;
}

static	void	file_defs(FILE *fp, char *tmp)
{
    char *p;

    while ( fgets(tmp, LINSIZ, fp) != NULL ) {
	if ( (p = strchr(tmp, '\n')) != NULL )
	    *p = '\0';
	if ( strcmp(tmp, "#end") == 0 )
	    break;
	if ( (p = strchr(tmp, '=')) == NULL )
	    continue;
	*(p++) = '\0';
	while ( isspace(*p) )
	    p++;
	if ( *p == '\0' )
	    continue;

	if ( strcmp(tmp, "TERMCAP") == 0 )
	    termcap_file = strdup(p);
	else if ( strcmp(tmp, "TERM") == 0 )
	    term_name = strdup(p);
    }
}
static	void	chdir_defs(FILE *fp, char *tmp)
{
    char *p;

    while ( fgets(tmp, LINSIZ, fp) != NULL ) {
	if ( (p = strchr(tmp, '\n')) != NULL )
	    *p = '\0';
	if ( strcmp(tmp, "#end") == 0 )
	    break;
	if ( tmp[0] == '\0' )
	    continue;

	dir_menu_vct[dir_menu_max++] = strdup(tmp);

        if ( dir_menu_max >= dir_menu_ent ) {
            dir_menu_ent += 8;
            if ( (dir_menu_vct = (char **)realloc(dir_menu_vct,
			sizeof(char *) * dir_menu_ent)) == NULL ) {
		fprintf(stderr, "chdir menu malloc error\n");
                exit(1);
	    }
        }

	dir_menu_vct[dir_menu_max] = NULL;
    }
}
int	config(char *file)
{
    FILE *fp;
    char *p;
    char tmp[LINSIZ + 2];

    if ( (fp = fopen(file,"r")) == NULL )
	return ERR;

    while ( fgets(tmp, LINSIZ, fp) != NULL ) {
	if ( (p = strchr(tmp, '\n')) != NULL )
	    *p = '\0';
	if ( strcmp(tmp, "#keydef") == 0 )
	    key_defs(fp, tmp);
	else if ( strcmp(tmp, "#filedef") == 0 )
	    file_defs(fp, tmp);
	else if ( strcmp(tmp, "#chdir") == 0 )
	    chdir_defs(fp, tmp);
    }

    fclose(fp);

    return FALSE;
}
void _interrupt _cdecl _far abort_handler(
	unsigned _es,	unsigned _ds,
	unsigned _di,	unsigned _si,
	unsigned _bp,	unsigned _sp,
	unsigned _bx,	unsigned _dx,
	unsigned _cx,	unsigned _ax,
	unsigned _ip,	unsigned _cs,
	unsigned _flag)
{
 _asm {
    mov ax,_ax
    mov al,03h
    mov _ax,ax
 }
}
int	main(int ac, char *av[])
{
    char *p;
    char tmp[128];

    dir_menu_ent = 8;
    dir_menu_vct = (char **)malloc(sizeof(char *) * 8);

    if ( config("fwcp.def") ) {
	if ( (p = getenv("FWCP")) == NULL || config(p) ) {
	    strcpy(tmp, av[0]);
	    if ( (p = strrchr(tmp, '\\')) != NULL ||
		 (p = strrchr(tmp, ':')) != NULL ) {
		strcpy(p + 1, "fwcp.def");
		if ( config(tmp) )
		    config(config_file);
	    } else
		config(config_file);
	}
    }

    DSKINIT();

    Console_Save();
    if ( SCRNINIT(term_name) ) {
	fprintf(stderr, "Screen init error");
	exit(1);
    }

    KEYINIT();

    _dos_setvect(0x24, abort_handler);

    while ( !fwcp() )
	;

    SCRNEND();
    KEYEND();
    Console_Load();

    return 0;
}
