/** ask copy / time stamp copy  **********************************************/
/*	"〜"を取り込むため__main2.oをリンクすること
	gcd acopy32 -om2						     */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iocslib.h>
#include "doslibm.h"
#include "deftype.h"
#include "astdio.h"
#include "astring.h"
#include "amacro.h"
#include "akey.h"
#include "acmp.h"
#include "acdata.h"
#include "aparam.h"
#include "afile.h"
#include "etc.h"
#include "fat32.h"
#include "s_secreadc.h"

//#define	DEBUG	1

char prog[]="@@> ACOPY32.C : 2000/12/05 TUE : COMMAND : ACOPY32/TCOPY32 : X680x0 : GCC";
/*
2000/09/14 FAT32対応版
		削除	moveモード
			英大文字小文字区別
			物理ドライブ対応
			エラー音
2000/09/20 /?時のメッセージが間違っていたので修正
2000/10/03 ロングファイル名対応
2000/10/19 ファイル名長定数をfat32.hのそれに合わせて変更
	   ロングファイル名関数差し替えに対応（実行ファイル大幅サイズ縮小）
2000/10/20 送り先ファイル存在判定が間違っていたので修正
	   ファイル名要素格納エリア長が間違っていたので修正
2000/10/23 ファイル名に一部ロングファイル名を使うようにする
2000/10/24 バグ取り（謎の暴走の解明）
2000/10/25 キャッシュ対応（高速化）
2000/10/26 スペース入り名前のアクセスに問題が多いのでオプション化
2000/10/27 スペース入りファイルが読み込めなかったので修正
	   （' '->'_'変換は元ファイル名ではなく先ファイル名で変換しなければならなかった。）
	   ファイル名長が１８を越える時にエラーが出るのを修正
2000/11/01 TwentyOneは+Tでないと２１文字判定しないので修正
	   マルチピリオド、特殊文字の判定を強化
	   ファイル名長判定に置ける拡張子位置の判定の間違いを修正
2000/11/02 ファイル名表示においてエスケープシーケンスによる行クリアがあったのをB_ERA_*()にして
	   リダイレクト無いようにエスケープシーケンスが入らないようにした
	   ファイル名変換に問題があったのを修正
2000/12/05 FILE32のサイズが大きくなりスタックをオーバーする可能性が出てきたのでmalloc()
	   による確保に変更した。
*/
/*****************************************************************************/
/* グローバル変数 */

#define	ALLBLOCK	1024	// キャッシュセクター数
static	int	cmode=0,attr=FA_ARCH|FA_RONLY;
static	int	fask,fhide,fsys,fnew,fsize,fkbclr,fnone;
static	int	ftrace,frep,fdir;
static	int	fnomit=0,feomit=0,fall;
static	int	cfile=0;
static	int	fs_date,fs_date_mode,fs_time,fs_time_mode,fs_size,fs_size_mode;
static	int	vflag;
static	unint	cbsize;
static	unchar	*cbuff,*mes;
static	unchar	drv2[MAXDRIVE32],dir2[MAXDIR32],name2[MAXFILE32]
					,ext2[MAXEXT32],fname2[MAXPATH32];
static	int	flazy;	// 遅延書き込み
static	int	flmax;	// ファイル名規定長
static	unchar	fnchg[16];	// ファイル名の文字変換パターン
#ifdef DEBUG
FILE	*fpstdout;
#endif

#define	MAXSHORT	(MAXSHORTFILEEXT-2)	// -'.'-EOS

/*****************************************************************************/

void printsss(unchar *s1,unchar *s2,unchar *s3)
/* ３文字列表示 */
{
	printss(s1,s2);
	prints(s3);
}

void printsssn(unchar *s1,unchar *s2,unchar *s3)
/* ３文字列表示＋改行 */
{
	printsss(s1,s2,s3);
	crlf();
}

/*****************************************************************************/

void ChangeName(unchar *fname)
// ファイル名中に特殊文字がある時、規則に従って変換
{
int i;
	if ((i=kstrchar2(fname,fnchg))!=-1) { // ファイル名中に特殊文字がある
		do {
			fname=&fname[i];
			#ifdef DEBUG
			fprintf2(fpstdout,"i=%d,fname=%s,fnchg=%s←\n",i,fname,fnchg);
			#endif
			if (!(*fname=='.'
			 && (
			   // 末尾に'.'は来ないので+1は判定無し
  			      *(fname+2)==0 // 拡張子に出来る'.'は許す
			   || *(fname+3)==0
			   || *(fname+4)==0
			    )
			)) *fname='_';
			i=kstrchar2(++fname,fnchg);
		} while (i!=-1);
		// 漢字２バイト目に' 'はないので大丈夫
	} // ファイル名中にスペースはない
}

unchar *SelectFname(FILE32 *fp,int max)
// ファイル名長により、ロングファイル名かショートファイル名を選択する。
// 名前にスペースを許さない時は' '->'_'変換もする。
// ファイルとディレクトリとで変えるため、最大長は引数としている。
{
int len;
	if (fp->lname[0]!=0) { // ロングファイル名がある
	    if ((len=strlen(fp->lname))<max) { // 規定長以下である
		// ロングファイル名が使える
		return(fp->lname);
	    } // 規定長より長い
	    if (len<max+1+3) { // 拡張子込みなら入る？
	    	// .ext[EOS]
	    	//-4321  0  末尾に'.'が来ることはない
	    	if (fp->lname[len-2]=='.'
	    	  ||fp->lname[len-3]=='.'
	    	  ||fp->lname[len-4]=='.') return(fp->lname); // 入る
	    }
	} // ロングファイル名がない
	// ショートファイル名
	return(fp->name);
}

/*****************************************************************************/

int nsd_check(FILE32 *fp)
/* サイズ、日付、時刻 */
{
int ret;
	/* サイズ判定 */
	switch (fs_size_mode) {
		case 1:/* 以下 */
			if (fp->filelen>fs_size) return(1);
			break;
		case 2:/* 以上 */
			if (fp->filelen<fs_size) return(1);
			break;
		case 3:/* のみ */
			if (fp->filelen!=fs_size) return(1);
			break;
	}
	
	/* 日付判定 */
	if (fs_date_mode) {
		ret=cmp_date(fp->date,fs_date);
		switch (fs_date_mode) {
			case 1:/* 以前 */
				if (ret==2) return(1);
				break;
			case 2:/* 以降 */
				if (ret==1) return(1);
				break;
			case 3:/* のみ */
				if (ret!=0) return(1);
				break;
		}
	}
	
	/* 時間判定 */
	if (fs_time_mode) {
		ret=cmp_time(fp->time,fs_time);
		switch (fs_time_mode) {
			case 1:/* 以前 */
				if (ret==2) return(1);
				break;
			case 2:/* 以降 */
				if (ret==1) return(1);
				break;
			case 3:/* のみ */
				if (ret!=0) return(1);
				break;
		}
	}
	return(0);
}

/*****************************************************************************/

int ask(unchar *mes,unchar *path)
{
int ky;
	if (fask) {
		if (flazy) lazyupdate_flush(); // キー待ちのある時は、その都度書き出す（安全性重視）
		printsss(mes,path," ? (Y/N) : ");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky==-2) crlf(); // ESC
		if (ky) return(ky); // N/ESC
	}
	B_ERA_AL(); printsssn("\r",mes,path);
	//printsssn("\r\x1b[0K",mes,path);
	#ifdef DEBUG
	if (strlen(path)>=MAXPATH) {
		printf2("パス名が長すぎます\n");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky==-2) crlf(); // ESC
		if (ky) return(ky); // N/ESC
	}
	#endif
	return(0);
}

/*****************************************************************************/

int md(unchar *drv,unchar *dir,unchar *dir2)
/* 送り先ディレクトリ作成 */
{
// スタックオーバーを防ぐためstaticにする
static _FILBUF fblock;
static unchar path[MAXPATH32],path2[MAXPATH32];
int ky;
	strmfp3(path,drv,dir,dir2);
	#ifdef DEBUG
	if (strlen(path)>=MAXPATH) {
		printf2("パス名が長すぎます\n");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky==-2) crlf(); // ESC
		if (ky) return(ky); // N/ESC
	}
	fprintf2(fpstdout,"path=%s\ndrv=%s\ndir=%s\ndir2=%s\n",path,drv,dir,dir2);
	#endif
	if (FILES(&fblock,path,FA_DIREC)<0) { /* ディレクトリ存在チェック */
		/* ディレクトリがない時は作成 */
		ky=ask("mkdir ",path);
		if (ky) return(ky); // N/ESC
		if (!ftrace) {
			/* ディレクトリ作成 */
			if (MKDIR(path)<0) {
				printsn("ディレクトリが作れません：",path);
				return(11);
			}
		}
	} /* ディレクトリはすでに存在する時->内部移動処理のみ */
	/* 内部移動処理 */
	strmfp3(path2,"",dir,dir2);
	#ifdef DEBUG
	fprintf2(fpstdout,"path2=%s\ndir=%s\ndir2=%s\n",path2,dir,dir2);
	#endif
	strcpy(dir,path2);
	return(0);
}

/*****************************************************************************/

int rd(unchar *drv,unchar *dir,unchar *dir2)
/* 送り先ディレクトリ削除 */
{
// スタックオーバーを防ぐためstaticにする
static unchar path[MAXPATH32];
int ky;
	strmfp3(path,drv,dir,dir2);
	#ifdef DEBUG
	if (strlen(path)>=MAXPATH) {
		printf2("パス名が長すぎます\n");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky==-2) crlf(); // ESC
		if (ky) return(ky); // N/ESC
	}
	#endif
	/* ディレクトリがない時は作成 */
	ky=ask("rmdir ",path);
	if (ky) return(ky); // N/ESC
	if (!ftrace) {
		if (RMDIR(path)<0) return(1);
	}
	return(0);
}

/*****************************************************************************/

int mc_main(unchar *src,unchar *des)
/* コピー処理本体 */
// src : FAT32 , des=FAT16/12
{
int ky;
	prints(src);
	if (fask) {
		if (flazy) lazyupdate_flush(); // キー待ちのある時は、その都度書き出す（安全性重視）
		prints("\x1b[s\tCopy? (Y/N) : ");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky==-2) crlf();
		if (ky) return(ky);
		prints("\x1b[u");
	}
	B_ERA_ED(); printsn("\t→ ",des);
	//printsn("\x1b[0K\t→ ",des);
	return(ftrace? 0:vfile_copy32(src,des,cbuff,cbsize,vflag,1,1,2,NULL));
}

/*****************************************************************************/

int CheckTcopy(FILE32 *fp,unchar *fname2)
// Tcopy時のコピー判定
{
// スタックオーバーを防ぐためstaticにする
static _FILBUF fblock2;
int ret;
	/* まずコピー先ファイルサーチ */
	if (FILES(&fblock2,fname2,FA_ARCH|FA_RONLY|FA_HIDE|FA_SYS)<0) {
		/* ファイルがない＝新ファイル */
		if (fnew) return(0); /* new file not copy */
	} else { /* 同じ名前のファイルがある */
		if (fnone) return(0); /* 送り先にあるﾌｧｲﾙはｺﾋﾟｰしない */
		/* 日付比較 */
		ret=cmp_date(fp->date,fblock2.date);
		/* ret==2 : 新しい */
		if (ret==1) return(0); /* 元の方が古かった */
		if (ret==0) { /* 日付は同じだった */
			/* 時間比較 */
			ret=cmp_time(fp->time,fblock2.time);
			/* ret==2 : 新しい */
			if (ret==1) return(0); /* 元の方が古かった */
			if (ret==0) { /* 時間も同じだった */
				/* size copy mode only */
				if (fsize || fp->filelen==fblock2.filelen) return(0);
			}
		}
	}
	// コピーする
	return(1);
}

/*****************************************************************************/

int copy(unchar *fname,int dan)
/* コピーメイン */
/* fname:元ファイル名(FAT32) */
{
FILE32 *fp;
int c,count,ret=0;
unchar *work;
#if 0
unchar name[MAXFILE32],ext[MAXEXT32],drv[MAXDRIVE32],dir[MAXDIR32];
unchar sname[MAXFILE32],sext[MAXEXT32];
unchar sdir[MAXDIR32],sdir2[MAXDIR32];
unchar fname0[MAXPATH32];
#endif
unchar *name,*ext,*drv,*dir;
unchar *sname,*sext;
unchar *sdir,*sdir2;
unchar *fname0;
	// ワークエリアの動的確保
	// スタック不足を回避するため
	work=malloc(sizeof(FILE32)+MAXFILE32+MAXEXT32+MAXDRIVE32+MAXDIR32
			+MAXFILE32+MAXEXT32
			+MAXDIR32+MAXDIR32+MAXPATH32);
	if (work==NULL) {
		prints("ワークエリアが確保出来ません\n");
		exit(55);
	}
	fp=(FILE32 *)work;
	name=&work[sizeof(FILE32)];
	ext=&name[MAXFILE32];
	drv=&ext[MAXEXT32];
	dir=&drv[MAXDRIVE32];
	sname=&dir[MAXDIR32];
	sext=&sname[MAXFILE32];
	sdir=&sext[MAXEXT32];
	sdir2=&sdir[MAXDIR32];
	fname0=&sdir2[MAXDIR32];
	//
	c=vfnsplit32(fname,drv,dir,name,ext,attr,fp,1);
	strcpy(sname,name);
	strcpy(sext,ext);
	#ifdef DEBUG
	fprintf2(fpstdout,"\n段=%d,drv=%s,dir=%s,name=%s,ext=%s\n",dan,drv,dir,name,ext);
	#endif
	
	if (dan==0) {
	    if (fall==2) {
		if (strcmpi(drv,drv2)==0) {
		    printsn("同一ドライブでは/ALL2は使えません:",drv);
		    ret=113;
		    goto COPY_END;
		}
		//if (!(dir2[1]==0&&dir[1]==0&&dir2[0]=='\\'&&dir[0]=='\\')) {
		if (!((dir[1]==0 && dir[0]=='\\')||dir[0]==0)) {
		    /* カレントディレクトリ作成 */
		    /* ただし、ルートディレクトリの時は作らない */
		    /* dir[]先頭の'\'を飛ばす */
		    #ifdef DEBUG
		    fprintf2(fpstdout,"dir=%s,dir2=%s\n",dir,dir2);
		    #endif
		    if (md(drv2,dir2,&dir[1])) {
		    	ret=(111);
		    	goto COPY_END;
		    }
		}
	    }
	}
	if (c) { // ファイルが存在しない
		#ifdef DEBUG
		printsn("ファイルが存在しない:",fname);
		#endif
		goto DIR_DIR;
	}
	
	do {
		#ifdef DEBUG
		fprintf2(fpstdout,"atr=%02x,fname=%s\n",fp->atr,SelectFname(fp,flmax));
		#endif
		if (fp->atr&(FA_DIREC|FA_VOL)) {
			#ifdef DEBUG
			fprintf2(fpstdout,"dir/vol\n");
			#endif
			continue; /* MS-DOSﾃﾞｨｽｸ対応 */
		}
		if (nsd_check(fp)) {
			#ifdef DEBUG
			fprintf2(fpstdout,"nsd\n");
			#endif
			continue;
		}
		
		c=fp->atr;
		if (!fhide && (c & FA_HIDE)) {
			#ifdef DEBUG
			fprintf2(fpstdout,"hide\n");
			#endif
			continue; /* hidden file */
		}
		if (!fsys  && (c & FA_SYS)) {
			#ifdef DEBUG
			fprintf2(fpstdout,"sys\n");
			#endif
			continue; /* system file */
		}
		
		/* 転送元フルパス名作成
			FILES32/NFILES32はファイル名と拡張子しか返さないから */
		#ifdef DEBUG
		fprintf2(fpstdout,"SelectFname=%s;;\n",SelectFname(fp,flmax));
		#endif
		strmfp30(fname,drv,dir,SelectFname(fp,flmax)); // 一端結合してから
		strsfn32(fname,drv,dir,name,ext); // 分解
		#ifdef DEBUG
		fprintf2(fpstdout,"転送元フルパス名=%s\n",fname);
		#endif
		
		/* 転送先名 */
		strmfn(fname2,drv2,dir2,(fnomit? name:name2),(feomit? ext:ext2));
		ChangeName(fname2);
		if (strcmpi(fname,fname2)==0) {
		    printss(mes,"元と"); printsssn(mes,"先が同じです:",fname);
		    /*continue;*/
		    ret=(100);
		    goto COPY_END;
		}
		
		if (cmode>=2) { /* TCOPY mode */
			if (!CheckTcopy(fp,fname2)) continue;
		}
		
		/* コピー */
		c=mc_main(fname,fname2);
		//printf2("ret=%d\n",c);
		if (c) {
		    switch (c) {
			case -1:continue; /* -1 : not copy */
	        	case 1:	printsn("ファイルが読み込めません:",fname);
				c=5;
				break;
	        	case 2:	printsn("ファイルに書き込めません:",fname2);
				c=6;
				break;
	        	case 3:	printsn("ディスクがいっぱいです:",drv2);
				c=7;
				break;
	        	case 4:	printsn("Ｖｅｒｉｆｙエラーです:",drv2);
				c=8;
				break;
	        	case 5:	printsn("読み込みオープンエラー:",fname);
				c=10;
				break;
	        	case 6:	printsn("書き込みオープンエラー:",fname2);
				c=11;
				break;
			case -2: /* BREAK */
				crlf();
				c=9;
		    }
		    ret=(100+c);
		    goto COPY_END;
		}
	        /* ok */
		cfile++;
	} while (NVFILES32(fp)>=0);
    DIR_DIR:
	/* 再帰消去指定ない／１段のみ */
	if (fdir==0 || (fdir==1 && dan==1)) goto COPY_END;
	
	/*（２）ディレクトリ */
	strmfp30(sdir,drv,dir,"*.*"); /* ディレクトリ名の制限はない */
	if (VFILES32(fp,sdir,FA_DIREC)<0) {
		ret=(1);
		goto COPY_END;
	}
	do {
		if (CheckParentDir(fp->name)) continue; /* ./.. cut */
		
		strmfp30(sdir,drv,dir,SelectFname(fp,MAXSHORT)); /* drive+dir名 */
		strmfp20(fname,sdir,sname,sext); /* サーチフルパス名 */
		if (fall) { /* コピー先ディレクトリ作成 */
			unchar drv3[MAXDRIVE32],dir3[MAXDIR32];
			/* う〜んとね、送り先ディレクトリ名の絶対パス化なの */
			 strmfn(sdir2,drv2,dir2,sname,sext); // 結合
			strsfn2(sdir2,drv3,dir3, name, ext); // 分解
			 strmfn(sdir2,drv3,dir3,sname,sext); // 結合
			if (strcmpi(fname,sdir2)==0) {
				/* 再帰的ディレクトリコピーを禁止するため */
				ret=(2);
		  		goto COPY_END;
			}
			strcpy(sdir2,dir2);
			strcpy(fname0,SelectFname(fp,MAXSHORT));
			ChangeName(fname0);
			c=md(drv2,dir2,fname0);
			if (c!=0 && c!=-1) { /* エラー/中断 */
			    if (c==-2) crlf();
			    ret=(114);
		  	    goto COPY_END;
			}
			if (fall==3) count=cfile; // ディレクトリが空かどうかの判定用
		}
		#ifdef DEBUG
		fprintf2(fpstdout,"再帰fname(%d)=%s\n",dan+1,fname);
		#endif
		copy(fname,dan+1);
		if (fall) {
			/* 送り先ディレクトリを戻す */
			strcpy(dir2,sdir2);
			if (fall==3 && cfile==count) {
				// そのディレクトリは空なので消す
				rd(drv2,dir2,fname0);
			}
		}
	} while (NVFILES32(fp)>=0);
    COPY_END:;
	free(work);
	return(ret);
}

/*****************************************************************************/

static	unchar *buff;	// 遅延書き込み用バッファー

void	CTRLC(void)
{
	if (flazy) { // 遅延書き込み終了
		lazyupdate_close();
		free(buff);
	}
	prints("中断します\n");
	exit(200);
}

#ifdef DEBUG
void atexit0()
{
	fclose(fpstdout);
}
#endif

/*****************************************************************************/

void main(int argc,unchar *argv[])
{
int i,fhelp=0;
unchar *src;
size_t bsize;
unlong opt;
	#ifdef DEBUG
	atexit(atexit0);
	fpstdout=fopen("CON","wt"); // 画面表示をファイルオープンする；エラーはない
	setnbf(fpstdout); // 画面表示のバッファリングを無くす
	#endif
	// TwentyOne常駐チェックとファイル名規定長設定
	/* ファイル名規定長に付いて
	元々は、TwentyOne非常駐時には常にショートファイル名で、
	+T 常駐時にはロングファイル名を許し、２１バイト以下ならロングファイル名を、
	それ以上ならショートファイル名を使う予定であった。
	しかし、ロングファイル名１つだけなら良いが、深いディレクトリが出来ると
	そのパス名長がHumanの許す88バイトを越えてしまいシステムがエラーを出す。
	（と言うより暴走する。）
	ディレクトリ名の最大長をあらかじめ知るのは負担が大きすぎるので（全部読む必要がある）、
	動的に長さを変更出来ない。
	従ってディレクトリ名は、8バイト以下ならロングファイル名を、
	それ以上ならショートファイル名を使うようにした。
	（拡張子の３バイトは除いている。）
	ショートファイル名でなら、MS-DOSでのパスの最大長はHumanのそれ以下だったはずなので
	大丈夫である。
	ファイル名は、18バイト以下ならロングファイル名をそれ以上ならショートファイル名を使う。
	もちろんロングファイル名がない時はショートファイル名である。
	ファイル名にスペースを許すかどうかはTwentyOneの+Sオプションによる。
	*/
	flmax=8;
	strcpy(fnchg," -+,;<=>[]|\"\'"); // +S無し時に'_'に変換すべき特殊文字
	opt=TwentyOneOptions();
	if (opt!=0) { // 常駐有り
		if (!(opt&BIT27)) flmax=18; // +T=21文字比較
		if (opt&BIT29) strcpy(fnchg," "); // +S時はスペースのみ判定
	}
	if (!(opt&BIT28)) strcat(fnchg,"."); // -P相当時は'.'も判定（但し拡張子となるものは有効）
	// ' 'はfnchgの先頭に来るようにする
	
	/* オプションチェック初期化 */
	clear_param();
	
	/* 動作モード決定：ファイル名によって動作モードが変わる */
        strsfn2(argv[0],drv2,dir2,name2,ext2);
	/* デフォルトはcmode=0:acopy32 mode */
	if (strcmpi(name2,"TCOPY32")==0) cmode=2; /* time stamp copy */
	
	/* 動作モードを強制的に変えるオプション */
	if (check_param3("MD",argv,argc,&cmode,0)) {
		/* /MD0=acopy /MD1=fmove(不可) /MD2=tcopy /MD3=tmove(不可) */
		if (cmode<0||cmode>3||cmode==1||cmode==3) cmode=0; /* 危ない時はacopyにする */
	}
	mes="コピー";
	
	/* parameter check */
	/* /! = key board buffer clear mode */
	fkbclr=check_param2("!",argv,argc,0);
	
	// TwentyOne +S時にスペース入りファイル/ディレクトリ名を許すかどうか
	// TwentyOne +S時でもスペースがうまく扱えないプログラムが多いので、
	//	オプションによる選択にした
	if (check_param2("SPC",argv,argc,0)) {
		if (opt&BIT29) strcpy(fnchg,fnchg+1); // 先頭の' 'を消す
	}
	
	/* バッファーサイズを表示する */
	frep=check_param2("B",argv,argc,0);
	
	/* 動作をシュミレートするだけで実際の動作はしない */
	ftrace=check_param2("V",argv,argc,0);
	
	/* acopy modeでは/Yの代わりに/Nがある */
	if (cmode==0) { /* acopy mode */
		fask=(check_param2("N",argv,argc,0)==0);
	} else {
		fask=check_param2("Y",argv,argc,0);
	}
	if (ftrace) fask=0; // トレースモードでは確認は一切無し
	
	flazy =check_param2("LU",argv,argc,0); // 遅延書き込み
	if (fask) flazy=0; // 確認モードでは遅延書き込み無し
	
	if (cmode>=2) { /* TCOPY */
		fnew =check_param2("N",argv,argc,0);
		/* /CSがないときはコピーしない */
		fsize=(check_param2("CS",argv,argc,0)==0);
	}
	
	/* ディレクトリ再帰検索 */
	if (check_param3("Z",argv,argc,&fdir,BIT2)) {
		/* /Z1 : 単階層ディレクトリ */
		/* /Z2 : 再帰的階層ディレクトリ */
		if (fdir<=0 || fdir>2) fdir=2; /* /Z = /Z2 */
	}
	
	/* 送り先なしファイルコピー */
	fnone=check_param2("M",argv,argc,0);
	
	/* サイズサーチ */
	i=check_param3("SS",argv,argc,&fs_size_mode,BIT2|BIT3);
	if (i) {
		if (fs_size_mode>3 || fs_size_mode<=0) fs_size_mode=2;
		znstrcpy2(fname2,argv[i],sizeof(fname2));
		if (fname2[0]!=0) {
			if (atoi3(fname2,&fs_size,0)) fs_size_mode=0;
			else if (fs_size<0) fs_size_mode=-1;
		} else fs_size_mode=0;
	}
	
	/* 日付サーチ */
	i=check_param3("DD",argv,argc,&fs_date_mode,BIT2|BIT3);
	if (i) {
		if (fs_date_mode>3 || fs_date_mode<=0) fs_date_mode=2;
		znstrcpy2(fname2,argv[i],sizeof(fname2));
		if (fname2[0]!=0) {
			fs_date=dtcnv(fname2);
			if (fs_date<0) fs_date_mode=0;
		} else fs_date_mode=0;
	}
	
	/* 時刻サーチ */
	i=check_param3("DT",argv,argc,&fs_time_mode,BIT2|BIT3);
	if (i) {
		if (fs_time_mode>3 || fs_time_mode<=0) fs_time_mode=2;
		znstrcpy2(fname2,argv[i],sizeof(fname2));
		if (fname2[0]!=0) {
			fs_time=tmcnv(fname2);
			if (fs_time<0) fs_time_mode=0;
		} else fs_time_mode=0;
	}
	
	/* COPYALL的機能 */
	if (check_param3("ALL",argv,argc,&fall,BIT2)) {
		/* /ALL,/ALL1 = カレントはコピーしない
		   /ALL2 = カレントもコピーする
		   /ALL3 = カレントはコピーしない
			 & ファイルコピーがなかったディレクトリは消す
		*/
		if (fall>3 || fall<=0) fall=1;
		fdir=2; /* 自動的に階層化ディレクトリする */
	}
	
	/* ファイル指定 */
	fhide=check_param2("H",argv,argc,0);
	fsys =check_param2("S",argv,argc,0);
	
	/* file attribute set */
	if (fhide) attr|=FA_HIDE;
	if (fsys ) attr|=FA_SYS;
	
	/* help file name */
	//	      01234567
	strcpy(name2,"ACOPY320");
	name2[7]+=cmode; /* '0'の部分を書き換える */
    HELP:;
	if (helpcom(argc,argv,fhelp,name2,"[Options] 元FAT32フルパス名 [受けFAT16ファイル名]")) {
		exit(fhelp? fhelp:255);
	}
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printsn("オプションエラーです：",argv[i]);
		exit(10);
	}
	
	/* 元パス名取得 */
	i=getfname(argc,argv,1,NULL);
	if (i==0) { /* ファイル名指定がない時：help! */
		fhelp=100;
		goto HELP;
	}
	src=argv[i];
	
	/* 先パス名取得(FAT16) */
	i=getfname(argc,argv,2,NULL);
	if (i!=0) { /* 転送先の指定がある時 */
	    strcpy(fname2,argv[i]);
	    if (fn_make(fname2,fname2,1)) exit(1);
	    strsfn2(fname2,drv2,dir2,name2,ext2);
	    
	    /* 送り先ファイルネーム省略判定 */
	    if (strcmp(name2,"??????????????????")==0) fnomit=1; /* ﾌｧｲﾙ名 */
	    if (strcmp(ext2 ,"???")==0) feomit=1; /* 拡張子 */
	    if ((!fnomit && strpbrk(name2,"*?")!=NULL)
	     || (!feomit && strpbrk(ext2,"*?")!=NULL)) {
	    	printsssn(mes,"先パス名にワイルドカードは使えません:",argv[i]);
	    	exit(2);
	    }
	} else { /* 指定がない時 */
	    strsfn2("*.*",drv2,dir2,name2,ext2); /* drv2,dir2にｶﾚﾝﾄを得る */
	    fnomit=1; /* ファイル名省略 */
	    feomit=1; /* 拡張子省略 */
	}
	
	/* コピーバッファー確保 */
	cbsize=chkml(); /* 確保出来るメモリーの最大サイズを知る */
	if (cbsize<=2048) goto MEM_ERR; /* メモリーが足りない */
	cbsize-=1024; /* 内部関数のmalloc()用に少しとっておく */
	i=cbsize/1024;
	cbsize=i*1024; // cbsizeを1024の倍数にする
	
	vflag=VERIFYG(); /* Verifyフラグ */
	
	if (frep) { /* バッファーサイズ表示：Kbytes単位 */
		printsn("VERIFY O",vflag? "N":"FF");
		prints("[buffer size:");
		print_dec(cbsize/1024); // cbsizeは必ず1024の倍数なのでこれで良い
		prints("Kbytes]\n");
	}
	
	/* バッファーメモリー確保 */
	cbuff=malloc(cbsize);
	if (cbuff==NULL) {
	    MEM_ERR:
		prints("メモリーが確保出来ません\n");
		exit(4);
	}
	
	/* コピー */
	INTVCS(CTRLVC,(char *)CTRLC); // CTRL-Cトラップ
	INTVCS(ERRJVC,(char *)CTRLC); // エラートラップ
	if (flazy) { // 遅延書き込みが使えるか
		bsize=lazyupdate_calc(32); // 通常は３２位で良い
		if (bsize==0) {
			flazy=0; // モードをオフにするだけ
			// prints("Swellfish.sysが組み込まれていません\n");
			// exit(100);
		}
	}
	if (flazy) { // 遅延書き込み準備
		buff=malloc(bsize);
		if (buff==NULL) {
			prints("遅延書き込み用バッファーが確保出来ません\n");
			exit(102);
		}
		if (lazyupdate_open(buff,bsize)) {
			prints("遅延書き込みが使えません\n");
			exit(103);
		}
	}
	if (OpenUni2SJisF(argv[0])) {
		prints("Unicode関数が初期化出来ない\n");
		i=(100);
		goto END;
	}
	{
	unlong scsiid;
	#define CACHEOFFID 0xff
	if (Path2ScsiID(src,&scsiid)==NULL) {
		printsn("SCSI-IDの指定がおかしい:",src);
		i=(101);
		goto END2;
	}
	if (S_CacheOpen(&_S_scb,scsiid,ALLBLOCK,S_CACHE_READ)) {
		// キャッシュ出来ないので通常読み込みにさせる
		_S_scb.id=CACHEOFFID; // 絶対に一致しないid
	}
	i=copy(src,0);
	if (_S_scb.id!=CACHEOFFID) S_CacheClose(&_S_scb);
	}
	
	if (flazy) { // 遅延書き込み終了
		lazyupdate_close();
	}
	if (i<100) {
		/* 結果 */
		if (cfile==0) {
			printsss("ファイルは",mes,"されません");
			if (!ftrace) prints("でした");
		} else {
			print_dec(cfile);
			printsss(" 個のファイルを",mes,ftrace? "します":"しました");
		}
		crlf();
		i=0;
	} else	i-=100;
    END2:;
	CloseUni2SJisF();
    END:;
	if (flazy) free(buff);
	free(cbuff);
	exit(i);
}

/*****************************************************************************/
