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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>	// exit
#include <io.h>
#include <conio.h>
#include <jfctype.h>
#include "defines.h"
#include "astring.h"
#include "astdio.h"
#include "amacro.h"
#include "aparam.h"
#include "adisk.h"
#include "akey.h"
#include "acdata.h"
#include "fat32.h"

char prog[]="@@> DUMP32.C : 2000/12/05 TUE : COMMAND : DUMP32 : X680x0 : GCC";

// 2000/09/13	FAT32版
// 2000/09/20	/?時のメッセージが間違っていたので修正
// 2000/10/03	ロングファイル名対応
// 2000/10/19	ファイル名長定数をfat32.hのそれに合わせて変更
//		ロングファイル名関数差し替えに対応（実行ファイル大幅サイズ縮小）
// 2000/12/05	コンパイル時のWarningを減らした
/*****************************************************************************/

#define	WIDMAX	64	/* ダンプ１行最大バイト数 */
#define	SRCHMAX	128	/* サーチコード最大バイト数／２ */

FILE32	ifp;
int	fasc,fadrs,wid,fofst,ffile,fcr,fwa,fup,fgage,gage;
int	fkbclr,fchar;
long	oadrs;
long	filemax;

/* サーチモード専用 */
int	fsrch,scount,count,fsadrs;
long	sbyte,sback;
unchar	scode[SRCHMAX+1];

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

int print_asc1(unchar *rbuff,long ad,long ead,int len,int fcc)
/* １行ASC表示 */
/* fcc!=0:前の行に１バイト貸してある , ==0:貸しはない */
{
unchar c,cc;
	if (fcc) { /* 前の行に貸したので消してしまう */
		fcc=0;
		rbuff++;
		ad++;
		len--;
		spc();
	}
	while (len>0) {
		c=*rbuff++;
		ad++;
		len--;
		if (fasc!=1) {
		    if (iskanji(c)) {
			if (len==0) { /* ２バイト目がない */
				if (ad>=ead) goto PA1; /* 領域中になし */
				/* ２バイト目を借りてくる */
				fcc=1; /* 借りた印 */
			}
			cc=(fcc? fgetc32(&ifp):*rbuff);
			if (!iskanji2(cc)) { /* 漢字として無効 */
				if (fcc) ungetc32(cc,&ifp); /* ファイルに戻す */
				fcc=0; /* 借りは帳消し */
				goto PA1;
			}
			printc(c);
			printc(cc);
			if (fcc) break; /* 借りているときはここで終わり */
			rbuff++;
			ad++;
			len--;
			continue;
		    }
		}
		if (!isprkana(c)) { /* コントロールコード */
		    PA1:c='.';
		}
		printc(c);
	}
	if (fcc) ungetc32(cc,&ifp); /* ファイルに戻す */
	return(fcc);
}

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

long print_dump1(long adrs,long ead,int wid,int *fcc,FILE *fp)
/* １行ダンプ */
/* 開始アドレスがwidの倍数でない時はwid境界に合せる */
{
int i,adw=0,c;
long ad;
unchar rbuff[WIDMAX];
	/* 境界処理 */
	if (!fwa) adw=(adrs-oadrs)%wid; /* oadrsがある時はwid=0とする */
	
	/* アドレス */
	if (fadrs) {
		print_hex8(adrs-oadrs-adw,fup);
		prints(" : ");
	}
	
	/* dump */
	if (adw) prints(kstring(adw,"   "));
	ad=adrs;
	wid-=adw;
	for (i=0;i<wid && ad<=ead;i++) {
		if ((c=fgetc32(&ifp))==EOF) return(-1); /* 本当はerror */
		print_hex2(c,fup); spc();
		if (ffile) {
			if (fputc(c,fp)==EOF) { /* エラーの可能性あり */
				if (ferror(fp)) return(-2); /* error */
			}
		}
		rbuff[i]=c;
		ad++;
	}
	if (i<wid) prints(kstring(wid-i,"   "));
	
	/* asc */
	if (fasc) {
		prints(": ");
		if (adw) prints(kstring(adw," "));
		*fcc=print_asc1(rbuff,adrs,ead,i,*fcc);
		if (i<wid) prints(kstring(wid-i," "));
	}
	crlf();
	if (kbhit()&& getch()==ESC) return(-1);
	
	if (fchar) kslow();
	if (fkbclr) kbclr(); /* キーボードバッファークリア */
	return(ad);
}

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

long search(long ad,long eadrs,int *ret)
/* コードサーチ */
/* リターン値：エンドアドレス */
/* アドレス＝シーク値 */
{
long ad2;
int i;
	*ret=1; /* 不一致シンボル */
	ad2=ad+fsrch;
	if (ad2>eadrs) return(ad2); /* 範囲内ではサーチできない＝不一致 */
	
	for (i=0;i<fsrch;i++) {
		if (fgetc32(&ifp)!=scode[i]) break;
	}
	if (i==fsrch) {	/* 一致 */
		*ret=0; /* 一致シンボル */
		return(ad+sbyte-1);
	}
	/* 不一致 */
	return(ad+1);
}

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

void PrintGage(int wid)
/* ゲージ表示 */
{
int i,h;
static unchar s[4]="+@ ";
	if (fadrs) prints("Address  : ");
	for (h=i=0;i<wid;i++) {
		s[1]=(h>=10? h+'A'-10:h+'0');
		prints(s);
		if ((++h)==16) h=0; /* +0〜+F */
	}
	if (fasc) {
		prints(": ");
		for (h=i=0;i<wid;i++) {
			printc(h>=10? h+'A'-10:h+'0');
			if ((++h)==16) h=0; /* +0〜+F */
		}
	}
	crlf();
}

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

int dump_main(long ad,long ead,FILE *fp)
/* 指定アドレス間ダンプ */
{
int i,fcc=0; /* 前の行からの借り無し */
long eadrs;
	if (fsrch) { /* サーチモード */
		prints("<< サーチコード : ");
		for (i=0;i<fsrch;i++) {
			print_hex2(scode[i],fup);
			spc();
		}
		prints(" >>\n");
	}
	
	oadrs=(fofst? ad:0);
	if (fadrs) {
		prints("< ");
		print_hex8(ad,fup);
		prints(" 〜 ");
		print_hex8(ead,fup);
		prints(" >\n");
		if (oadrs) {
			prints("[ ");
			print_hex8(oadrs,fup);
			prints(" : offset]\n");
		}
	}
	
	eadrs=ead;
	if (fsrch) { /* サーチモード */
		while (ad<=eadrs && fcc>=0) {
			if (fsadrs) {
				print_hex8(ad,fup);
				printc('\r');
			}
			if (kbhit()&& getch()==ESC) return(-1L);
			ead=search(ad,eadrs,&i);
			if (i) { /* 不一致 */
				ad=ead;
				fseek32(&ifp,ad,SEEK_SET);
				continue;
			}
			count++; /* 一致回数 */
			ad-=sback;
			if (ad<0L) ad=0L;
			fseek32(&ifp,ad,SEEK_SET);
			fcc=0;
			while (ad<=ead && fcc>=0) {
				ad=print_dump1(ad,ead,wid,&fcc,fp);
				if (ad<0L) break;
			}
			if (ad<0L) {
				crlf();
				break;
			}
			if (scount>0 && count>=scount) break;
			if (fcr) crlf();
		}
	} else { /* 通常ダンプモード */
		if (fgage && (ad%gage)!=0) PrintGage(wid);
		while (ad<=eadrs && fcc>=0) {
			if (fgage && (ad%gage)==0) PrintGage(wid);
			ad=print_dump1(ad,eadrs,wid,&fcc,fp);
			if (ad<0L) {
				crlf();
				break;
			}
		}
		if (fgage && (ad%gage)!=0) PrintGage(wid);
	}
	if (fsrch) { /* サーチモード：カウンター表示 */
		prints("コードは");
		if (count==0) prints("見つかりませんでした\n");
		else {
			spc();
			print_dec(count);
			prints("回見つかりました\n");
		}
	}
	return(fcc<0? fcc:0);
}

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

void main(int argc,unchar *argv[])
{
int i;
long sad,ead,byte/*,filemax*/;
unchar fname[MAXPATH32];
FILE *fp;
	/* parameter check */
	/* オプションチェック初期化 */
	clear_param();
	if (helpcom(argc,argv,0,"DUMP32","[Options] FAT32フルパス名")) exit(255);
	
	/* /! = key board buffer clear mode */
	fkbclr=check_param2("!",argv,argc,0);
	fchar=check_char_device(stdout); /* 出力先がｷｬﾗｸﾀｰﾃﾞﾊﾞｲｽかどうか */
	
	/* ASC mode */
	fasc=2;
	if (check_param3("A",argv,argc,&fasc,0)) {
		if (fasc<0||fasc>2) fasc=2;
	}
	
	/* adrs なし mode */
	fadrs=(!check_param2("NA",argv,argc,0));
	
	/* offset adrs mode */
	fofst=check_param2("OA",argv,argc,0);
	
	/* アドレス境界揃えなし */
	fwa=check_param2("WA",argv,argc,0);
	
	/* アドレス区切りで改行する */
	fcr=check_param2("C",argv,argc,0);
	
	/* １６進文字大文字小文字 */
	fup=check_param2("U",argv,argc,0);
	
	/* アドレス　*/
	sad=0L;
	if (check_param3L("ST",argv,argc,&sad,BIT2)) {
		if (sad<0) sad=0;
	}
	ead=-1;
	if (check_param3L("ED",argv,argc,&ead,0)) {
		if (ead<0) ead=-1;
	}
	
	/* １行バイト数　*/
	wid=16;
	if (check_param3("W",argv,argc,&wid,0)) {
		if (wid<0||wid>WIDMAX) wid=16;
	}
	
	/* ゲージ表示 */
	gage=256;
	fgage=check_param3("G",argv,argc,&gage,0);
	if (fgage) {
		if (gage<0) gage=wid;
	}
	
	/* /F"fname",/F,fname = ファイル出力 */
	// 出力されるファイルはHumanのFAT12/16上である
	ffile=check_param2("F",argv,argc,BIT3|BIT4);
	if (ffile) {
		znstrcpy3(fname,fd_path(argv[ffile]),MAXPATH);
		/* /Fの後にファイル名がなければ"DUMP.DAT"にする */
		if (fname[0]==0) strcpy(fname,"dump.dat");
	}
	
	/* /S"hexstr",/S,hexsrt = コードサーチモード */
	fsrch=check_param2("S",argv,argc,BIT3|BIT4);
	if (fsrch) {
	    unchar line[SRCHMAX*2+1];
		znstrcpy3(line,argv[fsrch],SRCHMAX);
		/* コード変換（文字列->バイトデータ）*/
		fsrch=hexstr(line,scode,SRCHMAX);
		if (fsrch==0) {
			printsn("\aサーチコードが異常です：",line);
			exit(8);
		}
	}
	if (fsrch) { /* サーチモードのみ有効なオプション */
		/* 何回見つかるまでサーチを続けるか */
		if (check_param3("SC",argv,argc,&scount,BIT2)) {
			if (scount<0) scount=0;
		}
		count=0;
		
		/* 見つかったとき何バイト表示するか */
		if (check_param3L("SL",argv,argc,&sbyte,BIT2)) {
			if (sbyte<0L) sbyte=0L;
		}
		if (sbyte==0L) sbyte=fsrch; /* コード長 */
		
		/* 見つかったとき何バイト前から表示するか */
		if (check_param3L("SB",argv,argc,&sback,BIT2)) {
			if (sback<0L) sback=0L;
		}
		
		/* サーチアドレス表示モード */
		fsadrs=check_param2("SA",argv,argc,0);
	}
	
	/* 表示バイト数 */
	if (check_param3L("L",argv,argc,&byte,BIT2)) {
		if (byte<0L) byte=0L;
	}
	
	/* オプションチェック */
	i=check_param_error(argv,argc);
	if (i) {
		printsn("\aオプションエラーです：",argv[i]);
		exit(1);
	}
	
	/* ファイル名 */
	i=getfname(argc,argv,1,NULL);
	if (i==0) {
		prints("\aファイル名を指定してください\n");
		exit(2);
	}
	/* ファイルオープン */
	if (vfopen32(argv[i],"rb",&ifp)) {
		printsn("\aファイルが見つかりません：",argv[i]);
		exit(3);
	}
	
	filemax=filelength32(&ifp);
	if (sad<0) sad=0L;
	if (sad>=filemax) {
		prints("\a開始アドレスがファイルサイズを越えています：");
		print_hex8(sad,fup);
		crlf();
		exit(3);
	}
	if (byte>0L) ead=sad+byte-1;
	if (ead<0L) ead=filemax-1;
	if (ead>=filemax) {
		prints("\a終了アドレスがファイルサイズを越えています：");
		print_hex8(ead,fup);
		crlf();
		exit(5);
	}
	if (ead<sad) {
		long ad;
		ad=ead;
		ead=sad;
		sad=ad;
	}
	
	/* メイン処理 */
	if (ffile) {
		fp=fopen(fname,"wb");
		if (fp==NULL) {
			fclose32(&ifp);
			printsn("\a書き出しファイルがオープンできません：",fname);
			exit(5);
		}
	}
	if (OpenUni2SJisF(argv[0])) {
		prints("Unicode関数が初期化出来ない\n");
		exit(100);
	}
	fseek32(&ifp,sad,SEEK_SET); /* スタートシーク */
	i=dump_main(sad,ead,fp);
	fclose32(&ifp);
	CloseUni2SJisF();
	if (ffile) {
		fclose(fp);
		if (i==-2) {
			printsn("\aファイル書き出しエラー：",fname);
			exit(6);
		}
	}
	exit(0);
}

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