#include    <stdio.h>
#include    <stdlib.h>
#include    <malloc.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	(4 * 1024)

static	char	*prog_name = "cp";
static	int	force_flg     = TRUE;
static	int	recursive_flg = TRUE;
static	int	verbose_flg   = FALSE;
static	int	update_flg    = FALSE;
static	int	verify_flg    = FALSE;
static	int	check_flg     = TRUE;

typedef	struct	_CP {
	struct	_CP	*next;
	char		*src_file;
	char		*dis_file;
} CPTR;

static	int		src_fp = EOF, dis_fp = EOF;
static	unsigned long	file_size = 0L;
static	DIRECT		src_stat;
static	CPTR		*copy_top = NULL;
static	char		io_buff[IO_BUFF_SIZE];

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);
    GETCH();
}
char	*file_name(char *file)
{
    int n;
    static char tmp[42];

    if ( (n = strlen(file)) <= 40 )
	return file;

    sprintf(tmp, "%-3.3s...%s", file, file + (n - 34));

    return tmp;
}
static	int	file_error(char *file)
{
    message("%s : %s", file_name(file), strerror(errno));
    return ERR;
}
int	copy_check()
{
    return (copy_top != NULL ? TRUE : FALSE);
}
int	copy_irq()
{
    int n, i;
    int rc, ch;
    CPTR *cp;
    unsigned read_size, write_size;
    char tmp[128];

    if ( copy_top == NULL )
	return FALSE;

    if ( src_fp == EOF )
	goto FILEOPEN;

    if ( _dos_read(src_fp, io_buff, IO_BUFF_SIZE, &read_size) ) {
	file_error(copy_top->src_file);
	goto ERROR;
    }

    if ( read_size == 0 )
	goto ENDOF;

    if ( _dos_write(dis_fp, io_buff, read_size, &write_size) ) {
	file_error(copy_top->dis_file);
	goto ERROR;
    }

    if ( read_size != write_size ) {
	message("%s : disk full ?", file_name(copy_top->dis_file));
	goto ERROR;
    }

    file_size += read_size;
    return FALSE;

ENDOF:

    if ( src_stat.d_size != file_size ) {
	message("%s : file read error ?", file_name(copy_top->src_file));
	goto ERROR;
    }

    if ( _dos_setftime(dis_fp, src_stat.d_date, src_stat.d_time) ) {
	file_error(copy_top->dis_file);
	goto ERROR;
    }

    _dos_close(dis_fp);

SKIP:
    _dos_close(src_fp);
    src_fp = EOF;

NEXT:
    copy_wind_check(copy_top->dis_file);
    cp = copy_top->next;
    free(copy_top->src_file);
    free(copy_top->dis_file);
    free(copy_top);
    copy_top = cp;
    SYSLINE("");

FILEOPEN:
    if ( copy_top == NULL )
	return FALSE;

    if ( dos_stat(copy_top->src_file, &src_stat) ) {
	file_error(copy_top->src_file);
	goto NEXT;
    }

    if ( _dos_open(copy_top->src_file, O_RDONLY, &src_fp) ) {
	file_error(copy_top->src_file);
	goto NEXT;
    }

    if ( _dos_creatnew(copy_top->dis_file, src_stat.d_att, &dis_fp) ) {
	file_error(copy_top->dis_file);
	goto SKIP;
    }

    file_size = 0L;

    i = 0;
    for ( n = 'A' ; n <= 'Z' ; n++ ) {
	for ( cp = copy_top ; cp != NULL ; cp = cp->next ) {
	    if ( *(cp->src_file) == n || *(cp->dis_file) == n ) {
		tmp[i++] = n;
		tmp[i++] = ':';
		break;
	    }
	}
    }
    tmp[i++] = ' ';
    strcpy(tmp + i, file_name(copy_top->dis_file));
    SYSLINE(tmp);

    return FALSE;

ERROR:
    _dos_close(src_fp);
    _dos_close(dis_fp);
    src_fp = EOF;

    if ( unlink(copy_top->dis_file) )
	file_error(copy_top->dis_file);

    goto NEXT;
}
char	*stralloc(char *str)
{
    char *p;

    if ( (p = (char *)malloc(strlen(str) + 1)) != NULL )
	strcpy(p, str);
    return p;
}
int	file_copy(char *src_file, char *dis_file)
{
    CPTR *cp, *tp;

    if ( (cp = (CPTR *)malloc(sizeof(CPTR))) == NULL ) {
	message("%s : malloc error", file_name(src_file));
	return ERR;
    }

    if ( (cp->src_file = stralloc(src_file)) == NULL ) {
	message("%s : malloc error", file_name(src_file));
	free(cp);
	return ERR;
    }

    if ( (cp->dis_file = stralloc(dis_file)) == NULL ) {
	message("%s : malloc error", file_name(dis_file));
	free(cp->src_file);
	free(cp);
	return ERR;
    }

    cp->next = NULL;
    if ( (tp = copy_top) == NULL )
	copy_top = cp;
    else {
	while ( tp->next != NULL )
	    tp = tp->next;
	tp->next = cp;
    }

    return FALSE;
}
static	int	chkdir(char *dir)
{
    int ch;
    int rc = 0;
    DIRECT st;

    if ( !dos_stat(dir, &st) ) {
	if ( !IS_DIR((&st)) ) {
	    message("%s : %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;
}
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 ( abort_check() )
	return ERR;

    if ( chkdir(dis_dir) )
	return ERR;

    if ( (dir = opendir(src_dir)) == NULL )
	return file_error(src_dir);

    if ( verbose_flg != FALSE ) {
	sz = 0L;
	while ( (dp = readdir(dir)) != NULL ) {
	    if ( dp->d_name[0] == '.' )
	        continue;
	    if ( !IS_DIR(dp) )
		sz += dp->d_size;
	}
	apend_scale(sz);
	seekdir(dir, 0);
    }

    while ( (dp = readdir(dir)) != NULL ) {
	if ( dp->d_name[0] == '.' )
	    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;
}
