/*****************************************************************************/
// attrib 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[]="@@> ATTRIB32.C : 2000/12/05 TUE : COMMAND : ATTRIB32 : 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 fsys,fhide,fronly;
static	int fnoask,fkbclr;
static	int cfile=0,cdir=0; /* 処理数 */
static	int fdir=0;	/* ディレクトリ処理 */
static	int cfex;	/* 指定以外ファイル指定開始位置(argc中) */
static	int fcol,fver;	// 色制御,仮想動作
static	int fshort;	// 強制ショートファイル名表示モード
#define	ALLBLOCK	1024	// キャッシュセクター数

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

void PrName(unchar *fname,int dan,int atr,int mode)
// ファイル名／ディレクトリ名表示
// mode: 0=ファイル , <>0=ディレクトリ
{
	/* 再帰的表示の時のために... */
	while (dan-->0) printf2("    "); /* 段を付ける */
	
	if (mode) {
		if (fcol) B_COLOR(TCYAN|REVERSE); /* 水色＋リバース */
	}
	print_fatr(atr);
	printf2(" %s",fname);
	if (fcol) {
		B_COLOR(TWHITE); /* 白 */
	}
}

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

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

int attrib1(FILE32 *fblock,int dan,int mode)
// 1ファイル／ディレクトリ削除
// mode=0:ファイル , <>0:ディレクトリ
{
int ky;
int atr;
	// ファイル／ディレクトリ名表示
	atr=fblock->atr;
	PrName(SelectFname(fblock),dan,atr,mode);
	
	if (!fnoask) {
		printf2("\x1b[s"" 変更? (Y/N) : ");
		ky=kywait(fkbclr); /* 'Y'/'N' */
		if (ky) return(ky);
		printf2("\x1b[u\x1b[0K");
	}
	
	if (fver) {
		ky=0;
	} else {
		if (fronly) {
			if (fronly==1) atr|=FA_RONLY;
			else atr&=(~FA_RONLY);
		}
		if (fhide) {
			if (fhide==1) atr|=FA_HIDE;
			else atr&=(~FA_HIDE);
		}
		if (fsys) {
			if (fsys==1) atr|=FA_SYS;
			else atr&=(~FA_SYS);
		}
		ky=_Attrib32(fblock,atr);
	}
	if (ky<0) printf2("...変更不可(%d)",ky);
	crlf();
	return(ky<0);
}

int attrib_dir(FILE32 *fblock,int dan)
/* このディレクトリ変更 */
{
	switch (attrib1(fblock,dan,1)) {
		/* -1:not change */
		case  0: /* 変更できた時のみカウント */
			cdir++;
		case  1:
        		break;
		case -2: /* BREAK */
			return(1);
	}
	return(0);
}

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

int attrib(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);
//	printf2("drv=%s,dir=%s,name=%s,ext=%s\n",drv,dir,name,ext);
	switch (ret) {
		default:
			//if (fver) printf2("指定ファイルはありません:%s\n",filename);
			goto RDIR;
		case -2:printf2("ドライブ情報が得られない:%s\n",filename);
			goto ATR_END;
		case -4:printf2("パス指定がおかしい:%s\n",filename);
			goto ATR_END;
		case 0: break;
	}
	do {
		if (fblock->atr&(FA_DIREC|FA_VOL)) continue; /* MS-DOSﾃﾞｨｽｸ対応 */
		
		/* ファイルチェック２：指定以外 */
		if (cfex_cp(cfex,argc,argv,fblock->name)) continue;
		
		switch (attrib1(fblock,dan,0)) {
			/* -1:not change */
			case  0:cfile++;
				break; /* 変更成功 */
			case  1:
        			ret=(2);
        			goto ATR_END;
			case -2:crlf();
				ret=(-2); /* BREAK */
        			goto ATR_END;
		}
	} while (NVFILES32(fblock)>=0);
    RDIR:;
	/* 再帰指定ない／１段のみ */
	if (fdir==0 || (fdir==1 && dan==1)) {
		ret=(0);
        	goto ATR_END;
        }
	
	/*（２）ディレクトリ */
	strmfp30(sdir,drv,dir,"*.*"); // ディレクトリ名は*.*で探す
	if (VFILES32(fblock,sdir,FA_DIREC)<0) {
		// ルート以外では来ない（下位ディレクトリには必ず./..が有るから）
		//if (fver) printf2("ディレクトリはありません:%s\n",sdir);
		ret=(-1);
  		goto ATR_END;
	}
	do {
		if (CheckParentDir(fblock->name)) continue; // ./..
		
		// ディレクトリ名表示
		strmfp30(sdir,drv,dir,SelectFname(fblock)); /* sdir=drv:dir\fblock->name\ */
		PrName(sdir,dan,fblock->atr,1); crlf();
		
		// ディレクトリ以下のファイル変更
		strmfp20(fname,sdir,name,ext); /* sdir\name.ext */
		if (attrib(fname,argc,argv,dan+1)==-2) {
			ret=(-2); // BREAK
  			goto ATR_END;
		}
		
		if (fdir==3) { /* ディレクトリ変更付の時 */
			/* このディレクトリ変更 */
			if (attrib_dir(fblock,dan)) {
				ret=(-2); /* BREAK */
  				goto ATR_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 (attrib_dir(fblock,0)) {
		    		ret=(-2); /* BREAK */
		  		goto ATR_END;
		    	}
	    	} // ルートの時は消さない
	}
	ret=0;
    ATR_END:;
    	free(work);
	return(ret);
}

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

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

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

void main(int argc,unchar *argv[])
{
int i,ret,fhelp=0;
	/* parameter check */
	/* オプションチェック初期化 */
	clear_param();
    HELP:;
	if (helpcom(argc,argv,fhelp
		,"ATTRIB32"
		,"[/R+ /R- /H+ /H- /S+ /S-] FAT32fname1 [FAT32fname2 ...]"
	)) {
		exit(fhelp? fhelp:255);
	}
	
	fsys=fronly=fhide=0;
	if (check_param2("R+",argv,argc,0)) fronly=+1;
	if (check_param2("R-",argv,argc,0)) fronly=-1;
	if (check_param2("H+",argv,argc,0)) fhide =+1;
	if (check_param2("H-",argv,argc,0)) fhide =-1;
	if (check_param2("S+",argv,argc,0)) fsys  =+1;
	if (check_param2("S-",argv,argc,0)) fsys  =-1;
	
	fshort=check_param2("SHORT",argv,argc,0); // 強制ショートファイル名表示モード
	fkbclr=check_param2("!",argv,argc,0);
	fnoask=check_param2("N",argv,argc,0); // 確認なし
	fcol  =check_param2("C",argv,argc,0); // 色付き表示する
	
	fver=0;
	if (check_param2("V",argv,argc,0)) fver=1; // 仮想動作
	if (fsys==0 && fhide==0 && fronly==0) fver=2; // 属性変更指定無しの時は仮想動作扱い
	if (fver) fnoask=1; // 仮想動作の時は確認無し
	
	/* ディレクトリ処理 */
	if (check_param3("Z",argv,argc,&fdir,BIT2)) {
		/* /Z1 : 単階層ディレクトリ内ファイル変更 */
		/* /Z2 : 再帰的階層ディレクトリ内ファイル変更 */
		/* /Z3 : 再帰的階層ディレクトリ変更付き */
		if (fdir<=0 || fdir>3) fdir=2; /* /Z = /Z2 */
	}
	
	/* 指定以外指定 */
	cfex=check_param2("E",argv,argc,0);
	if (cfex==0) cfex=argc; /* 指定以外指定無しの時 */
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printf2("オプションエラーです：%s\n",argv[i]);
		exit(3);
	}
	
	/* "/"または"-"のついていないパラメーターがpnameになる */
	i=getfname(argc,argv,1,NULL);
	if (i==0) { /* help! */
		fhelp=100;
		goto HELP;
	}
	
	if (i>cfex) { /* 以外指定のみの時 */
		printf2("/Eだけの指定は出来ません\n");
		exit(3);
	}
	
	/* 実行! */
	if (OpenUni2SJisF(argv[0])) {
		printf2("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=attrib(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 (fver!=2) {
		if (cfile==0 && cdir==0) {
			printf2("ファイルは変更されません");
			if (!fver) printf2("でした");
			crlf();
		}
		if (cdir) {
			printf2("%d 個のディレクトリを変更しま%s\n",cdir,(fver? "す":"した"));
		}
		if (cfile) {
			printf2("%d 個のファイルを変更しま%s\n",cfile,(fver? "す":"した"));
		}
	}
	
	exit(0);
}

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