/** FIle Search **************************************************************/
/*	"〜"を取り込むため__main2.oをリンクすること
	gc fs32 -om2							     */
/*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "doslibm.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[]="@@> FS32.C : 2000/12/05 TUE : COMMAND : FS32 : X680x0 : GCC";
/*
2000/09/13 FAT32対応版
	   削除		プログラム実行
			全ドライブサーチ
			大文字小文字区別
			物理ドライブ対応
2000/09/14 関数名変更に対応
2000/09/19 作成日時表示/表示日時をモードで選択可にする
2000/09/20 /Qがうまく動作しなかったのを修正
	   /?時のメッセージが間違っていたので修正
	   ロングファイル名対応（表示）
2000/10/03 ロングファイル名対応（指定）
2000/10/19 ファイル名長定数をfat32.hのそれに合わせて変更
	   ロングファイル名関数差し替えに対応（実行ファイル大幅サイズ縮小）
2000/10/23 検索ディレクトリ名がおかしくなるのを修正
2000/10/25 キャッシュ対応（高速化）
2000/12/05 FILE32のサイズが大きくなりスタックをオーバーする可能性が出てきたのでmalloc()
	   による確保に変更した。
*/
/*****************************************************************************/

static	int	ffull=0,fpr;
static	int	fsize,fnone,fdate,fattr,fdir=0,fsdir=0,fkbclr,fchar;
static	int	fs_date,fs_date_mode,fs_time,fs_time_mode,fs_size,fs_size_mode;
static	int	flsize,allsize=0,quit=-1,flong;
#define	ALLBLOCK	1024	// キャッシュセクター数

/* fsize <> 0 のときファイルサイズも表示する */
/* fnone <> 0 のときファイルのないディレクトリは表示しない */
/* fdate <> 0 のときファイルの各種日時を表示する */
/* fattr <> 0 のときファイルのアトリビュートを表示する */
/* fdir  <> 0 のとき下位ディレクトリへの移動を禁止する */
/* fsdir =  1 のとき下位ディレクトリ名も検索対象にする */
/*       =  2 のとき下位ディレクトリ名だけを検索対象にする */
// fpr   <> 0 検索中ディレクトリ表示

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

void print_num(int count,unchar *mes)
{
	print_dec(count);
	prints("個の");
	printsn(mes,"を見付けました");
}

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

int nsd_check(FILE32 *fp)
{
int c;
	if (!(fp->atr&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);
}

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

void fsearch(unchar *dir,unchar *fname,int fcount,int *allcount,int *dallcount)
/* dirで示されるディレクトリー内にあるfnameファイルを表示する */
/* fcount<> 0 のときファイルの発見数を表示する */
{
FILE32 *fp;
int fc=0,c,mode,count=0,dcount=0;
#if 0
unchar direc[MAXDIR32],path[MAXPATH32];
#else
unchar *work;
unchar *direc,*path;
#endif
	// ワークエリアの動的確保
	// スタック不足を回避するため
	work=malloc(sizeof(FILE32)+MAXDIR32+MAXPATH32);
	if (work==NULL) {
		prints("ワークエリアが確保出来ません\n");
		exit(55);
	}
	fp=(FILE32 *)work;
	direc=&work[sizeof(FILE32)];
	path=&direc[MAXDIR32];

	// すでに指定回数を越えている時は即時終了させる
	if (quit>=0) {
		if (*allcount>=quit) goto FS_END;
	}
	
	if (fpr) printsn(">>",dir);
	if (fnone==0) printss(dir,"\n");
	
	/* file search in this directory */
	strmfp30(path,"",dir,fname);
	
	mode=FA_ARCH|FA_RONLY|FA_HIDE|FA_SYS;
	if (fsdir==1) mode|=FA_DIREC; /* 下位ディレクトリ名も検索対象にする時 */
	if (fsdir==2) mode=FA_DIREC;  /* 下位ディレクトリ名だけを検索対象にする時 */
	
	if (VFILES32(fp,path,mode)<0) goto SEARCH_END;
	do {
		if (!fsdir&&(fp->atr&FA_DIREC)) continue; /* MS-DOSﾃﾞｨｽｸ対応 */
		if (nsd_check(fp)) continue;
		
		fc++; /* ファイル数 count */
		
		/* そのディレクトリの最初の時はディレクトリ名を表示する */
		c=fp->atr &FA_DIREC;
		if (fnone && fc==1) {printss("\n",dir); prints("\\\n");}
		allsize+=fp->filelen;
		if (fsdir==2 && !c) continue; /* ディレクトリ名のみの時 */
		if (c) { /* ディレクトリ名の時 */
			if (CheckParentDir(fp->name)) continue; /* . / .. */
			prints("-DIR-");
			dcount++;
		} else count++;
		
		/* ショートファイル・ディレクトリ名表示 */
		tab();
		if (ffull) {
			strmfp30(path,"",dir,fp->name);
			prints(path);
		} else	pr_spcleft(fp->name,MAXSHORTFILEEXT32);
		
		if (fsize) { /* ファイル長さ表示 */
			printf2("\t%12d",fp->filelen);
		}
		
		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);	// 作成日時
				}
			}
		}
		
		if (flong) { // ロングファイル名表示
			printss("\t",fp->lname);
		}
		
		if (fattr) { /* ファイル属性表示 */
			tab();
			print_fatr(fp->atr);
		}
		
		crlf();
		if (fkbclr) kbclr();
		if (fchar) kslow();
		if (quit>=0) {
			if (count>=quit) break;
		}
	} while (NVFILES32(fp)>=0);
SEARCH_END:
	if (fcount==1 || fcount==3) {
		if (count>0) {
			prints("-------- "); print_dec(count); prints(" file");
			if (count>1) printc('s');
			crlf();
		}
		if (dcount>0) {
			prints("-------- "); print_dec(dcount); prints(" dir.");
			if (dcount>1) printc('s');
			crlf();
		}
	}
	(*dallcount)+=dcount;
	(*allcount) +=count;
	if (quit>=0) {
		if (*allcount>=quit) goto FS_END;
	}
	if (fdir) goto FS_END; /* 下位ディレクトリには移動しないとき */
	
	/* directory search */
	strmfp30(path,"",dir,"*.*");
	c=VFILES32(fp,path,FA_DIREC);
	while (c>=0) {
		if (!CheckParentDir(fp->name)) {
			if ((fp->atr & FA_DIREC)!=0) {
				strmfp30(direc,"",dir,fp->name);
				fsearch(direc,fname,fcount,allcount,dallcount);
			}
		}
		c=NVFILES32(fp);
	}
    FS_END:;
    	free(work);
}

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

void main(int argc,unchar *argv[])
{
int i,j,fhelp=0,fcount;
int allcount=0,dcount=0;
unchar fname[MAXPATH32],name[MAXFILE32],ext[MAXEXT32]
						,drv[MAXDRIVE32],dir[MAXDIR32];
	/* parameter check */
	/* オプションチェック初期化 */
	clear_param();
    HELP:
	if (helpcom(argc,argv,fhelp,"FS32","ファイル名 FAT32パス名 [Options]")) exit(fhelp? fhelp:255);
	
	if (check_param3("Z",argv,argc,&fsdir,BIT2)) {
		if (fsdir<=0 || fsdir>2) fsdir=2; /* /Z = /Z2 */
	}
	
	// 合計発見個数表示
	fcount=2;
	if (check_param3("C",argv,argc,&fcount,0)) {
		if (fcount<=0 || fcount>3) fcount=2;
	}
	
	// 何個見つけたら終了するか
	if (check_param3("Q",argv,argc,&quit,0)) {
		if (quit<=0) quit=1;
	}
	
	/* サイズサーチ */
	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(fname,argv[i],sizeof(fname));
		if (fname[0]!=0) {
			if (atoi3(fname,&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(fname,argv[i],sizeof(fname));
		if (fname[0]!=0) {
			fs_date=dtcnv(fname);
			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(fname,argv[i],sizeof(fname));
		if (fname[0]!=0) {
			fs_time=tmcnv(fname);
			if (fs_time<0) fs_time_mode=0;
		} else fs_time_mode=0;
	}
	
	/* /! = key board buffer clear mode */
	fkbclr=check_param2("!",argv,argc,0);
	fattr=check_param2("A",argv,argc,0);
	fdir =check_param2("D",argv,argc,0);
	fsize=check_param2("S",argv,argc,0);
	fnone=(!check_param2("N",argv,argc,0));
	ffull=check_param2("F",argv,argc,0);	/* フルパス名表示 */
	fpr  =check_param2("P",argv,argc,0);	// 検索中ディレクトリ表示
	flsize=check_param2("LS",argv,argc,0);
	
	/* ロングファイル名表示 */
	flong=check_param2("LN",argv,argc,0);
	
	fdate=1;
	if (check_param3("T",argv,argc,&fdate,0)) {
		if (fdate<=0) fdate=1;
		if (fdate>=3) fdate=2;
	} else fdate=0;
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printsn("オプションエラーです：",argv[i]);
		exit(3);
	}
	
	/* "/"または"-"のついていない最初のパラメーターが検索ファイル名になる */
	i=getfname(argc,argv,1,NULL);
	if (i==0) { /* help! */
		fhelp=100;
		goto HELP;
	}
	
	/* ファイル名 */
	strsfn32(argv[i],drv,dir,name,ext); /* ファイル名分解 */
	if (name[0]==0) {
		printsn("ファイルネームが異常です:",argv[j]);
		exit(1);
	}
	
	/* ファイル名合成 */
	strcpy(fname,name);
	if (ext[0]!='.') strcat(fname,".");
	strcat(fname,ext); /* ドライブ、ディレクトリ指定は消す */
	printf("検索ファイル名:%s\n",fname);
	
	/* ディレクトリ名 */
	/* "/"または"-"のついていない２つ目のパラメーターがディレクトリ名になる */
	/* 省略されている時はエラー */
	j=getfname(argc,argv,2,NULL);
	if (j==0) { /* help! */
		fhelp=101;
		goto HELP;
	}
	if (check_wild(argv[j])) {
		printsn("ディレクトリ名にワイルドカードが含まれています:",argv[j]);
		exit(1);
	}
	
	/* ディレクトリ名作成 */
	strsfn32(argv[j],drv,dir,name,ext); /* ファイル名分解 */
	printf("検索ディレクトリ名:%s\n",argv[j]);
	
	/* 出力先がキャラクターデバイスかどうか */
 	fchar=check_char_device(stdout);
	
	if (OpenUni2SJisF(argv[0])) {
		prints("Unicode関数が初期化出来ない\n");
		exit(100);
	}
	/* サーチ */
	{
	unlong scsiid;
	#define CACHEOFFID 0xff
	if (Path2ScsiID(argv[j],&scsiid)==NULL) {
		CloseUni2SJisF();
		printsn("SCSI-IDの指定がおかしい:",argv[j]);
		exit(101);
	}
	if (S_CacheOpen(&_S_scb,scsiid,ALLBLOCK,S_CACHE_READ)) {
		// キャッシュ出来ないので通常読み込みにさせる
		_S_scb.id=CACHEOFFID; // 絶対に一致しないid
	}
	fsearch(argv[j],fname,fcount,&allcount,&dcount);
	if (_S_scb.id!=CACHEOFFID) S_CacheClose(&_S_scb);
	}
	CloseUni2SJisF();
	
	if (fcount>=2) {
		if (allcount==0 && dcount==0) {
			prints("ファイル");
			if (fsdir) prints("・ディレクトリ");
			prints("は見付かりませんでした\n");
		}
		if (allcount>0)  print_num(allcount,"ファイル");
		if (dcount>0) print_num(dcount,"ディレクトリ");
	}
	if (flsize) {
		prints_dec("トータルファイルサイズ：",allsize,"バイト");
		crlf();
	}
	exit(0);
}

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