/***************************************************************************
**
**    $Header:   D:/EP196/SRC/LOG/SRCDLL/SRCGBL.CPP   1.0   15 Aug 1997 14:03:42   ZJRD  $
**
**    $Log:   D:/EP196/SRC/LOG/SRCDLL/SRCGBL.CPP  $
** 
**    Rev 1.0   15 Aug 1997 14:03:42   ZJRD
** Initial revision.
** 
****************************************************************************/

// srcgbl.cpp : implementation file
//

#include "stdafx.h"
#include "srcdll.h"
#include "srcgbl.h"
#include "srcaddr.h"
#include "bptdata.h"
#include "srcdat.h"

#include "address.h"
#include "abiextfn.h"
#include "ldrexp.h"

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

/////////////////////////////////////////////////////////////////////////////
// Global variable

CMultiDocTemplate* pSourceTemplate = 0;
CMultiDocTemplate* pBrowseTemplate = 0;

CMDIChildWnd* pSourceWnd = 0;
CMDIChildWnd* pBrowseWnd = 0;

CSourceSearchDlg* pSrcSearchDlg = 0;

BOOL bSrcHintsOn(FALSE);

int nSrcLoadOption(LDR_CODE|LDR_SYMBOL|LDR_STATUS|LDR_WARNING);
CString* pSrcTargetPath = 0;
CString* pSrcTargetExt = 0;

CStringList* pSourcePathList = 0;
CStringList* pSourceExtNameList = 0;

BOOL bSrcSearchWord(FALSE);
BOOL bSrcSearchCase(FALSE);
int nSrcSearchDirect(1);
CStringList* pSourceSearchList = 0;

int g_nSrcGroupEntry(SRC_NULL);

int g_nSrcModuleDepth(0);
int g_nSrcModuleIndex(-1);
CObList* g_pSourceModuleDescList = 0;

int g_nBrwModuleDepth(0);
int g_nBrwModuleIndex(-1);
CObList* g_pBrowseModuleDescList = 0;

CStringList* pSourceFromList = 0;
CStringList* pSourceJumpList = 0;

CObList* pSourceModuleInfoList = 0;

BOOL bSrcAbortLoad(FALSE);

BOOL bSrcSymbolic(TRUE);

/////////////////////////////////////////////////////////////////////////////
// Global string

static char BASED_CODE szLine[] = " --- ";
static char BASED_CODE szPoint[] = "...";
static char BASED_CODE szFormatDWord[] = "%u";

/////////////////////////////////////////////////////////////////////////////
// Imported function

void SrcGetInitPC(CSourceAddr& Addr)
{
	// Get initial PC from Loader
	DWORD dwAddr;
	int nBank;
 	::LdrGetStartAddress(dwAddr, nBank); 

	Addr = CSourceAddr(dwAddr, nBank);
}

BOOL SrcGetModuleList(CStringList* &pList)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get all of the module name
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		pList->AddTail(((CModuleInfo*)pModuleList->GetNext(posModule))->GetName());
	}

	return TRUE;
}

BOOL SrcGetModuleName(const SYM_DESCRIPTOR dwModuleDesc, CString& strModuleName)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	strModuleName = "";
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get the specific module name by descriptor
	POSITION pos = pModuleList->GetHeadPosition();
	while ( pos ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(pos);
		if ( pObj->GetDesc() == dwModuleDesc ) {
			strModuleName = pObj->GetName();
			return TRUE;
		}
	}
	return FALSE;
}

BOOL SrcGetFunctionList(const CString& strModule, CStringList* &pList)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get all of the function names of the specific module
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		if ( strModule == pObj->GetName() ) {
			CObList* pFuncList = pObj->GetFuncList();
			if ( pFuncList->IsEmpty() ) {
				return FALSE;
			}
			
			// Add all of the functions' name
			POSITION posFunc = pFuncList->GetHeadPosition();
			while ( posFunc ) {
				pList->AddTail(((CFuncInfo*)pFuncList->GetNext(posFunc))->GetName());
			}
			return TRUE;
		}
	}

	return FALSE;
}

BOOL SrcGetLineRange(const BOOL bBrowse, const int nLine, CSourceAddr& AddrStart, CSourceAddr& AddrEnd)
{
	// Invalid index
	int nIndex = bBrowse ? ::g_nBrwModuleIndex : ::g_nSrcModuleIndex;
	if ( nIndex < 0 ) {
		return FALSE;
	}
	
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get the current module descriptor
	CObList* pList = bBrowse ? ::g_pBrowseModuleDescList : ::g_pSourceModuleDescList;
	POSITION pos = pList->FindIndex(nIndex);
	if ( !pos ) {
		return FALSE;
	}
	SYM_DESCRIPTOR dwDesc = ((CModuleDesc*)pList->GetAt(pos))->GetDesc();

	// Get the specific module name by descriptor
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pModuleObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		if ( pModuleObj->GetDesc() == dwDesc ) {
			CObList* pLineList = pModuleObj->GetLineList();
			if ( pLineList->IsEmpty() ) {
				return FALSE;
			}
			POSITION posLine = pLineList->GetHeadPosition();
			while ( posLine ) {
				CLineInfo* pObj = (CLineInfo*)pLineList->GetNext(posLine);
				if ( nLine == pObj->GetLine() ) {
					AddrStart = pObj->GetStart();
					AddrEnd = pObj->GetEnd();
					return TRUE;
				}
			}
		}
	}
		
	return FALSE;
}

BOOL SrcGetFuncRange(const CString& strName, CSourceAddr& AddrStart, CSourceAddr& AddrEnd)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get the specific function range by name
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pModuleObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		CObList* pFuncList = pModuleObj->GetFuncList();
		if ( pFuncList->IsEmpty() ) {
			return FALSE;
		}
		POSITION posFunc = pFuncList->GetHeadPosition();
		while ( posFunc ) {
			CFuncInfo* pObj = (CFuncInfo*)pFuncList->GetNext(posFunc);
			if ( pObj->GetName() == strName ) {
				AddrStart = pObj->GetStart();
				AddrEnd = pObj->GetEnd();
				return TRUE;
			}
		}
	}

	return FALSE;
}

BOOL SrcGetModule(const CSourceAddr& Addr, CString& strModulePath, SYM_DESCRIPTOR& dwModuleDesc)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get module range to compare
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		CSourceAddr Addr1 = pObj->GetStart();
		CSourceAddr Addr2 = pObj->GetEnd();
		if ( Addr >= Addr1 && Addr <= Addr2 ) {
			// Get module path
			if ( !::SrcGetModulePath(pObj->GetName(), strModulePath) ) {
//				::SrcDisplayErrorMessage(::errFile);
				return FALSE;
			}
			else {
				dwModuleDesc = pObj->GetDesc();
				return TRUE;
			}
		}
	}

	return FALSE;
}

void SrcGetModuleAddrRange(const CString& strModule, CString& strRange)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	strRange.Empty();
	if ( pModuleList->IsEmpty() ) {
		return;
	}
	
	// Get module range to compare
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		if ( strModule == pObj->GetName() ) {
			CString strStart, strEnd;
			if ( ::SrcAddrToText(pObj->GetStart(), strStart) && ::SrcAddrToText(pObj->GetEnd(), strEnd) ) {
				strRange = strStart + ::szLine + strEnd;
				return;
			}
		}
	}
}

BOOL SrcIsInSource(const CSourceAddr& Addr)
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get module range to compare
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		CSourceAddr Addr1 = pObj->GetStart();
		CSourceAddr Addr2 = pObj->GetEnd();
		if ( Addr >= Addr1 && Addr <= Addr2 ) {
			return TRUE;
		}
	}

	return FALSE;
}

BOOL SrcGetLoadInfo(int& nRatio, CString& strModuleName, CString& strModule, CString& strSymbol, CString& strType, CString& strFunction, CString& strByte, CString& strLine, CString& strPC)
{
	// Get current Loader status
    char* pszName = new char[MAX_MODULE_NAME_LEN+1];
    U16 wModule;
    U32 dwSymbol, dwType, dwFunction, dwLine, dwByte;
    if ( 0 != ::SymSrcGetLdrStats(pszName, &dwSymbol, &wModule, &dwType, &dwFunction, &dwLine, &dwByte, &nRatio) ) {
    	delete []pszName;
    	return FALSE;
    }
    strModuleName = pszName;
    delete []pszName;
    
    // Convert to string
    strModule.Format(::szFormatDWord, wModule);
    strSymbol.Format(::szFormatDWord, dwSymbol);
    strType.Format(::szFormatDWord, dwType);
    strFunction.Format(::szFormatDWord, dwFunction);
    strByte.Format(::szFormatDWord, dwByte);
    strLine.Format(::szFormatDWord, dwLine);

	// Get initial PC
	CSourceAddr Addr;
	::SrcGetInitPC(Addr);
	
    ::SrcAddrToText(Addr, strPC);
    
    return TRUE;
}

BOOL SrcGetAllModuleInfo()
{
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Free module info list
	if ( pModuleList ) {
		POSITION posMod = pModuleList->GetHeadPosition();
		while ( posMod ) {
			CModuleInfo* pModObj = (CModuleInfo*)pModuleList->GetNext(posMod);
			delete pModObj;
		}
		pModuleList->RemoveAll();
	}

	// Not loaded symbol
	if ( !::SrcIsLoadedSymbol() ) {
		return FALSE;
	}

	// Get total module number
	U16 uModuleNum;
	if ( 0 != ::SymSrcGetModuleNum(uModuleNum) ) {
		return FALSE;
	}

	// Alloc module descriptor list
	SYM_DESCRIPTOR* pDescList = new SYM_DESCRIPTOR[uModuleNum+1];
	if ( 0 != ::SymGetAllModules(pDescList, uModuleNum, &uModuleNum) || 0 == uModuleNum ) {
		delete []pDescList;
		return FALSE;
	}
		
    // Get all of the module name & range
    for ( unsigned int i(0); i < uModuleNum; i++ ) {
	    char* pszName = new char[MAX_MODULE_NAME_LEN+1];
	    *pszName = 0;
	    ADDR_RANGE_TYPE ModuleRange;
	    if ( 0 == ::SymGetModule(pDescList[i], pszName, &ModuleRange) ) {
			ASSERT(*pszName);
			ASSERT(ModuleRange.segType == ::SEG_CODE);
	    	if ( ModuleRange.startAddr <= ModuleRange.endAddr ) {
	    		// Get bank number
	    		int nBank1, nBank2;
				::SymConvertToBank(ModuleRange.startAddr, nBank1);
				::SymConvertToBank(ModuleRange.endAddr, nBank2);
				ASSERT(nBank1 == nBank2);
				ASSERT(nBank1 >= 0 && nBank1 <= 3);	// Different from ABI definition
	    		CSourceAddr Addr1(ModuleRange.startAddr, nBank1+1);
	    		CSourceAddr Addr2(ModuleRange.endAddr, nBank2+1);
	    		pModuleList->AddTail(new CModuleInfo(pDescList[i], pszName, Addr1, Addr2));
	    	}
	    }
	    delete []pszName;
	}
	delete []pDescList;

	// Get all of function descriptor, name & range of each module
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		CObList* pFuncList = pObj->GetFuncList();
		SYM_DESCRIPTOR dwFuncDesc;
		if ( 0 == ::SymSrcGetFirstFuncIndex(pObj->GetDesc(), dwFuncDesc) ) {
			char* pszName = new char[MAX_SYMNAME_LENGTH+1];
			do {
				SYM_DESCRIPTOR dwOldDesc = dwFuncDesc;
				*pszName = 0;
				if ( 0 == ::SymSrcGetNextFunc(dwFuncDesc, pszName, dwFuncDesc) ) {
					ASSERT(*pszName);
					FUNC_CLASS nClass;
					U32 dwStack;
	    			ADDR_RANGE_TYPE FuncRange;
					char* pszNewName = new char[MAX_SYMNAME_LENGTH+1];
					*pszNewName = 0;
					if ( 0 == ::SymGetFunc(dwOldDesc, pszNewName, &nClass, &dwStack, &FuncRange) ) {
						ASSERT(*pszNewName);
						ASSERT(0 == strcmp(pszName, pszNewName));
						ASSERT(FuncRange.segType == ::SEG_CODE);
				    	if ( FuncRange.startAddr <= FuncRange.endAddr ) {
				    		// Get bank number
	    					int nBank1, nBank2;
							::SymConvertToBank(FuncRange.startAddr, nBank1);
							::SymConvertToBank(FuncRange.endAddr, nBank2);
							ASSERT(nBank1 == nBank2);
							ASSERT(nBank1 >= 0 && nBank1 <= 3);	// Different from ABI definition
				    		CSourceAddr Addr1(FuncRange.startAddr, nBank1+1);
				    		CSourceAddr Addr2(FuncRange.endAddr, nBank2+1);
							pFuncList->AddTail(new CFuncInfo(dwOldDesc, pszName, Addr1, Addr2));
				    	}
				    }
					delete []pszNewName;
				}
				else {
					break;
				}
			} while ( dwFuncDesc );
			delete []pszName;
		}
	}

	// Get all of line info of each module
	posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		SYM_DESCRIPTOR dwModuleDesc = pObj->GetDesc();
		LINENUM_DESCRIPTOR dwLineDesc;
		if ( 0 == ::SymGetLinenumFirstIndex(dwModuleDesc, &dwLineDesc) ) {
			do {
				LINENUM_DESCRIPTOR dwOldLineDesc = dwLineDesc;
				ADDR_RANGE_TYPE LineRange;
	         	LINENUM_TYPE nLineNum;
	         	COLUMN_TYPE  nColumn;
				if ( 0 == ::SymGetLinenumByIndex(dwModuleDesc, dwLineDesc, &LineRange, &dwLineDesc, &nLineNum, &nColumn) ) {
					ASSERT(LineRange.segType == ::SEG_CODE);
			    	if ( LineRange.startAddr <= LineRange.endAddr ) {
			    		// Get bank number
    					int nBank1, nBank2;
						::SymConvertToBank(LineRange.startAddr, nBank1);
						::SymConvertToBank(LineRange.endAddr, nBank2);
						ASSERT(nBank1 == nBank2);
						ASSERT(nBank1 >= 0 && nBank1 <= 3);	// Different from ABI definition
			    		CSourceAddr Addr1(LineRange.startAddr, nBank1+1);
			    		CSourceAddr Addr2(LineRange.endAddr, nBank2+1);
						pObj->GetLineList()->AddTail(new CLineInfo(dwOldLineDesc, (int)nLineNum, Addr1, Addr2));
					}
				}
				else {
					break;
				}
			} while ( dwLineDesc );
		}
	}

	return TRUE;
}

BOOL SrcAddrToLine(const BOOL bBrowse, const CSourceAddr& Addr, int& nLine, int& nStart, int& nEnd)
{
	// Invalid index
	int nIndex = bBrowse ? ::g_nBrwModuleIndex : ::g_nSrcModuleIndex;
	if ( nIndex < 0 ) {
		return FALSE;
	}
	
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return FALSE;
	}
	
	// Get the current module descriptor
	CObList* pList = bBrowse ? ::g_pBrowseModuleDescList : ::g_pSourceModuleDescList;
	POSITION pos = pList->FindIndex(nIndex);
	if ( !pos ) {
		return FALSE;
	}
	SYM_DESCRIPTOR dwDesc = ((CModuleDesc*)pList->GetAt(pos))->GetDesc();

	// Get the specific module name by descriptor
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pModuleObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		if ( pModuleObj->GetDesc() == dwDesc ) {
			CObList* pLineList = pModuleObj->GetLineList();
			if ( pLineList->IsEmpty() ) {
				return FALSE;
			}
			POSITION posLine = pLineList->GetHeadPosition();
			while ( posLine ) {
				CLineInfo* pObj = (CLineInfo*)pLineList->GetNext(posLine);
				CSourceAddr Addr1 = pObj->GetStart();
				CSourceAddr Addr2 = pObj->GetEnd();
				if ( Addr >= Addr1 && Addr <= Addr2 ) {
					nLine = pObj->GetLine();
					nStart = -1;	// Ignore column info
					nEnd = -1;
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}

BOOL SrcIsMarkVariable(const CString& strToken, const int nLine)
{
	// Query from symbol server
	return (0 == ::SrcIsVariable(strToken, nLine));
}

BOOL SrcIsMarkFunction(const CString& strToken)
{
	// Query from symbol server
	return (0 == ::SrcIsFunction(strToken));
}

void SrcAddModuleDesc(const int nModuleSelect)
{
	// Add one node or Remove all
	if ( -1 == nModuleSelect ) {
		// Reset index
		::g_nSrcModuleIndex = -1;
		::g_nBrwModuleIndex = -1;
		
		// Reset depth
		::g_nSrcModuleDepth = 0;
		::g_nBrwModuleDepth = 0;

		// Remove all of the nodes
		POSITION pos = ::g_pSourceModuleDescList->GetHeadPosition();
		while ( pos ) {
			CModuleDesc* pObj = (CModuleDesc*)::g_pSourceModuleDescList->GetNext(pos);
			delete pObj;
		}
		::g_pSourceModuleDescList->RemoveAll();

		pos = ::g_pBrowseModuleDescList->GetHeadPosition();
		while ( pos ) {
			CModuleDesc* pObj = (CModuleDesc*)::g_pBrowseModuleDescList->GetNext(pos);
			delete pObj;
		}
		::g_pBrowseModuleDescList->RemoveAll();
	}
	else {
		// Get module list
		CObList* pModuleList = ::SrcGetModuleInfoList();
		ASSERT(pModuleList);
		ASSERT(nModuleSelect < pModuleList->GetCount());

		// Get module descriptor
		POSITION posModule = pModuleList->FindIndex(nModuleSelect);
		CModuleInfo* pObj = (CModuleInfo*)pModuleList->GetAt(posModule);
		SYM_DESCRIPTOR dwDesc = pObj->GetDesc();
		
		// Add to list
		CObList* pList = ::g_nSrcGroupEntry == ::SRC_SOURCE ? ::g_pSourceModuleDescList : ::g_pBrowseModuleDescList;
		pList->AddTail(new CModuleDesc(dwDesc));

		// Index to last module & Increase depth
		(::g_nSrcGroupEntry == ::SRC_SOURCE) ? 
			(::g_nSrcModuleIndex = ::g_nSrcModuleDepth++) : 
			(::g_nBrwModuleIndex = ::g_nBrwModuleDepth++);
	}
}

int SrcGetModuleIndex(const BOOL bBrowse)
{
	// Invalid index
	int nIndex = bBrowse ? ::g_nBrwModuleIndex : ::g_nSrcModuleIndex;
	if ( nIndex < 0 ) {
		return -1;
	}
	
	// Get module list
	CObList* pModuleList = ::SrcGetModuleInfoList();
	ASSERT(pModuleList);

	// Not any module with source level info
	if ( pModuleList->IsEmpty() ) {
		return -1;
	}

	// Get the current module descriptor
	CObList* pList = bBrowse ? ::g_pBrowseModuleDescList : ::g_pSourceModuleDescList;
	POSITION pos = pList->FindIndex(nIndex);
	if ( !pos ) {
		return -1;
	}
	SYM_DESCRIPTOR dwDesc = ((CModuleDesc*)pList->GetAt(pos))->GetDesc();

	// Get the specific module name by descriptor
	nIndex = 0;
	POSITION posModule = pModuleList->GetHeadPosition();
	while ( posModule ) {
		CModuleInfo* pModuleObj = (CModuleInfo*)pModuleList->GetNext(posModule);
		if ( pModuleObj->GetDesc() == dwDesc ) {
			return nIndex;
		}
		nIndex++;
	}

	return -1;
}

BOOL SrcGetModuleDesc(const BOOL bBrowse, SYM_DESCRIPTOR& dwModuleDesc)
{
	// Invalid index
	int nIndex = bBrowse ? ::g_nBrwModuleIndex : ::g_nSrcModuleIndex;
	if ( nIndex < 0 ) {
		return FALSE;
	}
	
	// Get the current module descriptor
	CObList* pList = bBrowse ? ::g_pBrowseModuleDescList : ::g_pSourceModuleDescList;
	POSITION pos = pList->FindIndex(nIndex);
	if ( pos ) {
		dwModuleDesc = ((CModuleDesc*)pList->GetAt(pos))->GetDesc();
		return TRUE;
	}
	else {
		return FALSE;
	}
}

const CString& SrcGetTargetPath()
{
	// Get the target downloaded file path
	return *::pSrcTargetPath;
}

BOOL SrcGetModulePath(const CString& strModuleName, CString& strModulePath)
{
	// Has a module name?
	if ( strModuleName.IsEmpty() ) {
		return FALSE;
	}
	CString strModule(strModuleName);
	strModule.MakeUpper();

	// Try the default path
	strModulePath = "";
	CString strTarget = ::SrcGetTargetPath();
	int nSlash = strTarget.ReverseFind('\\');
	if ( -1 != nSlash ) {
		strModulePath = strTarget.Mid(0, nSlash+1);

		// Appended by module name
		strModulePath += strModule;
			
		// No any extension name
		CFileStatus rStatus;
		if ( CFile::GetStatus(strModulePath, rStatus) ) {
			return TRUE;
		}
			
		// Appended by extension name
		CString strOld(strModulePath);
		CStringList* pExtList = ::SrcGetExtNameList();
		POSITION posExt = pExtList->GetHeadPosition();
		while ( posExt ) {
			CString strExt = pExtList->GetNext(posExt);
			strModulePath = strOld;
			strModulePath += strExt;

			CFileStatus rStatus;
			if ( CFile::GetStatus(strModulePath, rStatus) ) {
				return TRUE;
			}
		}
	}
		
	// Search from path list
	CStringList* pPathList = ::SrcGetPathList();
	POSITION posPath = pPathList->GetHeadPosition();
	while ( posPath ) {
		strModulePath = pPathList->GetNext(posPath);
		if ( '\\' != strModulePath[strModulePath.GetLength()-1] ) {
			strModulePath += '\\';
		}
				
		// Appended by module name
		strModulePath += strModule;
			
		// No any extension name
		CFileStatus rStatus;
		if ( CFile::GetStatus(strModulePath, rStatus) ) {
			return TRUE;
		}
			
		// Appended by extension name
		CString strOld(strModulePath);
		CStringList* pExtList = ::SrcGetExtNameList();
		POSITION posExt = pExtList->GetHeadPosition();
		while ( posExt ) {
			CString strExt = pExtList->GetNext(posExt);
			strModulePath = strOld;
			strModulePath += strExt;

			CFileStatus rStatus;
			if ( CFile::GetStatus(strModulePath, rStatus) ) {
				return TRUE;
			}
		}
	}

	return FALSE;
}

CStringList* SrcGetExtNameList()
{
	// Get Extension Name list
	return ::pSourceExtNameList;
}

CStringList* SrcGetPathList()
{
	// Get Source Path list
	return ::pSourcePathList;
}

CObList* SrcGetModuleInfoList()
{
	// Point all info about module, function & line got from Symbol server
	return ::pSourceModuleInfoList;
}

void SrcGetPCRange(DWORD& dwMinPC, DWORD& dwMaxPC)
{
	// EP196
	dwMinPC = 0x0000;
	dwMaxPC = 0xFFFF;

	// EP251
//	dwMinPC = 0xFE0000;
//	dwMaxPC = 0xFFFFFF;
}

int SrcGetMaxByte()
{
	// EP196
	return 6;

	// EP251
//	return 7;
}

int SrcGetAddrWidth()
{
	// EP196: p0:0000
	return 7;

	// EP251: FF0000
//	return 6;
}

