//==============================================================================================================================
//	スクリプトチェック
//
//
//==============================================================================================================================

#define	SW_MODULE_CHECKSCR

#define	FNAME_MAXLEN	16
#define	FILE_MAX		(1024*8)
#define	FILENAME(num)	(m_pFileList+FNAME_MAXLEN*num)



//------------------------------------------------------------------
//		スクリプトコマンドクラス
//------------------------------------------------------------------
class CHECKSCR{
	
	enum REMTYPE{
		REMTYPE_NOTHING,	//	何もしない
		REMTYPE_CPP,		//	C言語注釈を除外する
		REMTYPE_ASM,		//	アセンブラ注釈を除外する
		REMTYPE_PERL,		//	Perl注釈を除外する
	};
	
	BOOL		m_bInitialized;
	BOOL		m_bImplemented;
	BOOL		m_bFullInit;
	
	TCHAR		*m_pFileList;
	int			m_iFileEntry;
	int			*m_pFileUse;
	
	TCHAR		*m_pNameList;
	int			m_iNameEntry;
	
	
	REMTYPE		iSwRem;
	BOOL		bSwSort;
	BOOL		bSwNoNumber;
	BOOL		bSwFileName;
	
	
	void		Initialize( LPCTSTR filefolder, LPCTSTR param );
	
	int			check_filename( LPTSTR fname );
	int			add_filename( LPCTSTR name );
public:
	int			Func( LPCTSTR _sParamString );
//	int			Func(char *path,char *outname,char *param);
	void		Quit( BOOL _bExit );
	
	CHECKSCR();
	~CHECKSCR();
	
};

//	アプリケーション起動時
CHECKSCR::CHECKSCR()
	: m_bInitialized( FALSE )
	, m_bImplemented( FALSE )
	, m_bFullInit( FALSE )
	, m_iFileEntry( 0 )
	, m_pFileList( NULL )
	, m_pFileUse( NULL )
	, m_pNameList( NULL )
	, m_iNameEntry( 0 )
	, iSwRem( REMTYPE_CPP )	//	1:C言語注釈を除外する　2:アセンブラ注釈を除外する　3:Perl注釈を除外する
	, bSwSort( TRUE )		//	1:結果をソートする
	, bSwNoNumber( TRUE )	//	1:数値のみはファイル名としない
	, bSwFileName( FALSE )	//	1:拡張子を指定してあるものしかファイル名としない
{
}
//	アプリケーション終了時
CHECKSCR::~CHECKSCR(){
}


//==============================================================================================================================================
//	初期化と開放
//		1ファイルに1つの処理でコンプリートするような場合は修正する必要ありません
//		注釈となっている Message_printf を有効にして sample.swb を実行すると動きがよく分かると思います。
//==============================================================================================================================================

//------------------------------------------------------------------
//		スクリプトコマンドの初期化
//			(特に必要ないなら変更の必要なし)
//------------------------------------------------------------------
void	CHECKSCR::Initialize( LPCTSTR filefolder, LPCTSTR param )
{
		
		if(m_bInitialized == TRUE)	return;
		m_bInitialized = TRUE;	//	初期済みフラグ
		
		if(m_bFullInit == FALSE){
			m_bFullInit = TRUE;
			//	全体を通して一度しか行わない初期化
			
			//Message_printf("全体の初期化");
		}
		//	初期化処理
		//	１つのバッチに同じスクリプトが２度指定されていたならここには２度来る
		//Message_printf("初期化");
#if 0	//★★ FILE_GetXcopy 旧verにつき一時凍結
		FILEXCOPY	xcpy;
		int			ii,ent;
		char		path[_MAX_PATH],fPath[_MAX_PATH],fName[_MAX_FNAME];
		DWORD		attr;
		
		
		defaultpath( path, filefolder );
		
		FILE_GetXcopy( &xcpy, path );
		ent = xcpy.files;
		
		mem_alloc(char, m_pFileList, FNAME_MAXLEN*ent )
		m_iFileEntry = 0;
		mem_alloc(int, m_pFileUse, ent );
		
		
		mem_alloc(char,m_pNameList,FNAME_MAXLEN*FILE_MAX)
		m_iNameEntry = 0;
		
		
		for( ii = 0 ;ii < ent ;ii++ ){
			STRING_cpy( fName,(LPSTR)xcpy.mem.lpBuf + xcpy.ptr );
			xcpy.ptr += STRING_len((LPSTR)xcpy.mem.lpBuf + xcpy.ptr)+ 1;
			
			STRING_cpy( fPath,path );
			STRING_cat( fPath,fName );
			attr = GetFileAttributes( fPath );
			
			if( !(attr & FILE_ATTRIBUTE_DIRECTORY)){
				
				if(STRING_len(fName)+1 >= FNAME_MAXLEN){
					Message_error("ファイル名が長すぎます %s",fName);
				}
				if(fName[0]=='\\')	STRING_cpy( FILENAME(m_iFileEntry), fName+1 );
				else				STRING_cpy( FILENAME(m_iFileEntry), fName );
				STRING_SmallToBig( FILENAME(m_iFileEntry) );
				
				m_iFileEntry++;
			}
			else{
				ii--;
				ent--;
			}
		}
		MEM_free( &xcpy.mem );
#else
		int				ii, iEntry;
		TCHAR			sPath[ _MAX_PATH ];//, fPath[ _MAX_PATH ], fName[ _MAX_FNAME ];
		FILE_XCOPY		cXcopy;
		
		
		defaultpath( sPath, filefolder );
		
		cXcopy.Clear();
		cXcopy.SetSearchSubDir( TRUE );
		cXcopy.AddXcopy( sPath );
		
		iEntry = cXcopy.GetEntry();
		
		mem_alloc( TCHAR, m_pFileList, FNAME_MAXLEN * iEntry );
		m_iFileEntry = 0;
		mem_alloc( int, m_pFileUse, iEntry );
		
		
		mem_alloc( TCHAR, m_pNameList, FNAME_MAXLEN * FILE_MAX );
		m_iNameEntry = 0;
		
		
		for( ii = 0 ;ii < iEntry ;ii++ ){
			if( STRING_len( cXcopy.GetFileName( ii ) ) >= FNAME_MAXLEN){
				Message_error( TEXT("ファイル名が長すぎます %s"), cXcopy.GetFileName( ii ) );
				continue;
			}
			STRING_cpy( FILENAME(m_iFileEntry), cXcopy.GetFileName( ii ) );
			m_iFileEntry++;
		}
		
#endif
		
		
		if(param[0] == '-'){
			iSwRem = REMTYPE_NOTHING;
			bSwSort = bSwNoNumber = bSwFileName = FALSE;
			if( STRING_str( param,  TEXT("c") ) != NULL)	iSwRem = REMTYPE_CPP;		//	C言語注釈を除外する
			if( STRING_str( param,  TEXT("a") ) != NULL)	iSwRem = REMTYPE_ASM;		//	アセンブラ注釈を除外する
			if( STRING_str( param,  TEXT("p") ) != NULL)	iSwRem = REMTYPE_PERL;		//	Perl注釈を除外する
			if( STRING_str( param,  TEXT("s") ) != NULL)	bSwSort = TRUE;				//	結果をソートする
			if( STRING_str( param,  TEXT("n") ) != NULL)	bSwNoNumber = TRUE;			//	数値のみはファイル名としない
			if( STRING_str( param,  TEXT("e") ) != NULL)	bSwFileName = TRUE;			//	拡張子を指定してあるものしかファイル名としない
		}
		
		Message_printf( TEXT("path:%s  %d files"), filefolder, m_iFileEntry );
		
		if(iSwRem == REMTYPE_CPP)	Message_win( TEXT("C言語注釈を除外") );
		if(iSwRem == REMTYPE_ASM)	Message_win( TEXT("アセンブラ注釈を除外") );
		if(iSwRem == REMTYPE_PERL)	Message_win( TEXT("Perl注釈を除外") );
		if(bSwSort == TRUE)			Message_win( TEXT("結果はソートされます") );
		if(bSwNoNumber == TRUE)		Message_win( TEXT("数値のみはファイル名と判断しません") );
		if(bSwFileName == TRUE)		Message_win( TEXT("拡張子(ピリオド)のある物のみ判定します") );
		
}


//------------------------------------------------------------------
//		スクリプトコマンドの終了
//			(特に必要ないなら変更の必要なし)
//------------------------------------------------------------------
void	CHECKSCR::Quit( BOOL _bExit )
{
		int			ii,jj,f;
		TCHAR		temp[256];
		
		
		//	ここにはスクリプトを使っていなくても来るので注意
		
		if(m_bImplemented == FALSE)	return;		//	変換処理が実行されていないなら帰還
		m_bImplemented = FALSE;
		
		m_bInitialized = FALSE;
		
		
		if( !m_pFileList || !m_pFileUse || !m_pNameList )	return;
		
		if(m_iNameEntry != 0){
			
			if( bSwSort )
				for(ii=0 ; ii<m_iNameEntry-1 ; ii++)
					for(jj=ii ; jj<m_iNameEntry ; jj++)
						if( STRING_cmp( m_pNameList+FNAME_MAXLEN*jj, m_pNameList+FNAME_MAXLEN*ii ) < 0 )
						{
							STRING_cpy( temp, m_pNameList+FNAME_MAXLEN*ii );
							STRING_cpy( m_pNameList+FNAME_MAXLEN*ii, m_pNameList+FNAME_MAXLEN*jj );
							STRING_cpy( m_pNameList+FNAME_MAXLEN*jj, temp );
						}
			
			Message_win( TEXT("\r\n以下のファイルは見つかりません") );
			for(ii=0 ; ii<m_iNameEntry ; ii++){
				Message_printf( TEXT("%s"), m_pNameList + FNAME_MAXLEN*ii );
			}
		}
		
		
		
		if( bSwSort )
			for(ii=0 ; ii<m_iFileEntry-1 ; ii++)
				for(jj=ii ; jj<m_iFileEntry ; jj++)
					if(STRING_cmp(FILENAME(jj),FILENAME(ii)) < 0){
						STRING_cpy(temp,FILENAME(ii));
						STRING_cpy(FILENAME(ii),FILENAME(jj));
						STRING_cpy(FILENAME(jj),temp);
						f = m_pFileUse[ii];
						m_pFileUse[ii] = m_pFileUse[jj];
						m_pFileUse[jj] = f;
					}
		
		f = 1;
		for(ii=0 ; ii<m_iFileEntry ; ii++){
			if(m_pFileUse[ii] == 0){
				if(f){Message_win( TEXT("\r\n以下のファイルは使用されていません") );f=0;}
				Message_printf( TEXT("	%s"), FILENAME(ii) );
			}
		}
		
		f = 1;
		for(ii=0 ; ii<m_iFileEntry ; ii++){
			if(m_pFileUse[ii] > 1){
				if(f){Message_win( TEXT("\r\n以下のファイルは複数回使用されています") );f=0;}
				Message_printf( TEXT("	%s  %d(s)"), FILENAME(ii), m_pFileUse[ii]);
			}
		}
		
		
		//	終了処理
		//Message_printf("完了");
		
		if( _bExit == TRUE )
		{
			//	次のスクリプトは存在しない、完全な終了
			//	１つのバッチに同じスクリプトに別パラメータを渡しての処理で
			//	逐一結果を出さず、全体で統合して結果を出したい場合などはここで
			
			//Message_printf("終了");
			
			mem_del(m_pFileList);
			mem_del(m_pFileUse);
			
			mem_del(m_pNameList);
			
		}
		
}



int		CHECKSCR::check_filename( LPTSTR fname )
{
		int		f,ii;
		TCHAR	name[_MAX_FNAME];
		
		
		f = 0;
		STRING_ToBig(fname);
		for( ii=0 ; ii<STRING_len(fname) ; ii++ )
			if(fname[ii] == '.'){
				f = 1;
				break;
			}
		
		
		for( ii=0 ; ii<m_iFileEntry ; ii++ ){
			FILE_split( FILENAME(ii), NULL, NULL, name, NULL );
			
			if(f==1){
				if(STRING_cmp( fname, FILENAME(ii) ) == 0 )	return ii;
			}else{
				if(STRING_cmp( fname, name ) == 0 )			return ii;
			}
		}
		
		return -1;
}




//==============================================================================================================================================
//	変換処理部分
//==============================================================================================================================================

#define	CHECKSCR_RANGE				//	このdefineを有効にすると範囲限定機能が有効になる

//------------------------------------------------------------------
//	変換フィルターサンプル　機能:無変換(ファイルコピー)
//			変換せず調査だけなら out に関する部分は不要
//------------------------------------------------------------------
int		CHECKSCR::Func( LPCTSTR _sParamString )
{
		CSwbParam	cParam( _sParamString );							///< パラメータ処理.
	
		TCHAR	*mem=NULL, temp[FNAME_MAXLEN+2];
		int		ii, jj, n, len, idx;
		xstring	sPath, sFilefolder, sParam;
		
		
		/// 引数の取り出し.
		sPath       = cParam.GetPath();		///< ターゲットファイル (GetFilePath(0)としても同じ).
		sFilefolder = cParam.GetOutPath();	///< 出力ファイルパス取得(%0等が変換されて得られる).
		sParam      = cParam.GetString( cParam.SearchOption() );
		
		
		if(sFilefolder[0] == '-'){
			Message_error( TEXT("フォルダが指定されていません") );
			return FALSE;
		}
		
		Initialize( sFilefolder.c_str(), sParam.c_str() );
		
		
		if( !m_pFileList || !m_pFileUse || !m_pNameList )	return FALSE;
		
		len = MEM_TextRead( &mem, sPath.c_str() );
		if(len == 0)	return FALSE;		//	ファイルがない
		
		
		if(iSwRem == REMTYPE_CPP)	len = FILT_deleteREM( mem, len  );		//	行注釈記号,範囲注釈記号始点,範囲注釈記号終点,文字列とする記号
		if(iSwRem == REMTYPE_ASM)	len = FILT_deleteREM( mem, len, TEXT(";"), NULL, NULL );
		if(iSwRem == REMTYPE_PERL)	len = FILT_deleteREM( mem, len, TEXT("#"), NULL, NULL );
		FILT_ToBig( mem, len, 0 );		//	大文字に
		
		
		m_bImplemented = TRUE;	//	実行済みフラグ
		
		ii = 0;
		#ifdef	CHECKSCR_RANGE
		cRange.Init(mem,len);						//範囲限定機能を有効にするにはこの初期化と
		while(cRange.Is(mem,ii,len))	ii++;		//　初回スキップ、下の[スキップ判定]が必要。スキップが必要な間trueが返りループしている
		#endif
		
		jj = 0;
		while(ii < len){
			#ifdef	CHECKSCR_RANGE
			while(cRange.Is(mem,ii,len))	ii++;	//	スキップ判定
			#endif
			
			if( STRING_IsMultiByte(*(mem+ii)) ){	//	全角文字だ
				ii += STRING_GetMultiByte();
				continue;
			}
			if( *(mem+ii)=='\"' ){		//	文字列指定
				ii++;
				jj = 0;
				while(*(mem+ii)!='\"'){
#ifndef	_UNICODE
					if( _ismbblead(*(mem+ii)) != 0 )	//	全角文字だ
						temp[jj++] = *(mem+ii++);
#endif
					temp[jj++] = *(mem+ii++);
					if(jj >= FNAME_MAXLEN){
						jj=0;
						while(*(mem+ii)!='\"')	ii++;
						break;
					}
					if( *(mem+ii) == ' ' || *(mem+ii) == '\t' ){
						jj=0;
						while(*(mem+ii)!='\"')	ii++;
						break;
					}
				}
				temp[jj] = 0;
				ii++;		//	"の分
				if(jj==0)	continue;		//	空
			}else if(*(mem+ii)=='(' || *(mem+ii)==','){
				ii++;
				while(*(mem+ii)==' ' || *(mem+ii)=='\t')	ii++;
				
				if(*(mem+ii)=='\"')	continue;		//	文字列指定
				if( STRING_IsMultiByte(*(mem+ii)) )	continue;
				
				jj = 0;
				while(
					*(mem+ii)!=',' && 
					*(mem+ii)!='(' && 
					*(mem+ii)!=')' && 
					*(mem+ii)!='[' && 
					*(mem+ii)!=']' && 
					*(mem+ii)!='\\' && 
					*(mem+ii)!='|' && 
					*(mem+ii)!='&' && 
					*(mem+ii)!='+' && 
					*(mem+ii)!='-' && 
					*(mem+ii)!='*' && 
					*(mem+ii)!='/' && 
					*(mem+ii)!=':' && 
					*(mem+ii)!='=' && 
					*(mem+ii)!='?' && 
					*(mem+ii)!=' ' && 
					*(mem+ii)!='\t' && 
					*(mem+ii)!='\r' && 
					*(mem+ii)!='\n' && 
					*(mem+ii)!='@'){
					
#ifndef	_UNICODE
					if( _ismbblead(*(mem+ii)) != 0 )	//	全角文字だ
						temp[jj++] = *(mem+ii++);
#endif
					temp[jj++] = *(mem+ii++);
					if(jj >= FNAME_MAXLEN){jj=0;break;}
				}
				while(*(mem+ii)==' ' || *(mem+ii)=='\t')	ii++;
				if(
					*(mem+ii)=='[' || 
					*(mem+ii)==']' || 
					*(mem+ii)=='\\' || 
					*(mem+ii)=='|' || 
					*(mem+ii)=='&' || 
					*(mem+ii)=='+' || 
					*(mem+ii)=='-' || 
					*(mem+ii)=='*' || 
					*(mem+ii)=='/' || 
					*(mem+ii)==':' || 
					*(mem+ii)=='=' || 
					*(mem+ii)=='?' || 
					*(mem+ii)=='@')	jj = 0;
				
				temp[jj] = 0;
				if(jj==0)	continue;
			}
			else
				ii++;
			
			if(jj != 0){		//	tempに何か入ってきた
				int		f_fname,f_str,f_knj;
				
				f_fname = f_str = f_knj = 0;
				for(n=0 ; n<jj ; n++){
					if( STRING_IsMultiByte(temp[n]) ){	//	全角文字だ
						n++;
						f_knj = f_str = 1;
						continue;
					}
					if(temp[n] == '.'){
						f_fname = 1;		//	ファイル名である可能性が高い
					}
					if(temp[n] < '0' || temp[n] > '9')	f_str = 1;
				}
				
				if(f_knj == 1 && f_fname == 0)			continue;	//	全角が含まれる物は'.'がないとファイル名と判断しない
				if(bSwNoNumber == TRUE && f_str == 0)	continue;
				if(bSwFileName == TRUE && f_fname == 0)	continue;
				
				idx = check_filename(temp);
				if(idx != -1){
					m_pFileUse[idx]++;
				//	Message_printf("file: %s %d",temp,m_pFileUse[idx]);
				}else{
					add_filename(temp);
				}
				jj = 0;
			}
			
		}
		
		
		//	メモリを開放
		mem_del(mem);
		
		return TRUE;
}


//		
int		CHECKSCR::add_filename( LPCTSTR name )
{
		int		ii;
		
		
		for(ii=0 ; ii<m_iNameEntry ;ii++){
			if(STRING_cmp((m_pNameList + FNAME_MAXLEN*ii),name)==0)	return 0;
		}
		
		STRING_cpy((m_pNameList + FNAME_MAXLEN*ii),name);
		m_iNameEntry++;
		
		return 1;
}


CHECKSCR	*pC_checkscr = NULL;

