#include    <stdio.h>
#include    <stdarg.h>
#include    <string.h>
#include    <errno.h>
#include    <dos.h>
#include    <fcntl.h>
#include    <share.h>
#include    "dir.h"

#define TRUE		1
#define FALSE		0
#define ERR		(-1)

#define	IO_BUFF_SIZE	(16 * 1024)

static	char	*prog_name = "cp";
static	int	force_flg     = TRUE;
static	int	recursive_flg = TRUE;
static	int	verbose_flg   = TRUE;
static	int	update_flg    = FALSE;
static	int	verify_flg    = FALSE;
static	int	check_flg     = TRUE;
static	char	io_buff[IO_BUFF_SIZE];

	char	*strform(char *tmp, char *str, int max);

/************
static	void    message(char *form, ...)
{
    va_list arg;
    char    tmp[128];

    va_start(arg, form);
    vsprintf(tmp, form, arg);
    va_end(arg);
    BEEP();
    SYSLINE(tmp);
}
*************/
char	*file_name(char *file)
{
    static char tmp[42];

    return strform(tmp, file, 40);
}
static	int	file_error(char *file)
{
    message("%s : %s", file_name(file), strerror(errno));
    return ERR;
}
int	file_copy(char *src_file, char *dis_file)
{
    int    sfp, dfp;
    int    ch, rc = 0;
    unsigned read_size, write_size;
    unsigned long file_size = 0L;
    DIRECT st, dt;

    if ( strcmp(src_file, dis_file) == 0 ) {
	message("%s -> %s\n重複したコピ−は出来ません", src_file, dis_file);
	return ERR;
    }

    if ( abort_check() )
	return ERR;

    if ( dos_stat(src_file, &st) )
	return file_error(src_file);

    if ( _dos_open(src_file, O_RDONLY, &sfp) )
	return file_error(src_file);

    if ( _dos_creatnew(dis_file, st.d_att, &dfp) ) {
	if ( check_flg && !dos_stat(dis_file, &dt) ) {
	    BEEP();
	    for ( ; ; ) {
		verbose("'%s' overwrite ? %s", file_name(dis_file),
			(rc == 0 ? "([Yes]/No) ?" : "(Yes/[No]) ?"));
		if ( (ch = yesno(&rc)) == ERR )
		    return ERR;
		else if ( ch == TRUE )
		    break;
	    }
	}
	if ( update_flg != FALSE && !dos_stat(dis_file, &dt) &&
		st.d_att == dt.d_att && st.d_size == dt.d_size &&
		st.d_date <= dt.d_date && st.d_time <= dt.d_time ) {
	    _dos_close(sfp);
	    return FALSE;
	}
	if ( force_flg == FALSE || _dos_creat(dis_file, st.d_att, &dfp) ) {
	    _dos_close(sfp);
	    return file_error(dis_file);
	}
    }

    if ( verbose_flg != FALSE )
	verbose("COPY %s", file_name(dis_file));

    for ( ; ; ) {
	if ( _dos_read(sfp, io_buff, IO_BUFF_SIZE, &read_size) ) {
	    file_error(src_file);
	    goto ERROR;
	}

	if ( read_size == 0 )
	    break;

	if ( _dos_write(dfp, io_buff, read_size, &write_size) ) {
	    file_error(dis_file);
	    goto ERROR;
	}

	if ( read_size != write_size ) {
	    message("%s : disk full ?", file_name(dis_file));
	    goto ERROR;
	}

	if ( verbose_flg != FALSE )
	    scale((unsigned long)read_size);

	file_size += read_size;
    }

    if ( st.d_size != file_size ) {
	message("%s : file read error ?", file_name(src_file));
	goto ERROR;
    }

    if ( _dos_setftime(dfp, st.d_date, st.d_time) ) {
	file_error(dis_file);
	goto ERROR;
    }

    _dos_close(sfp);
    _dos_close(dfp);

    return FALSE;

ERROR:
    _dos_close(sfp);
    _dos_close(dfp);

    if ( unlink(dis_file) )
	file_error(dis_file);

    return ERR;
}
static	int	chkdir(char *dir)
{
    int ch;
    int rc = 0;
    DIRECT st;

    if ( !dos_stat(dir, &st) ) {
	if ( !IS_DIR((&st)) ) {
	    message("%s : not directory", file_name(dir));
	    return ERR;
	}

	if ( check_flg ) {
	    BEEP();
	    for ( ; ; ) {
		verbose("%s : copy directory %s", file_name(dir),
			(rc == 0 ? "([Yes]/No) ?" : "(Yes/[No]) ?"));
		if ( (ch = yesno(&rc)) == ERR )
		    return ERR;
		else if ( ch == TRUE )
		    break;
	    }
	}

    } else {
	if ( mkdir(dir) )
	    return file_error(dir);
    }

    return FALSE;
}
static	int	dir_cmp(char *src, char *dis)
{
    while ( *src != '\0' ) {
	if ( *(src++) != *(dis++) )
	    return FALSE;
    }

    if ( *dis == '\0' || *dis == '\\' )
	return TRUE;

    return FALSE;
}
int	root_check(char *dir)
{
    return (dir[0] == '.' && (dir[1] == '.' || dir[1] == '\0') ? TRUE : FALSE);
}
int	dir_copy(char *src_dir, char *dis_dir)
{
    DIR    *dir;
    DIRECT *dp;
    DIRECT st;
    unsigned long sz;
    char   src_file[128];
    char   dis_file[128];

    if ( dir_cmp(src_dir, dis_dir) ) {
	message("%s -> %s\n重複したコピ−は出来ません", src_dir, dis_dir);
	return ERR;
    }

    if ( abort_check() )
	return ERR;

    if ( chkdir(dis_dir) )
	return ERR;

    if ( (dir = opendir(src_dir, 0)) == NULL )
	return file_error(src_dir);

    while ( (dp = readdir(dir)) != NULL ) {
	if ( root_check(dp->d_name) )
	    continue;

	strcpy(src_file, path_make(src_dir, dp->d_name));
	strcpy(dis_file, path_make(dis_dir, dp->d_name));

	if ( IS_DIR(dp) ) {
	    if ( recursive_flg == FALSE )
		continue;
	    if ( dir_copy(src_file, dis_file) )
		goto ERROR;
	    continue;
	}

	if ( file_copy(src_file, dis_file) )
	    goto ERROR;
    }

    closedir(dir);
    return FALSE;

ERROR:
    closedir(dir);
    return ERR;
}
unsigned long	dir_size(char *src_dir)
{
    DIR    *dir;
    DIRECT *dp;
    unsigned long sz = 0;
    char   tmp[128];

    if ( (dir = opendir(src_dir, 0)) == NULL )
	return file_error(src_dir);

    if ( verbose_flg != FALSE )
	verbose("SIZE %s...", file_name(src_dir));

    while ( (dp = readdir(dir)) != NULL ) {
	if ( root_check(dp->d_name) )
	    continue;
	if ( IS_DIR(dp) )
	    sz += dir_size(strcpy(tmp, path_make(src_dir, dp->d_name)));
	else
	    sz += dp->d_size;
    }

    closedir(dir);

    return sz;
}
