/** FILES32 ******************************************************************/
/*	"〜"を取り込むため__main2.oをリンクすること
	gcd files32 -om2						     */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include "doslibm.h"
#include <string.h>
#include <conio.h>
#include <error.h>
#include "defines.h"
#include "aparam.h"
#include "astdio.h"
#include "acmp.h"
#include "amacro.h"
#include "astring.h"
#include "akey.h"
#include "acdata.h"
#include "fat32.h"
#include "s_secreadc.h"

char prog[]="@@> FILES32.C : 2000/12/05 TUE : COMMAND : FILES32 : X680x0 : GCC";
/*
2000/09/13 FAT32対応版
	   削除	/8,/8.	８文字ファイル名チェック
		/OL,/OU	大文字小文字ファイル名チェック
		/X,/DX	プログラム起動
		FDD/RAMDISK物理ドライブ名指定
		カレントドライブはないので絶対にパス指定をさせる
	   追加	アクセス日付表示
2000/09/14 関数名変更に対応
2000/09/19 作成日時表示/表示日時をモードで選択可にする
2000/09/20 /?時のメッセージが間違っていたので修正
	   ロングファイル名対応（表示）
2000/10/03 ロングファイル名対応（指定）
2000/10/19 ファイル名長定数をfat32.hのそれに合わせて変更
	   ロングファイル名関数差し替えに対応（実行ファイル大幅サイズ縮小）
	   files.x用処理が残っていたので削除。
2000/10/25 キャッシュ対応（高速化）
2000/12/05 FILE32のサイズが大きくなりスタックをオーバーする可能性が出てきたのでmalloc()
	   による確保に変更した。
2002/06/07 /OD3が使えなかったので修正
*/
/*****************************************************************************/
/* 変数宣言：訳あってほとんどグローバルにしている */

static	int atr=(FA_ARCH|FA_RONLY) /* 標準ではDIRとほぼ同じにする(volumeはなし) */
	,fdir=1,frd=1,fhide=0,fsys=0,fvol=0
	,fsize=0,fdate,fatr=1,lsize=0,ffull
	,fcount=0,dcount=0,vcount=0
	,flong
	,fchar,fkbclr;
static	int	fs_date,fs_date_mode,fs_time,fs_time_mode,fs_size,fs_size_mode;
static	int	flsize,allsize=0;
static	int	cfex;	/* 指定以外ファイル指定開始位置(argc中) */
#define	ALLBLOCK	1024	// キャッシュセクター数

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

void print_num(int count,unchar *mes)
/* 数表示 */
{
	prints("-------- ");
	if (count==0) prints("No");
	else print_dec(count);
	prints(mes);
}

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

void print_line(unchar *fname,int size)
/* ファイル先頭簡易表示 */
/* このルーチンは基本的にテキスト専用なの */
{
int i,c,cc;
static FILE32 fp;
	if (!vfopen32(fname,"rt",&fp)) {
		for(i=0;i<size;i++) {
			if ((c=fgetc32(&fp))==-1) break;
			if (c=='\n') { /* 改行 */
				C_COLOR(TYELLOW); /* 黄色 */
				printc2(0x801f);
				C_COLOR(TWHITE); /* 白 */
				continue;
			}
			if (c==TAB) { /* TAB */
				C_COLOR(TYELLOW);
				printc2(0x801c);
				C_COLOR(TWHITE);
				continue;
			}
			if (check_kanji1(c)) {
				if ((cc=fgetc32(&fp))==-1) break;
				printc(c);
				c=cc;
				i++;
			}
			if (c<' ') c='.';
			printc(c);
		}
		fclose32(&fp);
	} else { /* ファイルがオープン出来ない */
		C_COLOR(TYELLOW);
		prints("Can't open");
		C_COLOR(TWHITE);
	}
}

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

int nsd_check(FILE32 *fp)
{
int c;
	c=fp->atr;
	if (!frd   && (c & FA_RONLY)) return(1); /* read-only file */
	if (!fhide && (c & FA_HIDE))  return(1); /* hidden file */
	if (!fsys  && (c & FA_SYS))   return(1); /* system file */
	if (!fvol  && (c & FA_VOL))   return(1); /* volume name */
	
	if (!(c&FA_DIREC)) {
		/* サイズ判定 */
		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) {
		c=cmp_date(fp->date,fs_date);
		switch (fs_date_mode) {
			case 1:/* 以前 */
				if (c==2) return(1);
				break;
			case 2:/* 以降 */
				if (c==1) return(1);
				break;
			case 3:/* のみ */
				if (c!=0) return(1);
				break;
		}
	}
	
	/* 時間判定 */
	if (fs_time_mode) {
		c=cmp_time(fp->time,fs_time);
		switch (fs_time_mode) {
			case 1:/* 以前 */
				if (c==2) return(1);
				break;
			case 2:/* 以降 */
				if (c==1) return(1);
				break;
			case 3:/* のみ */
				if (c!=0) return(1);
				break;
		}
	}
	return(0);
}

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

static void PrintFileDateTime(FILE32 *fp)
// 日時表示
{
	if (fdate) { /* ファイル日付表示 */
		tab();
		print_fdate_time(fp->date,fp->time);	// 更新日時
		if (fdate>=2) {
			prints(" ");
			print_fdate(fp->adate);	// アクセス日付
			if (fdate>=3) {
				prints(" ");
				if (fp->m10ms>=0x64) fp->mtime++;
				print_fdate_time(fp->mdate,fp->mtime);	// 作成日時
			}
		}
	}
}

static void PrintAtrbFname(int dan,int atr,unchar *fname,FILE32 *fp)
/* アトリビュート＆ショートファイル/ディレクトリ名表示 */
{
	/* 再帰的表示の時のために... */
	while (dan-->0) prints("    "); /* 段を付ける */
	
	if (fatr) print_fatr(atr);
	tab();
	if (ffull) {
		prints(fname);
	} else {
		pr_spcleft(fp->name,MAXSHORTFILEEXT32);
	}
}

static void PrintLongname(FILE32 *fp)
// ロングファイル名表示
{
	if (flong) {
		printss("\t",fp->lname);
	}
}

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

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

//	printf("Start :%d/%s\n",dan,path);
	/*（１）ファイルのみ */
	/* 最初のファイルサーチ */
	/* ファイル名解体:drv,dir ｦ ﾄｯﾃｵｸ */
	/* ファイルネーム補正 */
	if (vfnsplit32(path,drv,dir,name,ext,atr,fp,1)) goto DIR_DIR;
//	strsfn32(path,drv,dir,name,ext);
//	printf("drv=%s,dir=%sname=%s,ext=%s\n",drv,dir,name,ext);
//	if (VFILES32(fp,path,atr)<0) goto DIR_DIR; // ファイルが１つもない時
	
	do {
		/* ファイルチェック１ */
		if (fp->atr&FA_DIREC) continue; /* MS-DOSﾃﾞｨｽｸ対応 */
		if (nsd_check(fp)) continue;
		
		/* ファイルチェック２：指定以外 */
		if (cfex_cp(cfex,argc,argv,fp->name)) goto NF;
		
		/* ﾌﾙﾊﾟｽ名作成：VFILES32はﾌｧｲﾙ名と拡張子しか返さないから */
		strmfp30(fname,drv,dir,fp->name);
		
		allsize+=fp->filelen;
		
		/* アトリビュート＆ファイル名表示 */
		c=fp->atr;
		PrintAtrbFname(dan,c,fname,fp);
		
		/* ファイル長さ表示（ファイルのみ）*/
		if (fsize) {
			if ((c&FA_ARCH)||fp->filelen>0) {
				printf2("\t%11d",fp->filelen);
			} else {
				printf2("\t-----------");
			}
		}
		
		/* ファイル日付表示 */
		PrintFileDateTime(fp);
		
		// ロングファイル名表示
		PrintLongname(fp);
		
		/* ファイル先頭表示（ファイルのみ）*/
		if (lsize && (c&FA_ARCH)) {
			tab();
			print_line(fname,lsize);
		}
		crlf();
		
		if (fkbclr) kbclr();
		if (fchar) kslow();
		
		/* カウント */
		if (c & FA_VOL) vcount++;
		else fcount++;
	    NF:;
	} while (NVFILES32(fp)>=0);
//	} while (c=NVFILES32(fp),printf("ret=%d/error=%d\n",c,fp->error),c>=0);
	/* サブディレクトリ表示指定がない時 */
    DIR_DIR:
	if (fdir==0) goto FILES_END;
	
	/*（２）ディレクトリ */
	strmfp30(sdir,drv,dir,"*.*"); /* ディレクトリ名の制限はない */
//	printf("ディレクトリサーチ:%s\n",sdir);
	if (VFILES32(fp,sdir,FA_DIREC)<0) {
//		printf("NO DIRECTORY\n");
		goto FILES_END;
	}
	do {
		if (CheckParentDir(fp->name)) continue; /* ./.. cut */
		
		strmfp30(sdir,drv,dir,fp->name); /* ディレクトリ名 */
		
		/* アトリビュート＆ディレクトリ名表示 */
		PrintAtrbFname(dan,fp->atr,sdir,fp);
		
		if (!nsd_check(fp)) {
			/* ファイル日付表示 */
			PrintFileDateTime(fp);
			/* カウント */
			dcount++;
		}
		
		// ロングファイル名表示
		PrintLongname(fp);
		crlf();
		
		if (fkbclr) kbclr();
		if (fchar) kslow();
		
		if (fdir==2) { /* サブディレクトリ表示 */
//			printf("Start of Sub-Dir:%d/%s\n",dan,fp->nextfname);
			strmfp20(fname,sdir,name,ext); /* フルパス名 */
			files_main(fname,argc,argv,dan+1);
//			printf("End of Sub-Dir:%d/%s\n",dan,fp->nextfname);
		}
	} while (NVFILES32(fp)>=0);
//	printf("End :%d/%s\n",dan,path);
    FILES_END:;
	free(work);
}

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

void main(int argc,unchar *argv[])
{
unchar line[MAXPATH32];
int i,c,hflag=0;
	/* check parameter */
	/* オプションチェック初期化 */
	clear_param();
    HELP:
	if (helpcom(argc,argv,hflag,"FILES32","[Options] FAT32フルパス名")) exit(hflag? hflag:255);
	
	/* /! = key board buffer clear mode */
	fkbclr=check_param2("!",argv,argc,0);
	ffull =check_param2("F",argv,argc,0);
	fsize =check_param2("OS",argv,argc,0);
	flsize=check_param2("LS",argv,argc,0);
	
	if (check_param2("OA",argv,argc,0)) fatr=0;
	
	fdate=1;
	if (check_param3("OD",argv,argc,&fdate,0)) {
		if (fdate<=0) fdate=1;
		if (fdate> 3) fdate=3;
	} else fdate=0;
	
	/* file display mode flag */
	if (check_param3("OT",argv,argc,&lsize,BIT2)) {
		if (lsize<=0) lsize=15; /* 先頭１５バイト表示が標準 */
		/* 何と表示サイズに上限がない！ */
		/* でも途中で勝手に中断されるけどね */
	}
	
	/* サイズサーチ：/Sより先にチェックする */
	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(line,argv[i],sizeof(line));
		if (line[0]!=0) {
			if (atoi3(line,&fs_size,0)) {
				fs_size_mode=0;
			} else {
				if (fs_size<0) fs_size_mode=-1;
			}
		} else fs_size_mode=0;
	}
	
	/* 日付サーチ：/Dより先にチェックする */
	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(line,argv[i],sizeof(line));
		if (line[0]!=0) {
			fs_date=dtcnv(line);
			if (fs_date<0) fs_date_mode=0;
		} else fs_date_mode=0;
	}
	
	/* 時刻サーチ：/Dより先にチェックする */
	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(line,argv[i],sizeof(line));
		if (line[0]!=0) {
			fs_time=tmcnv(line);
			if (fs_time<0) fs_time_mode=0;
		} else fs_time_mode=0;
	}
	
	/* ファイルアトリビュート系 */
	if (check_param2("N",argv,argc,0)) {atr=0; fdir=0;}
	if (check_param2("A",argv,argc,0))  atr|=FA_ARCH;
	if (check_param2("R",argv,argc,0)) {atr|=FA_RONLY; frd=1;}
	if (check_param2("H",argv,argc,0)) {atr|=FA_HIDE;  fhide=1;}
	if (check_param2("S",argv,argc,0)) {atr|=FA_SYS;   fsys=1;}
	if (check_param2("V",argv,argc,0)) {atr|=FA_VOL;   fvol=1;}
	
	/* ロングファイル名表示 */
	flong=check_param2("LN",argv,argc,0);
	
	/* 指定以外指定 */
	cfex=check_param2("E",argv,argc,0);
	if (cfex==0) cfex=argc; /* 指定以外指定無しの時 */
	
	if (check_param2("D",argv,argc,0)) fdir=1; /* ﾃﾞｨﾚｸﾄﾘは別処理なのでatrに入れない */
	if (check_param2("Z",argv,argc,0)) fdir=2; /* 下位ディレクトリも再帰的に表示する */
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printsn("\aオプションエラーです：",argv[i]);
		exit(3);
	}
	
	/* help! */
	if (atr==0 && fdir==0) {
		hflag=(atr==0? 100:101);
		goto HELP;
	}
	
	/* 出力先がキャラクターデバイスかどうか */
 	fchar=check_char_device(stdout);
	
	/* pathname */
	/* "/"または"-"のついていない最初のパラメーターがpathnameになる */
	i=getfname(argc,argv,1,NULL);
	if (i==0 || i>cfex) { /* 指定なし叉は以外指定のみの時 */
		prints("\aパス指定が必須です\n");
		exit(3);
	}
	
	/* 実行! */
	if (OpenUni2SJisF(argv[0])) {
		prints("Unicode関数が初期化出来ない\n");
		exit(100);
	}
	
	for (;i<cfex;i++) {
	unlong scsiid;
	#define CACHEOFFID 0xff
		c=argv[i][0];
		if (c=='/'||c=='-') 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
		}
		files_main(argv[i],argc,argv,0);
		if (_S_scb.id!=CACHEOFFID) S_CacheClose(&_S_scb);
	}
	CloseUni2SJisF();
	
	/* カウンタ表示 */
	print_num(fcount," File");
	if (fcount>=2) printc('s');
	crlf();
	
	if (fdir) {
		print_num(dcount," Director");
		prints(dcount>=2? "ies":"y");
		crlf();
	}
	if (fvol) print_num(vcount," Volume name\n");
	if (flsize) {
		prints_dec("Total file size:",allsize,"byte");
		if (allsize>1) printc('s');
		crlf();
	}
	exit(0);
}

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