// ★コメント未記入
// FinderBREGEXP.cpp: CFinderBREGEXP クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "shitarabian.h"
#include "FinderBREGEXP.h"
#include "BregPool.h"
#include "Selection.h"
#include "ShitarabianDoc.h"
#include "ExeCommon.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

CFinderBREGEXP::CFinderBREGEXP()
{

}

CFinderBREGEXP::~CFinderBREGEXP()
{

}



BOOL	CFinderBREGEXP::IsAlive()
{
	CBregPool* pBRegPool = CBregPool::GetInstance();
	BOOL		bRegExp = pBRegPool->IsAlive();
	return( bRegExp );
}

CString	CFinderBREGEXP::Name()
{
	return("BREGEXP.DLL");
}

// 行から文字列を検索
BOOL CFinderBREGEXP::FindAtLine(
	CString&			strTarget,
	long				idxStartColumn,
	long				idxEndColumn,
	CString&			strSubStringSrc,
	long*				pidxFoundCaretColumn,
	long*				pnCaretColumn,
	BOOL				bCaseCare,
	BOOL				bToken
)
{
	BOOL	bFound = FALSE;

	// 検索対象文字列取得
	if ( !strTarget.IsEmpty() )
	{
		// 行頭が要求されているかのフラグを得る
		BOOL	bLineFirst;
		long	iDummy1, iDummy2;
		bLineFirst = Match(
			strSubStringSrc,
			"/[^\\\\\\[]*\\^/",
			&iDummy1, &iDummy2,
			FALSE,FALSE
		);

		// パターンについて、"\/"でない"/"を"\/"に変換する please!
		// 難しい。どんな正規表現になる？　とりあえずあきらめる。

		// Perl正規表現文字列作成
		CString		strSubStringFormat;
		strSubStringFormat.Format( "/%s/k", strSubStringSrc );

		long	lOffsetByteColumn = 0;
		long	lOffsetCaretColumn = 0;
		bFound = TRUE;
		while ( bFound )
		{
			bFound = FALSE;

			if ( lOffsetByteColumn > strTarget.GetLength()-1 )
			{
				break;
			}

			long		idxFoundByteColumn;
			long		nFoundByte;
			const char*	pstr = ((LPCTSTR)(strTarget))+lOffsetByteColumn;
			bFound = Match(
				pstr,
				strSubStringFormat,		// パターンとして完成した文字列
				&idxFoundByteColumn,
				&nFoundByte,
				bCaseCare,
				bToken
			);
			if ( bFound )
			{
				// 発見した位置のカラム
				int		idxFoundCaretColumn;
				idxFoundCaretColumn = ::ByteColumnToCaretColumn( pstr, idxFoundByteColumn );

				// 長さ
				int		nCaretColumn;
				nCaretColumn = ::ByteColumnToCaretColumn( pstr+idxFoundByteColumn, nFoundByte );

				// Match位置が指定範囲内なら採用
				if( idxStartColumn <= lOffsetCaretColumn+idxFoundCaretColumn )
				if( lOffsetCaretColumn+idxFoundCaretColumn+nCaretColumn <= idxEndColumn )
				{
					*pidxFoundCaretColumn = lOffsetCaretColumn+idxFoundCaretColumn;
					*pnCaretColumn = nCaretColumn;
					break;
				}

				if( bLineFirst )
				{
					bFound = FALSE;
					break;
				}

				lOffsetByteColumn += idxFoundByteColumn+nFoundByte;
				lOffsetCaretColumn += idxFoundCaretColumn + nCaretColumn;
			}
		}
	}

	return( bFound );
}




CString CFinderBREGEXP::GetReplaceWord(
	CShitarabianDoc*	pDoc,
	long				idxRow,
	long				idxStartColumn,
	long				idxEndColumn,
	CString&			strSubString,
	CString&			strReplaceFormat,
	BOOL				bCaseCare,
	BOOL				bToken
)
{
	// warning C4100:警告の無視
	bToken; bCaseCare;

	CString*	pstrTarget = pDoc->GetLine( idxRow );
	CString		strSubLine;
	{
		if( pstrTarget == NULL )
		{
			ASSERT( FALSE );
			return( "" );
		}
	}

	CString		strAfter( strReplaceFormat );
	{
		CBregPool* pBRegPool = CBregPool::GetInstance();

		char	msg[80];	// メッセージ領域
		char*	pTarget = pstrTarget->GetBuffer( pstrTarget->GetLength() );

		CString		strSub;
		strSub.Format( "s/%s/%s/k", strSubString, strReplaceFormat );
		char*	pSubString = strSub.GetBuffer( strSub.GetLength() );
		BREGEXP *rxp = NULL;

		// Substは置換をかけた行全体を返すので、あらかじめ検索ＨＩＴ範囲だけちぎって渡してやる
		// これによってnot行頭指定とか利かなくなるような気がするのだが please! 
		long	idxStartByte = ::CaretColumnToByteColumn(
			pTarget,
			idxStartColumn
		);
		long	idxEndByte = ::CaretColumnToByteColumn(
			pTarget + idxStartByte,
			idxEndColumn - idxStartColumn
		) + idxStartByte;

		if ( pBRegPool->Subst(
				pSubString,
				pTarget + idxStartByte,
				pTarget + idxEndByte,
				&rxp, msg)
		)
		{
			strAfter = rxp->outp;
			char	cr[2] = { 0x0A, 0x00 };
			char	crlf[3] = { 0x0D, 0x0A, 0x00 };
			strAfter.Replace( cr, crlf);
		}

		if ( rxp != NULL )
		{

			// コンパイルブロックの解放
			if ( rxp != NULL )
			{
				pBRegPool->Free( rxp );
			}
		}
		pstrTarget->ReleaseBuffer();
		strSub.ReleaseBuffer();
	}
	return( strAfter );

}


BOOL CFinderBREGEXP::Match(
	const char*			pTarget,
	const char*			pSubString,		// パターンとして完成した文字列
	long*				pidxFoundByte,
	long*				pnFoundByte,
	BOOL				bCaseCare,
	BOOL				bToken
)
{	// warning C4100:警告の無視
	bToken; bCaseCare;

	BOOL	bFound = FALSE;

	long	iLength = strlen( pTarget );
	if ( iLength > 0 )
	{
		// 正規表現オブジェクト
		CBregPool*	pBRegPool = CBregPool::GetInstance();
		char		msg[80];	// メッセージ領域

		// 検索情報の作成
		BREGEXP		*rxp = pBRegPool->Get( const_cast<char*>(pSubString) );

		if( rxp != NULL )
		{
			bFound = pBRegPool->Match(
				const_cast<char*>( pSubString ),
				const_cast<char*>( pTarget ),
				const_cast<char*>( pTarget ) +iLength,
				&rxp,
				msg
			);
			if ( bFound )
			{
				// 発見した位置のカラム
				long	idxFoundByte = rxp->startp[0] - pTarget;
				// 長さ
				long	nFoundByte = rxp->endp[0] - rxp->startp[0];

				*pidxFoundByte = idxFoundByte;
				*pnFoundByte = nFoundByte;
			}
		}

		// コンパイルブロックの開放
		if ( rxp != NULL )
		{
			pBRegPool->Free( rxp );
		}
	}

	return( bFound );
}




long CFinderBREGEXP::GetMatchz(
	CString&					strSrc,
	CString&					strSubString,
	CArray<TMatch, TMatch& >*	paMatchz,
	BOOL						bCaseCare,
	BOOL						bToken,
	BOOL						bNeedSubMatch
)
{
// ▼ (ワーニング回避) BGN 2003.12.29 (moralog) warning C4100
	// warning C4100 回避
	bNeedSubMatch;
// ▲ (ワーニング回避) END

	BOOL	bFound = FALSE;

	// 検索対象文字列取得
	CString*	pstrTarget = &strSrc;
	if ( pstrTarget->GetLength() > 0 )
	{
		// 行頭が要求されているかのフラグを得る
		BOOL	bLineFirst;
		long	iDummy1, iDummy2;
		bLineFirst = Match(
			strSubString,
			"/[^\\\\\\[]*\\^/",
			&iDummy1, &iDummy2,
			FALSE,FALSE
		);

		// パターンについて、"\/"でない"/"を"\/"に変換する please!
		// 難しい。どんな正規表現になる？　とりあえずあきらめる。

		// Perl正規表現文字列作成
		CString		strSubStringFormat;
		strSubStringFormat.Format( "/%s/k", strSubString );

		long	lOffsetByteColumn = 0;
		long	lOffsetCaretColumn = 0;
		bFound = TRUE;
		while ( bFound )
		{
			bFound = FALSE;

			if ( lOffsetByteColumn > pstrTarget->GetLength()-1 )
			{
				break;
			}

			long		idxFoundByteColumn;
			long		nFoundByte;
			const char*	pstr = (LPCTSTR)(*pstrTarget)+lOffsetByteColumn;
			bFound = Match(
				pstr,
				strSubStringFormat,		// パターンとして完成した文字列
				&idxFoundByteColumn,
				&nFoundByte,
				bCaseCare,
				bToken
			);
			if ( bFound )
			{
				// 発見した位置のカラム
				int		idxFoundCaretColumn;
				idxFoundCaretColumn = ::ByteColumnToCaretColumn( pstr, idxFoundByteColumn );

				// 長さ
				int		nCaretColumn;
				nCaretColumn = ::ByteColumnToCaretColumn( pstr+idxFoundByteColumn, nFoundByte );

				// Match位置が指定範囲内なら採用
				{
					TMatch	Match;
					Match.idxStartColumn = lOffsetCaretColumn+idxFoundCaretColumn;
					Match.nColumn = nCaretColumn;
					paMatchz->Add( Match );
				}

				if( bLineFirst )
				{
					bFound = FALSE;
					break;
				}

				lOffsetByteColumn += idxFoundByteColumn+nFoundByte;
				lOffsetCaretColumn += idxFoundCaretColumn + nCaretColumn;
			}
		}
	}
	return( paMatchz->GetSize() );
}


/*-----------------------------------------------------------------------------
[名称]	文字列検索
[機能]	対照文字列から任意の文字列をひとつ検索する。
[戻値]	BOOL	検索結果 [-] (TRUE:マッチ、FALSE:マッチしない)
[備考]	複数行強調表示色の終端文字列の検索に使用する。
-----------------------------------------------------------------------------*/
BOOL CFinderBREGEXP::QuickMatch(
	LPCTSTR			strSrc,			// I  :検索対象文字列 [-] (-) :-
	CString&		strSubString,	// I  :検索文字列 [普通の文字列] (-) :-
	TMatch*			pMatch,			//   O:マッチ情報 [-] (-) :-
	BOOL			bCaseCare,		// I  :大文字小文字区別 [-] (TRUE:する、FALSE:しない) :-
	BOOL			bToken			// I  :単語単位 [-] (TRUE:する、FALSE:しない) :-
)
{
	BOOL	bFound = FALSE;

	// 検索対象文字列取得
	if ( strSrc != NULL )
	if ( *strSrc != 0x00 )
	{
		// Perl正規表現文字列作成
		CString		strSubStringFormat;
		strSubStringFormat.Format( "/%s/k", strSubString );

		long		idxFoundByteColumn;
		long		nFoundByte;
//		const char*	pstr = (LPCTSTR)(*pstrTarget);
		bFound = Match(
			strSrc,
			strSubStringFormat,		// パターンとして完成した文字列
			&idxFoundByteColumn,
			&nFoundByte,
			bCaseCare,
			bToken
		);
		if ( bFound )
		{
			pMatch->idxStartColumn = ::ByteColumnToCaretColumn( strSrc, idxFoundByteColumn );
			pMatch->nColumn = ::ByteColumnToCaretColumn( strSrc+idxFoundByteColumn, nFoundByte );
		}
	}
	return( bFound );
}


