/*****************************************************************************/
// file ask delete for FAT32
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>	// exit()
#include <conio.h>
#include <iocslib.h>
#include <string.h>
#include "doslibm.h"
#include "defines.h"
#include "amacro.h"
#include "aparam.h"
#include "astring.h"
#include "astdio.h"
#include "acmp.h"
#include "akey.h"
#include "fat32.h"
#include "s_secreadc.h"

char prog[]="@@> ADEL32.C : 2000/12/05 TUE : COMMAND : ADEL32 : X680x0 : GCC";
// 2000/10/18	FAT32版
//	削除	大文字小文字区別
//		遅延書き込み
// 2000/10/19	ファイル名長定数をfat32.hのそれに合わせて変更
//		ロングファイル名関数差し替えに対応（実行ファイル大幅サイズ縮小）
// 2000/10/20	/Eオプションだけの時に問題があるので修正
//		ファイル名の表示をフルパスからファイル名のみに変更
//		強制ショートファイル名表示モード追加
// 2000/10/23	最後にあるカレントディレクトリの処理がおかしかったので修正
// 2000/10/25	キャッシュ対応（高速化）
//		ルートディレクトリを削除しようとするのを修正
// 2000/12/05	FILE32のサイズが大きくなりスタックをオーバーする可能性が出てきたのでmalloc()
//		による確保に変更した。
/*****************************************************************************/

static	int fnoask,fhide,frd,fsys,fkbclr,attr=FA_ARCH;
static	int cfile=0,cdir=0; /* 削除数 */
static	int fdir=0;	/* V3.0 : ディレクトリ消去 */
static	int cfex;	/* V4.0 : 指定以外ファイル指定開始位置(argc中) */
static	int fver;	// V4.5 : 仮想動作
static	int fshort;	// 強制ショートファイル名表示モード
#define	ALLBLOCK	1024	// キャッシュセクター数

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

void PrFatr(int atr)
// 属性表示
{
	if (atr) {
		if (atr&FA_RONLY) printc('R');
		if (atr&FA_HIDE)  printc('H');
		if (atr&FA_SYS)   printc('S');
		if (atr&FA_DIREC) printc('D');
	}
}

void PrName(unchar *fname,int dan)
// ファイル名／ディレクトリ名表示
{
	/* 再帰的表示の時のために... */
	while (dan-->0) prints("    "); /* 段を付ける */
	prints(fname);
}

unchar *SelectFname(FILE32 *fblock)
// ファイル名
{
	return(!fshort && fblock->lname[0]? fblock->lname:fblock->name);
}

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

int delete1(FILE32 *fblock,int atr0,int dan)
// 1ファイル／ディレクトリ削除
{
unint ky,atr;
	// ファイル／ディレクトリ名表示
	PrName(SelectFname(fblock),dan);
	
	atr=atr0&0b111; // 特殊属性のみ
	if (	((atr & FA_RONLY) && !frd)
	     || ((atr & FA_HIDE ) && !fhide)
	     || ((atr & FA_SYS  ) && !fsys)
	) {
		prints(" ;");
		PrFatr(atr0);
		prints(" 削除不可\n");
		return(-1); /* not delete */
	}
	
	if (fnoask==0||(fnoask==1 && atr)) {
		/* Not askモードでも特殊属性のある時は'Y'/'N'で答える */
		prints("\x1b[s ;");
		PrFatr(atr0);
		prints(" 削除? (Y/N) : ");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky) return(ky);
		prints("\x1b[u\x1b[0K");
	}
	
	// 削除
	if (fver) {
		ky=0;
	} else {
		// 属性変更（必要時のみ）
		if (atr) { /* 特殊属性がある時：属性解除 */
			_Attrib32(fblock,atr0&~(FA_RONLY|FA_HIDE|FA_SYS));
		}
		ky=_Delete32(fblock); /* ファイル/ディレクトリ強要 */
		if (ky!=0) { /* 削除不可 */
			prints("...削除不可");
			if (atr) _Attrib32(fblock,atr0); /* 消せなかった時は属性を戻す */
		}
	}
	crlf();
	return(ky!=0);
}

int del_dir(FILE32 *fblock,unchar *sdir,int atr0,int dan)
/* ディレクトリ削除 */
{
int ret;
	prints("Rmdir ");
	if (_CheckDirEmpty32(sdir)) {
		PrName(SelectFname(fblock),dan);
		prints("...削除不可\n");
		ret=1; // 空でないので消せない
	} else {
		ret=delete1(fblock,atr0,dan);
	}
	switch (ret) {
		/* -1:not delete */
		case  0: /* 消せた時のみカウント */
			cdir++;
		case  1:
        		break;
		case -2: /* BREAK */
			return(1);
	}
	return(0);
}

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

int del(unchar *filename,int argc,unchar *argv[],int dan)
// return : -2=breakされた
{
#if 0
FILE32 fblock;
unchar name[MAXFILE32],ext[MAXEXT32],drv[MAXDRIVE32],dir[MAXDIR32],fname[MAXPATH32],sdir[MAXPATH32];
#else
unchar *work;
FILE32 *fblock;
unchar *name,*ext,*drv,*dir,*fname,*sdir;
#endif
int ret;
	// ワークエリアの動的確保
	// スタック不足を回避するため
	work=malloc(sizeof(FILE32)+MAXFILE32+MAXEXT32+MAXDRIVE32+MAXDIR32+MAXPATH32+MAXPATH32);
	if (work==NULL) {
		prints("ワークエリアが確保出来ません\n");
		exit(55);
	}
	fblock=(FILE32 *)work;
	name=&work[sizeof(FILE32)];
	ext=&name[MAXFILE32];
	drv=&name[MAXEXT32];
	dir=&drv[MAXDRIVE32];
	fname=&dir[MAXDIR32];
	sdir=&fname[MAXPATH32];

	/*（１）ファイルのみ */
	/* ファイル名解体:drv,dir ｦ ﾄｯﾃｵｸ ＆ ファイルネーム補正 */
	ret=vfnsplit32(filename,drv,dir,name,ext,FA_ARCH,fblock,1);
	switch (ret) {
		default:
			//if (fver) printf2("指定ファイルはありません:%s\n",filename);
			goto RDIR;
		case -2:printf2("ドライブ情報が得られない:%s\n",filename);
			goto ADEL_END;
		case -4:printf2("パス指定がおかしい:%s\n",filename);
			goto ADEL_END;
		case 0: break;
	}
	if (fdir==4) goto RDIR2; /* vfnsplit32()を１回は通す必要があるため */
	do {
		if (fblock->atr&(FA_DIREC|FA_VOL)) continue; /* MS-DOSﾃﾞｨｽｸ対応 */
		
		/* ファイルチェック２：指定以外 */
		if (cfex_cp(cfex,argc,argv,fblock->name)) continue;
		
		switch (delete1(fblock,fblock->atr,dan)) {
			/* -1:not delete */
			case  0:cfile++;
				break; /* 削除成功 */
			case  1:
        			ret=(2);
        			goto ADEL_END;
			case -2:crlf();
				ret=(-2); /* BREAK */
        			goto ADEL_END;
		}
	} while (NVFILES32(fblock)>=0);
    RDIR:;
	/* 再帰消去指定ない／１段のみ */
	if (fdir==0 || (fdir==1 && dan==1)) {
		ret=(0);
  		goto ADEL_END;
	}
    RDIR2:;
	/*（２）ディレクトリ */
	strmfp30(sdir,drv,dir,"*.*"); /* ディレクトリ名の制限はない */
	if (VFILES32(fblock,sdir,FA_DIREC)<0) {
		// ルート以外では来ない（下位ディレクトリには必ず./..が有るから）
		//if (fver) printsn("ディレクトリはありません:",sdir);
		ret=(-1);
  		goto ADEL_END;
	}
	do {
		if (CheckParentDir(fblock->name)) continue; // ./..
		
		// ディレクトリ名表示
		strmfp30(sdir,drv,dir,SelectFname(fblock)); /* sdir=drv:dir\fblock->name\ */
		PrName(sdir,dan); crlf();
		
		// ディレクトリ以下のファイル削除
		strmfp20(fname,sdir,name,ext); /* sdir\name.ext */
		if (del(fname,argc,argv,dan+1)==-2) {
			ret=(-2); // BREAK
  			goto ADEL_END;
		}
		
		if (fdir==3||fdir==4) { /* ディレクトリ消去付の時 */
			/* このディレクトリ削除 */
			if (del_dir(fblock,sdir,fblock->atr,dan)) {
				ret=(-2); /* BREAK */
  				goto ADEL_END;
			}
		}
	} while (NVFILES32(fblock)>=0);
	
	if (dan==0) { // カレントディレクトリ削除
		strcpy(sdir,drv);
		strcat(sdir,dir);
		if (dir[0]!=0) {
			printf2("カレントディレクトリ削除\n%s\n",sdir);
			if (VFILES32(fblock,sdir,FA_DIREC)<0) {
				printf2("カレントディレクトリがありません\n");
			}
	    		if (del_dir(fblock,sdir,fblock->atr,0)) {
	    			ret=(-2); /* BREAK */
		  		goto ADEL_END;
	    		}
	    	} // ルートの時は消さない
	}
	ret=0;
    ADEL_END:;
    	free(work);
	return(ret);
}

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

void	CTRLC(void)
{
	prints("ADEL32を中断します\n");
	exit(200);
}

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

void main(int argc,unchar *argv[])
{
int i,ret,fhelp=0;
	/* parameter check */
	/* オプションチェック初期化 */
	clear_param();
    HELP:;
	if (helpcom(argc,argv,fhelp,"ADEL32","[Options] FAT32fname1 [FAT32fname2 ...]")) {
		exit(fhelp? fhelp:255);
	}
	
	fkbclr=check_param2("!",argv,argc,0);
	fnoask=0;
	if (check_param2("N",argv,argc,0))  fnoask=1; // 一部確認有り
	if (check_param2("NN",argv,argc,0)) fnoask=2; // 全確認なし
	fhide =check_param2("H",argv,argc,0);
	frd   =check_param2("R",argv,argc,0);
	fsys  =check_param2("S",argv,argc,0);
	fver  =check_param2("V",argv,argc,0); // 仮想動作
	fshort=check_param2("SHORT",argv,argc,0); // 強制ショートファイル名表示モード
	if (fver) fnoask=2; // 仮想動作の時は確認無し
	
	/* V3.0 : ディレクトリ消去 */
	if (check_param3("Z",argv,argc,&fdir,BIT2)) {
		/* /Z1 : 単階層ディレクトリ内ファイル消去 */
		/* /Z2 : 再帰的階層ディレクトリ内ファイル消去 */
		/* /Z3 : 再帰的階層ディレクトリ消去付き */
		/* /Z4 : 空ディレクトリのみ消去機能 */
		if (fdir<=0 || fdir>4) fdir=3; /* /Z = /Z3 */
	}
	
	/* file attribute set */
	if (fhide) attr|=FA_HIDE;
	if (frd)   attr|=FA_RONLY;
	if (fsys)  attr|=FA_SYS;
    	
	/* V4.0 : 指定以外指定 */
	cfex=check_param2("E",argv,argc,0);
	if (cfex==0) cfex=argc; /* 指定以外指定無しの時 */
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printsn("オプションエラーです：",argv[i]);
		exit(3);
	}
	
	/* "/"または"-"のついていないパラメーターがpnameになる */
	i=getfname(argc,argv,1,NULL);
	if (i==0) { /* help! */
		fhelp=100;
		goto HELP;
	}
	
	if (i>cfex) { /* 以外指定のみの時 */
		prints("/Eだけの指定は出来ません\n");
		exit(3);
	}
	
	/* 実行! */
	if (OpenUni2SJisF(argv[0])) {
		prints("Unicode関数が初期化出来ない\n");
		exit(100);
	}
	INTVCS(CTRLVC,(char *)CTRLC); // CTRL-Cトラップ
	INTVCS(ERRJVC,(char *)CTRLC); // エラートラップ
	for (;i<cfex;i++) {
	unlong scsiid;
	#define CACHEOFFID 0xff
		ret=argv[i][0];
		if (ret=='/'||ret=='-') continue; /* parameter skip */
		if (Path2ScsiID(argv[i],&scsiid)==NULL) {
			printsn("SCSI-IDの指定がおかしい:",argv[i]);
			break;
		}
		if (S_CacheOpen(&_S_scb,scsiid,ALLBLOCK,S_CACHE_READ)) {
			// キャッシュ出来ないので通常読み込みにさせる
			_S_scb.id=CACHEOFFID; // 絶対に一致しないid
		}
		ret=del(argv[i],argc,argv,0);
		if (_S_scb.id!=CACHEOFFID) S_CacheClose(&_S_scb);
		if (ret>0||ret==-2) break;
	}
	CloseUni2SJisF();
	if (ret==-2) ret=0; // breakされた時
	if (ret>0) exit(ret);
	
	if (cfile==0 && cdir==0) {
		printss(fdir==4? "ディレクトリ":"ファイル","は削除されません");
		if (!fver) prints("でした");
		crlf();
	}
	if (cdir) {
		print_dec(cdir);
		printsn(" 個のディレクトリを削除しま",(fver? "す":"した"));
	}
	if (cfile) {
		print_dec(cfile);
		printsn(" 個のファイルを削除しま",(fver? "す":"した"));
	}
	
	exit(0);
}

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