/**********************************************************************
UML StateWizard provides its software under the LGPL License and
zlib/libpng License.
Email us at info@intelliwizard.com for any information, suggestions and
feature requestions.
Home Page: http://www.intelliwizard.com
*************************************************************************/
// StateTreeStateTagDb.cpp : Implementation of CStateTreeCtrl
#include "stdafx.h"
#include "StateTreeCtrl.h"
/*
#include "AddAppDlg.h"
#include "AddEventDlg.h"
#include "CreateEventIdFileDlg.h"
#include "StateChartDlg.h"
#include "EventChange.h"
#include ".\statetreectrl.h"
#pragma comment(lib, "comctl32.lib")
*/
// CStateTreeCtrl
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//////////////////////////////////////////////////////////////////////////
// Create tag database operations
//
//
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Create tag database
// INPUT:
//
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateTreeCtrl::CreateTagDB()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
//Clear list to store the file path of event id list
m_EventIdPathList.RemoveAll();
TRACE(_T("CreateTagDB........\n"));
// Get project list
CStringArray strPrjNameList;
strPrjNameList.RemoveAll();
long lPrjCount;
Fire_GetProjectList();
data.Convert2StringArray(strPrjNameList, data.prjNameList);
lPrjCount = (long)strPrjNameList.GetSize();
if (lPrjCount == 0)
return TRUE;
m_tagDBIndex.RemoveAll();
m_appSrcHdrFiles.RemoveAll();
// Create tag database in order of project in project list respectively
for (int nPrjSeqNum = 0; nPrjSeqNum < lPrjCount; nPrjSeqNum++)
{
// Sequence in m_appSrcHdrFiles should be consistent with sequence in m_tagDBIndex
// hence, project name would only be stored in tag database rather in appSrcHdrFile
// structure
int nAppFileNum;
nAppFileNum = (int)m_appSrcHdrFiles.GetSize();
// Get handler of current project item in state tree and make this one selected
CString strPrjName;
strPrjName = strPrjNameList[nPrjSeqNum];
/* Commented by Jerry.D . Project name is not the ful. file name.
strPrjName = strPrjName.Left(strPrjName.GetLength()-SUFFIXLEN);
strPrjName.Replace('/', '\\');
int idx = strPrjName.ReverseFind('\\');
if(-1 != idx)
strPrjName = strPrjName.Right(strPrjName.GetLength()-idx-1);
*/
TRACE(_T("strPrjName=%s\n"), strPrjName);
HTREEITEM hWorkSpace = tree.GetRootItem();
HTREEITEM hCurrentPrj = tree.GetChildItem(hWorkSpace);
ASSERT(NULL != hCurrentPrj);
while (true)
{
if (hCurrentPrj == NULL)
break;
CString sItemName = tree.GetItemText(hCurrentPrj);
sItemName.Replace(" application(s)", NULL);
sItemName.TrimLeft();
sItemName.TrimRight();
if (sItemName.CompareNoCase(strPrjName) == 0)
{
tree.SelectItem(hCurrentPrj); //found current project handler
break;
}
hCurrentPrj = tree.GetNextSiblingItem(hCurrentPrj);
}
// Get selected project file list
CStringArray PrjFileList;
PrjFileList.RemoveAll();
// BSTR bstr = strPrjNameList[nPrjSeqNum].AllocSysString();
BSTR bstr = strPrjName.AllocSysString();
Fire_GetProjectFileList(bstr);
::SysFreeString(bstr);
data.Convert2StringArray(PrjFileList, data.prjFileList);
// Create a project index unit
TAG_DB_INDEX_T* pTagDBIndex = (TAG_DB_INDEX_T*)new(TAG_DB_INDEX_T);
ASSERT(NULL != pTagDBIndex);
pTagDBIndex->sPrjName = (char*)new char[strPrjName.GetLength()+1];
ASSERT(NULL != pTagDBIndex->sPrjName);
memcpy(pTagDBIndex->sPrjName, (LPCTSTR)strPrjName, strPrjName.GetLength()+1);
// Get last write time
HANDLE hFile=CreateFile(strPrjNameList[nPrjSeqNum],
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_SEQUENTIAL_SCAN,
0);
SYSTEMTIME LastWriteSysTime = {0,0,0,0,0,0,0,0};
if (hFile)
{
BY_HANDLE_FILE_INFORMATION FileInfo;
GetFileInformationByHandle( hFile, &FileInfo );
FILETIME LastWriteLocalTime = FileInfo.ftLastWriteTime;
FileTimeToLocalFileTime( &(FileInfo.ftLastWriteTime), &LastWriteLocalTime );
FileTimeToSystemTime( &LastWriteLocalTime, &LastWriteSysTime );
pTagDBIndex->LastWriteTime = LastWriteSysTime;
CloseHandle( hFile );
}
else
pTagDBIndex->LastWriteTime = LastWriteSysTime;
pTagDBIndex->pDBFile = NULL;
m_tagDBIndex.Add(pTagDBIndex);
// Traverse each file in project and create tag database
TAG_DB_FILE_INFO_T* pDBFileItem;
//!! LPCTSTR sOrignalStatus = GetStatusPaneText(); //************************************************//
for(int i = 0; i < PrjFileList.GetSize(); i++)
{
CString sFilePath = PrjFileList[i];
TRACE(_T("sFilePath=%s\n"), sFilePath);
// Create a file index unit
pDBFileItem = (TAG_DB_FILE_INFO_T*)new(TAG_DB_FILE_INFO_T);
ASSERT(NULL != pDBFileItem);
pDBFileItem->sFilePath = (char*)new char[sFilePath.GetLength()+1];
memcpy(pDBFileItem->sFilePath, (LPCTSTR)sFilePath, sFilePath.GetLength()+1);
ASSERT(NULL != pDBFileItem);
pDBFileItem->pFuncList = NULL;
pDBFileItem->pNextFile = NULL;
pDBFileItem->pNextFile = ((TAG_DB_INDEX_T*)m_tagDBIndex[nPrjSeqNum])->pDBFile;
((TAG_DB_INDEX_T*)m_tagDBIndex[nPrjSeqNum])->pDBFile = pDBFileItem;
// Show the file name creating tag db.
//!! SetStatusPaneText(0, sFilePath); //************************************************//
CStdioFile OpenedFile;
if (OpenedFile.Open(sFilePath, CFile::modeRead | CFile::typeText ) == 0)
{
// File exists in dsp file but does not exist in disk
//DSUtils(m_pApp).PrintToOutputWindow(_T((CString)sFilePath+" error: unexpected failure to open this file"));//************************************************//
// _bstr_t bError1("Failure in create tag db: open a file");
// Fire_OutPutStringToPane(bError1.GetBSTR());
CString s = sFilePath+" error: unexpected failure to open this file. This file may not exist.";
_bstr_t bError2(s.GetBuffer());
Fire_OutPutStringToPane(bError2.GetBSTR());
s.ReleaseBuffer();
delete(pDBFileItem->sFilePath);
pDBFileItem->sFilePath = NULL;
((TAG_DB_INDEX_T*)m_tagDBIndex[nPrjSeqNum])->pDBFile = (TAG_DB_FILE_INFO_T*)pDBFileItem->pNextFile;
pDBFileItem->pNextFile = NULL;
delete(pDBFileItem);
continue;
}
UCHAR nCommentFlag = NO_COMMENTS_STATE; // flag used in marking state status in parsing code
UCHAR nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE; // flag used in marking state status in creating tag db
UCHAR nReverseStateTreeFlag = TREE_GENERATION_BEGIN_STATE; // flag used in marking process status in generating state tree
CString sCurrentLine = ""; // current line
CString sPrefixLine = ""; // record previous useful information for parsing function prototype
CString sClassHead = "";
CString sContexJoint = ""; // record '\' joint connections part
CStringList ClassNameList;
ClassNameList.RemoveAll();
UINT nClassBraceNum[MAX_EMBEDDED_CLASS_DEPTH];
UINT nFuncPos = 0; // record the { postion in function implementation
UINT nFuncBraceNum = 0; // record the number of { and } in function implementation
int nErrorPos;
for (int j = 0; j < MAX_EMBEDDED_CLASS_DEPTH; j++)
nClassBraceNum[j] = 0;
CStringArray DefaultStateNameList; //record all default states in state tree
std::vector<HTREEITEM> TreeItemList; //record all tree item needed to build the state tree
DefaultStateNameList.RemoveAll();
TreeItemList.clear();
while (true)
{
// Read a line from the file.
if (!OpenedFile.ReadString(sCurrentLine))
break;
// Build state tree
if ((nErrorPos = GenerateStateTree(FALSE, NULL, sCurrentLine, nPrjSeqNum, nReverseStateTreeFlag, TreeItemList, DefaultStateNameList, OpenedFile)) <= 0)
{
// DSUtils(m_pApp).PrintToOutputWindow("Fail in building a state tree\n");//************************************************//
_bstr_t bError1("Fail in building a state tree");
Fire_OutPutStringToPane(bError1.GetBSTR());
break;
}
// Filter comments part from current line of text
BSTR bstr = sCurrentLine.AllocSysString();
//Fire_ParseCommentState(bstr, nCommentFlag, NULL, &nFuncPos);
CComVariant CountResultArray;
CountResultArray.puintVal=NULL;
CComVariant pFuncPos;
pFuncPos.puintVal=&nFuncPos;
Fire_ParseCommentState(bstr, nCommentFlag, CountResultArray,pFuncPos);
nFuncPos=*(data.pFuncPosLine);
sCurrentLine = (wchar_t*)data.sCleanLine;
nCommentFlag = (UCHAR)data.CommentState;
::SysFreeString(bstr);
if (data.isParseCommentStateOk == TRUE)
{
// Whether mix code and comment.
sContexJoint += sCurrentLine;
continue;
}
// '\' joint symbol
if (!sContexJoint.IsEmpty())
{
CString sMergedLine;
sMergedLine = sContexJoint;
sMergedLine += sCurrentLine;
sCurrentLine = sMergedLine;
sContexJoint = "";
}
sCurrentLine.TrimLeft();
sCurrentLine.TrimRight();
if (!sCurrentLine.IsEmpty())// case 1: comments line; case 2: blank line
{
ParseToTagDB(sCurrentLine,sClassHead, &nTagDBFlag,&nFuncBraceNum,sPrefixLine,nFuncPos,&(pDBFileItem->pFuncList),ClassNameList, nClassBraceNum);
}
}
if (nReverseStateTreeFlag == TREE_GENERATION_BEGIN_STATE)
{
// Non application files
HTREEITEM hNonEventSrcFile = tree.GetChildItem(hCurrentPrj);
ASSERT(NULL != hNonEventSrcFile);
while (true)
{
if (((tree.GetItemData(hNonEventSrcFile)) & STATE_TREE_OTHER_SOURCE_MASK) != 0)
break;
hNonEventSrcFile = tree.GetNextSiblingItem(hNonEventSrcFile);
}
AddNonHdlerSrcToStateTree(FALSE, pDBFileItem, hNonEventSrcFile);
// Sort tree node
TV_SORTCB SortCB;
SortCB.hParent = hNonEventSrcFile;
SortCB.lpfnCompare = CompareFunc;
SortCB.lParam = 0;
tree.SortChildrenCB(&SortCB);
SortCB.hParent = hCurrentPrj;
SortCB.lpfnCompare = CompareFunc;
SortCB.lParam = 0;
tree.SortChildrenCB(&SortCB);
}
if (nReverseStateTreeFlag == TREE_GENERATION_END_STATE)
{
// Non event handlers in application files
HTREEITEM hApp;
hApp = m_NewApp;
// if (TreeItemList.size() != 0)
// {
// In normal case, TreeItemList will not decrease to 0
// but such condition is in case that exception happens
// in parsing file.(Like: Build tree flag also exists in
// other source file which they are not meant to be tree
// flag ,instead, they are used by users by mistaken)
// hApp = *(TreeItemList.begin());
// }
AddNonHdlerSrcToStateTree(FALSE, pDBFileItem, hApp);
// Sort tree node
TV_SORTCB SortCB;
SortCB.hParent = hApp;
SortCB.lpfnCompare = CompareFunc;
SortCB.lParam = 0;
tree.SortChildrenCB(&SortCB);
SortCB.hParent = hCurrentPrj;
SortCB.lpfnCompare = CompareFunc;
SortCB.lParam = 0;
tree.SortChildrenCB(&SortCB);
tree.Expand(hCurrentPrj, TVE_EXPAND);
}
if (nReverseStateTreeFlag == TREE_GENERATION_STATE_TREE_DEFINE
|| nReverseStateTreeFlag == TREE_GENERATION_STATE_DECLARE
|| nReverseStateTreeFlag == TREE_GENERATION_EXCEPTION_STATE
|| nReverseStateTreeFlag == TREE_GENERATION_EXCEPTION_STATE_NO_TREE_HDR
|| nReverseStateTreeFlag == TREE_GENERATION_EXCEPTION_STATE_NO_STATE_DECL_HDR
|| nReverseStateTreeFlag == TREE_GENERATION_EXCEPTION_STATE_NO_APP_CLASS_DECL_HDR
|| nReverseStateTreeFlag == TREE_GENERATION_EXCEPTION_STATE_HANDLER_ERR
)
{
// damaged application file
if (TreeItemList.size() != 0)
{
std::vector<HTREEITEM>::iterator pHItem = TreeItemList.begin();
HTREEITEM hApp = (*pHItem);
tree.DeleteItem(hApp);
}
if (nReverseStateTreeFlag != TREE_GENERATION_EXCEPTION_STATE_HANDLER_ERR)
{
CString sWarningMsg;
if (nErrorPos < 0)
nErrorPos *= (-1);
else
nErrorPos = nFuncPos+1;
sWarningMsg.Format("%s(Line %d): error: illegal syntax",OpenedFile.GetFileName(), nErrorPos);
//!! DSUtils(m_pApp).PrintToOutputWindow(sWarningMsg);
//************************************************//
_bstr_t bError(sWarningMsg.GetBuffer());
Fire_OutPutStringToPane(bError.GetBSTR());
sWarningMsg.ReleaseBuffer();
}
}
DefaultStateNameList.RemoveAll();
TreeItemList.clear();
OpenedFile.Close();
}
// Reset the status bar to the original text.
//!! SetStatusPaneText(0,sOrignalStatus); //************************************************//
if (nAppFileNum == m_appSrcHdrFiles.GetSize())
{
m_appSrcHdrFiles.Add(NULL); // meet a non application project
}
}
GetEventIdListFilePath(ST_EVENT_HDR_FILE_UPDATE);
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Clear tag database
// INPUT:
//
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE:
//
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateTreeCtrl::ClearTagDB()
{
// Clear tag database memory
int i=0;
for (i = 0; i < m_tagDBIndex.GetSize(); i++)
{
TAG_DB_INDEX_T* pDBIndexItem = (TAG_DB_INDEX_T*)m_tagDBIndex[i];
TAG_DB_FILE_INFO_T* pDBFileItem = pDBIndexItem->pDBFile;
while (true)
{
if (NULL == pDBFileItem)
break;
TAG_DB_FUNC_INFO_T* pDBFuncItem = pDBFileItem->pFuncList;
TAG_DB_FILE_INFO_T* pDelFileItem = pDBFileItem;
pDBFileItem = (TAG_DB_FILE_INFO_T*)pDBFileItem->pNextFile;
while(true)
{
if (NULL == pDBFuncItem)
break;
TAG_DB_FUNC_INFO_T* pDelItem = pDBFuncItem;
pDBFuncItem = (TAG_DB_FUNC_INFO_T*)pDBFuncItem->pNextFunction;
delete(pDelItem->key);
delete(pDelItem->paramNameList);
delete(pDelItem);
}
delete(pDelFileItem->sFilePath);
delete(pDelFileItem);
}
delete(pDBIndexItem->sPrjName);
delete(pDBIndexItem);
}
m_tagDBIndex.RemoveAll();
// Clear application file information's memory
for (i = 0; i < m_appSrcHdrFiles.GetSize(); i++)
{
APP_FILE_INFO_T* pAppFileItem = (APP_FILE_INFO_T*)m_appSrcHdrFiles[i];
while (true)
{
if (NULL == pAppFileItem)
break;
APP_FILE_INFO_T* pDelAppItem = pAppFileItem;
pAppFileItem = (APP_FILE_INFO_T*)pAppFileItem->pNextApp;
delete(pDelAppItem->sAppName);
if (pDelAppItem->sHdrFilePath != NULL)
delete(pDelAppItem->sHdrFilePath);
if (pDelAppItem->sSrcFilePath != NULL)
delete(pDelAppItem->sSrcFilePath);
delete(pDelAppItem);
}
}
m_appSrcHdrFiles.RemoveAll();
return TRUE;
}
/*******************************************************************************************
** DESCRIPTION: Traverse the project files and update all items related to the saved file
** INPUT: 1)sPrjName: Project name which contains clicking function
** 2)sFilePath: File full path name.
** OUTPUT: 1) TRUE: Update Success 2)FALSE: Update Failed 3) -1: No other files can be updated
** NOTE: When sFilePath is null, it means that we need to choose a random unsaved file to
** save. This case happens when a new unsaved function need to be located.
** sPrjName should not be empty.
**
*******************************************************************************************/
int CStateTreeCtrl::ExecuteUpdate(LPCTSTR sPrjName, CString sFilePath)
{
// Get tag database corresponding item
ASSERT(sPrjName!=NULL && sPrjName[0]!=0); // For debug edition.
if (sPrjName==NULL || sPrjName[0]==0) return FALSE; // For release edition.
TAG_DB_INDEX_T* pDBIndexItem=NULL;
TAG_DB_FILE_INFO_T* pDBFileItem=NULL;
for (int nPrjSeqNum = 0; nPrjSeqNum < m_tagDBIndex.GetSize(); nPrjSeqNum++)
{
pDBIndexItem = (TAG_DB_INDEX_T*)m_tagDBIndex[nPrjSeqNum];
if (stricmp(sPrjName, pDBIndexItem->sPrjName) == 0)
break;
}
if (pDBIndexItem) //Found
pDBFileItem = pDBIndexItem->pDBFile;
else
return -1; //Why???
// Deal with null file path. It means the indicated function is a new one
if (sFilePath == "")
{
// Get a random unsaved file
BOOL bSaved = FALSE;
while (true)
{
if (pDBFileItem == NULL)
return -1;
CString sPath = pDBFileItem->sFilePath;
BSTR bstr = sPath.AllocSysString();
Fire_TestOpenedDocIsModified(bstr, VARIANT_TRUE);
::SysFreeString(bstr);
if (data.isOpenedDocModified == TRUE)
break;
pDBFileItem = (TAG_DB_FILE_INFO_T*)pDBFileItem->pNextFile;
}
sFilePath = pDBFileItem->sFilePath;
//. sFilePath.MakeLower();
}
CString sFileName;
sFileName = sFilePath;
//. sFileName.MakeLower();
sFileName.Replace('/', '\\');
int idx = sFileName.ReverseFind('\\');
if(-1 != idx)
sFileName = sFileName.Right(sFileName.GetLength()-idx-1);
// Update modified parts in state tree
HTREEITEM hWorkSpace = tree.GetRootItem();
HTREEITEM hCurrentPrj = tree.GetChildItem(hWorkSpace);
HTREEITEM hItem;
// Get handler of corresponding project tree item
while (true)
{
if (hCurrentPrj == NULL)
break;
CString sItemName = tree.GetItemText(hCurrentPrj);
sItemName.Replace(" application(s)", NULL);
sItemName.TrimLeft();
sItemName.TrimRight();
if (!sItemName.CompareNoCase(sPrjName))
{
tree.SelectItem(hCurrentPrj);
break;
}
hCurrentPrj = tree.GetNextSiblingItem(hCurrentPrj);
}
hItem = tree.GetChildItem(hCurrentPrj);
BOOL bFound = FALSE;
BOOL bResult = TRUE; // record whether this time update is successful
// Traverse each child tree item of indicated project item and update it if needed
while (true)
{
if (hItem == NULL)
{
///////// no one is added
if (bFound == FALSE)
{
BOOL bHandled = TRUE;
OnRefresh(0,0,0,bHandled);
}
return bResult;
}
DWORD lMask = tree.GetItemData(hItem);
if (lMask & STATE_TREE_APPLICATION_MASK)
{
HTREEITEM hSaved;
hSaved = tree.GetChildItem(hItem);
while (true)
{
if (NULL == hSaved)
break;
if (tree.GetItemData(hSaved) & (STATE_TREE_APPLICATION_SOURCE_FILE_MASK|STATE_TREE_APPLICATION_HEADER_FILE_MASK))
{
CString sFileNameToSearch = sFileName;
CString sFileNameAtTree = tree.GetItemFileName(hSaved);
if ((sFileNameToSearch).CompareNoCase(sFileNameAtTree) == 0)
{
bFound = TRUE;
BOOL bReturn;
bReturn = UpdateStateTree(hItem, hCurrentPrj, sFilePath);
/* Duplicate with the actions in function UpdateStateTree();
CString sTempFilePath = sFilePath;
sTempFilePath.MakeLower();
if (sTempFilePath.CompareNoCase(m_EventIdFilePath) == 0)
{
m_EventIdList.RemoveAll();
CComVariant EventIdList_var;
EventIdList_var.puintVal = reinterpret_cast<UINT*>(&m_EventIdList);
Fire_GetEventIdList(CComBSTR(m_EventIdFilePath), EventIdList_var);
data.Convert2StringArray(m_EventIdList, data.eventIdList);
}
*/
if (bReturn == FALSE)
bResult = bReturn;
break;
}
}
hSaved = tree.GetNextSiblingItem(hSaved);
}
} // if STATE_TREE_APPLICATION_MASK
if (lMask & STATE_TREE_OTHER_SOURCE_MASK)
{
HTREEITEM hSaved;
hSaved = tree.GetChildItem(hItem);
while (true)
{
if (NULL == hSaved)
break;
TRACE("tree.GetItemText(hSaved)=%s\n", tree.GetItemText(hSaved));
CString sTempFileName = sFileName;
//sTempFileName.MakeLower();
if (0==sTempFileName.CompareNoCase(tree.GetItemText(hSaved)))
{
bFound = TRUE;
BOOL bReturn;
bReturn = UpdateStateTree(hSaved, hCurrentPrj, sFilePath);
/* Duplicate with the actions in function UpdateStateTree();
CString sTempFilePath = sFilePath;
sTempFilePath.MakeLower();
if (sFilePath.CompareNoCase(m_EventIdFilePath) == 0)
{
m_EventIdList.RemoveAll();
CComVariant EventIdList_var;
EventIdList_var.puintVal = reinterpret_cast<UINT*>(&m_EventIdList);
Fire_GetEventIdList(CComBSTR(m_EventIdFilePath), EventIdList_var);
data.Convert2StringArray(m_EventIdList, data.eventIdList);
}
*/
if (bReturn == FALSE)
bResult = bReturn;
return bResult;
}
hSaved = tree.GetNextSiblingItem(hSaved);
}
} // if STATE_TREE_OTHER_SOURCE_MASK
hItem = tree.GetNextSiblingItem(hItem);
} // while true
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Parse code to get function implementations
// INPUT: 1) sText: Code context with comments excluded to be parsed
// 2) nTagDBFlag: Parser stage when processing parsing
// 3) sFuncHead: Record useful information from previous parsed lines
// 4) nFuncPos: Line number of current parsed code's position
// 5) nDocSeqNum: Sequence num in m_tagDBIndex
// 6) ClassNameList: Record parsed class name
// 7) nClassBraceNum: Record braces which indicate validity of current class's field
//
// OUTPUT: 1) TRUE: 2)FALSE
// NOTE: Parse "class" or "struct" name first if thet exist, then parse every function name in
// code. When each function has been parsed correctly, it will call CreateTagDBIndex to
// record relative information into tag database.
// The grammar for function implementation in a class is
// Syntax
// class-specifier :
// class-head { member-listopt }
//
// class-head :
// class-key imodelopt identifieropt base-specopt
// class-key imodelopt class-nameopt base-specopt
//
// class-key :
// class
// struct
// union
//
// imodel :
// __declspec
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateTreeCtrl::ParseToTagDB(CString sText, CString &sClassHead, UCHAR *nTagDBFlag, UINT *nFuncBraceNum, CString &sFuncHead, UINT nFuncPos, TAG_DB_FUNC_INFO_T** pDBFuncItem, CStringList &ClassNameList, UINT *nClassBraceNum)
{
sText.TrimLeft();
sText.TrimRight();
CString sCurrentRecord = ""; // detract current line's useful information
BOOL bJmpFromFuncParse = FALSE;// mark whether re-jumping to the loop is caused by function parsing's finish
while(true)
{
// Case: initialized status or re-jump from function's parsing
if (*nTagDBFlag == TAG_DB_CLASS_BEGIN_STATE)
{
sText.TrimLeft();
sText.TrimRight();
// Skip predefined macros
if (sText.Find('#') == 0)
break;
// Skip empty line
if (sText.IsEmpty())
break;
// Supported class keyword
int nClassIdx = sText.Find("class");
int nStructIdx = sText.Find("struct");
int nUnionIdx = sText.Find("union");
// Assume that class keyword must occur ahead of line
if (nClassIdx == 0 || nStructIdx == 0 || nUnionIdx == 0)
{
// "class", "struct", "union" class-keys' length
int nKeywordLen = (nStructIdx == 0)? 6: 5;
// Detract sequent text from class-keys
CString sTmpText = sText.Right(sText.GetLength()-nKeywordLen);
// Confirm class-keys' syntax to prevent from mistaking normal identifies which
// contain class-keys as a part for real class keys.
if (sTmpText.IsEmpty() || sTmpText.GetAt(0) == ' ' || sTmpText.GetAt(0) == '\t' || sTmpText.GetAt(0) == '{')
{
*nTagDBFlag = TAG_CLASS_KEYWORD_FOUND_STATE;
sTmpText.TrimLeft();
sText = sTmpText;
if (sText.IsEmpty())
break;
else
continue;
}
}
// Convert current state to TAG_CLASS_LEFT_BRACE_FOUND_STATE for detracting left braces
// which belongs to class-key's fields if class exists, otherwise, state will jump to
// TAG_DB_FUNCTION_BEGIN_STATE for parsing function implementation.
if (ClassNameList.GetCount() == 0)
{
*nTagDBFlag = TAG_DB_FUNCTION_BEGIN_STATE;
}
else
{
// Count left braces of every existed class in valid field
*nTagDBFlag = TAG_CLASS_LEFT_BRACE_FOUND_STATE;
}
continue;
}
// Case: class keyword has found and need get class name
if (*nTagDBFlag == TAG_CLASS_KEYWORD_FOUND_STATE)
{
int nSemicolonIdx = sText.Find(';');
int nLeftBraceIdx = sText.Find('{');
// No '{' found or '{' occurs before ';''s occurrence, then confirm current
// class-keys are not definitions.
if ((nSemicolonIdx != -1 && nLeftBraceIdx != -1 && nSemicolonIdx < nLeftBraceIdx) ||
nSemicolonIdx != -1 && nLeftBraceIdx == -1)
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sText = sText.Right(sText.GetLength()-nSemicolonIdx-1);
sText.TrimLeft();
if (!sText.IsEmpty())
continue;
break;
}
else
{
// Convert to begin seeking class name
*nTagDBFlag = TAG_CLASS_NAME_BEGIN_STATE;
// '{' occurs which means class name must exist among current text
if (nLeftBraceIdx != -1)
{
*nTagDBFlag = TAG_CLASS_NAME_END_STATE;
sClassHead += " ";
sClassHead += sText.Left(nLeftBraceIdx);
sText = sText.Right(sText.GetLength()-nLeftBraceIdx);
continue;
}
// Temporarily store pseudo class name
sClassHead += sText;
break;
}
}
// Case: begin seeking class name
if (*nTagDBFlag == TAG_CLASS_NAME_BEGIN_STATE)
{
// Class name confirmed until we found '{'
int nLeftBraceIdx = sText.Find('{');
if (nLeftBraceIdx == -1)
{
sClassHead += " ";
sClassHead += sText;
break;
}
else
{
// Once '{' occurs then directly jump to next state
*nTagDBFlag = TAG_CLASS_NAME_END_STATE;
sClassHead += " ";
sClassHead += sText.Left(nLeftBraceIdx);
sText = sText.Right(sText.GetLength()-nLeftBraceIdx);
continue;
}
}
// Case: parse class head to get the class name
if (*nTagDBFlag == TAG_CLASS_NAME_END_STATE)
{
sClassHead.Replace('\t', ' ');
sClassHead.TrimLeft();
sClassHead.TrimRight();
// "class", "union", "struct" is anonymous structure
if (sClassHead.IsEmpty())
{
*nTagDBFlag = TAG_CLASS_NAME_FOUND_STATE;
ClassNameList.AddTail("");
sClassHead = "";
continue;
}
CString sTmpClassHead = sClassHead;
// Deal with inheritance
int nColonIdx = sClassHead.Find(':');
if (nColonIdx != -1)
{
sTmpClassHead = sTmpClassHead.Left(nColonIdx);
sTmpClassHead.TrimRight();
}
// Assume class limit word only can occur once at most ahead of class name
int nSpaceIdx = sTmpClassHead.Find(' ');
if (nSpaceIdx != -1)
{
sTmpClassHead = sTmpClassHead.Right(sTmpClassHead.GetLength()-nSpaceIdx-1);
sTmpClassHead.TrimLeft();
nSpaceIdx = sTmpClassHead.Find(' ');
// Assume that a class head without inheritance statement and class limited word
// which still have more than one word must not be a class declaration. It may be
// a function that returns a class structure
if (nSpaceIdx != -1)
{
*nTagDBFlag = TAG_DB_FUNCTION_BEGIN_STATE;
// Recover the original line
CString sMergedLine = sClassHead;
sMergedLine += " ";
sMergedLine += sText;
sText = sMergedLine;
sClassHead =""; // clear class head for next parsing
continue;
}
}
// Confirm a class structure
*nTagDBFlag = TAG_CLASS_NAME_FOUND_STATE;
ClassNameList.AddTail(sTmpClassHead);
sClassHead = ""; // after retrieving class name, then clear class head
continue;
}
// Case: class name is found to confirm whether a definition or a declaration
if (*nTagDBFlag == TAG_CLASS_NAME_FOUND_STATE)
{
int nLeftBraceIdx = sText.Find('{');
int nSemicolonIdx = sText.Find(';');
// ';' occurs first, it is a class declaration
if ((nSemicolonIdx != -1 && nLeftBraceIdx != -1 && nSemicolonIdx < nLeftBraceIdx) ||
nSemicolonIdx != -1 && nLeftBraceIdx == -1)
{
ClassNameList.RemoveTail();
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sText = sText.Right(sText.GetLength()-nSemicolonIdx-1);
sText.TrimLeft();
if (!sText.IsEmpty())
continue;
break;
}
// '{' becomes dominant. It is a class definition
if (nLeftBraceIdx != -1)
{
*nTagDBFlag = TAG_CLASS_LEFT_BRACE_FOUND_STATE;
// Embedded child class. Initialize state
if (bJmpFromFuncParse == TRUE)
{
bJmpFromFuncParse = FALSE;
sFuncHead = "";
sCurrentRecord = "";
}
nClassBraceNum[ClassNameList.GetCount()-1]++; // increase braces sum in corresponding class field
// Retrieve remains to continue parsing
sText = sText.Right(sText.GetLength()-nLeftBraceIdx-1);
sText.TrimLeft();
sText.TrimRight();
if (!sText.IsEmpty())
continue;
}
break; // '{' also doesn't occur, then left it to next parsing
}
// Case: count adjacent braces of the corresponding class. When meet '{', it will increase
// sum of the braces by one. When meet '}', it will decrease by one. If the sum equals 0, then
// we can confirm a class definition is over.
if (*nTagDBFlag == TAG_CLASS_LEFT_BRACE_FOUND_STATE )
{
int rightBracesPos = sText.Find('}');
int nLeftBraceIdx = sText.Find('{');
if (nLeftBraceIdx == 0) //find a '{' which belonged to class field
{
int i = (int)ClassNameList.GetCount()-1;
nClassBraceNum[i]++; // increase sum of braces
sText = sText.Right(sText.GetLength()-1);
sText.TrimLeft();
// Initialize state
if (bJmpFromFuncParse == TRUE)
{
bJmpFromFuncParse = FALSE;
sFuncHead = "";
sCurrentRecord = "";
}
continue;
}
if (rightBracesPos == 0) //find a '}' which belonged to class field
{
int i = (int)ClassNameList.GetCount()-1;
nClassBraceNum[i]--; // decrease sum of braces
sText = sText.Right(sText.GetLength()-1);
sText.TrimLeft();
if (nClassBraceNum[i] == 0) //jump out of current class field
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
ClassNameList.RemoveTail();
continue;
}
}
*nTagDBFlag = TAG_DB_FUNCTION_BEGIN_STATE;
// No necessary to parse function part again cause it is jumped out of
// function parsing state
if (bJmpFromFuncParse == TRUE)
break;
continue;
}
// Case: class name has been parsed if it exists. Then, it start to parse function part
if (*nTagDBFlag == TAG_DB_FUNCTION_BEGIN_STATE)
{
// To seek '(' as a precursor for function implementation
int lParenthesisPos = sText.Find("(");
int nSemicolonIdx = sText.Find(";");
// '(' occurs
if(lParenthesisPos != -1)
{
*nTagDBFlag = TAG_FUNCTION_LEFT_PARENTHESIS_FOUND_STATE;
////////// prefix only used when ()pram list is separated with function name
if (sFuncHead.Find("::") == -1 && sText.Find("::") != 0 && lParenthesisPos != 0)
{
sFuncHead = "";
}
// Record probable function head part
sCurrentRecord += sText.Left(lParenthesisPos+1);
// Deal with remains of parsing part
sText = sText.Right(sText.GetLength()-lParenthesisPos-1);
sText.TrimLeft();
sText.TrimRight();
if (!sText.IsEmpty())
continue;
sFuncHead += " ";
sFuncHead += sCurrentRecord;
break;
}
// hasn't found ( but found ;
else if (nSemicolonIdx != -1)
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sText.TrimLeft();
sText.TrimRight();
// Exclude ';' out of parsing text for next round
if (sText.GetAt(0) == ';')
sText = sText.Right(sText.GetLength()-1);
// Initialize accessory structure
sFuncHead = "";
sCurrentRecord = "";
// No necessary to reparse the same part
if (bJmpFromFuncParse == TRUE)
break;
bJmpFromFuncParse = TRUE;
if (!sText.IsEmpty())
continue;
break;
}
else
{
sText.TrimLeft();
// If it is not class related function, then no necessary to store last
// stored function head part
if (sText.Find("::") != 0 && sFuncHead.Find("::") == -1)
sFuncHead = "";
// Record current part to be probable function name or function's parent
// class name
sCurrentRecord += sText;
sFuncHead += " ";
sFuncHead += sCurrentRecord;
// Reparse the current part for probable embedded child class
if (ClassNameList.GetCount() != 0)
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
bJmpFromFuncParse = TRUE; // mark it is jumping out of parsing function
continue;
}
break;
}
} // end of case
// Case: '(' has got, then the aim is to get ')'
if (*nTagDBFlag == TAG_FUNCTION_LEFT_PARENTHESIS_FOUND_STATE)
{
// Find the position of ')'
int rParenthesisPos = sText.Find(')');
// ')' has found
if (rParenthesisPos != -1)
{
// Store the part ahead of ')'
*nTagDBFlag = TAG_FUNCTION_RIGHT_PARENTESIS_FOUND_STATE;
sCurrentRecord += sText.Left(rParenthesisPos+1);
sText = sText.Right(sText.GetLength() - rParenthesisPos -1);
sText.TrimLeft();
sText.TrimRight();
if (!sText.IsEmpty())
continue;
sFuncHead += " ";
sFuncHead += sCurrentRecord;
break;
}
else
{
// ')' has not been found, then store current part. Since this part
// may become part of function's parameters
sCurrentRecord += sText;
sFuncHead += " ";
sFuncHead += sCurrentRecord;
break;
}
}// end of case
// Case: ')' occurs and next step is to confirm whether it is an implementation or
// a declaration
if (*nTagDBFlag == TAG_FUNCTION_RIGHT_PARENTESIS_FOUND_STATE)
{
// Get the position of '{' or ';'
int nLeftBraceIdx = sText.Find('{');
int nSemicolonIdx = sText.Find(";");
// sub case 1: ";" occurs before "{"
if ((nSemicolonIdx != -1 && nLeftBraceIdx != -1 && nSemicolonIdx < nLeftBraceIdx) ||
nSemicolonIdx != -1 && nLeftBraceIdx == -1)
{
// Initialize state
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sFuncHead = "";
sCurrentRecord = "";
sText.TrimLeft();
sText.TrimRight();
if (sText.GetAt(0) == ';')
sText = sText.Right(sText.GetLength()-1); // exclude ';' from part
sText.TrimLeft();
// bJmpFromFuncParse = TRUE;
if (!sText.IsEmpty())
continue;
break;
}
// sub case 2: "{" occurs
if (nLeftBraceIdx != -1)
{
*nTagDBFlag = TAG_DB_FUNCTION_END_STATE;
// Get "const" word for function if it exists
CString sTmpText = sText.Left(nLeftBraceIdx);
sTmpText.TrimLeft();
sTmpText.TrimRight();
if(!sTmpText.Compare("const"))
sCurrentRecord += "const";
else if (!sTmpText.IsEmpty())
{
//need consider macro situation??????
if (ClassNameList.GetCount() == 0 &&
(sFuncHead.Find("::") == -1 || (sFuncHead.Find("::")!= -1 && sFuncHead.Find('(')!= -1&& sFuncHead.Find('(') < sFuncHead.Find("::"))) &&
(sCurrentRecord.Find("::") == -1 || (sCurrentRecord.Find("::")!= -1 && sCurrentRecord.Find('(')!= -1 && sCurrentRecord.Find('(') < sCurrentRecord.Find("::"))))
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sFuncHead = "";
sCurrentRecord ="";
continue;
}
}
(*nFuncBraceNum)++; // count the "{" num
sText = sText.Right(sText.GetLength()-nLeftBraceIdx-1);
sText.TrimLeft();
continue;
}
if (ClassNameList.GetCount() == 0 &&
(sFuncHead.Find("::") == -1 || (sFuncHead.Find("::")!= -1 && sFuncHead.Find('(')!= -1&& sFuncHead.Find('(') < sFuncHead.Find("::"))) &&
(sCurrentRecord.Find("::") == -1 || (sCurrentRecord.Find("::")!= -1 && sCurrentRecord.Find('(')!= -1 && sCurrentRecord.Find('(') < sCurrentRecord.Find("::"))))
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sFuncHead = "";
sCurrentRecord ="";
continue;
}
sText.TrimLeft();
sText.TrimRight();
// Confirm whether it is function assignment
if (sText.GetAt(0) == ':')
{
// If it is function assignment, then convert state to skip it
*nTagDBFlag = TAG_FUNCTION_COLON_ASSIGNMENT_STATE;
sFuncHead += " ";
sFuncHead += sCurrentRecord;
continue;
}
// Get "const" word if it exists
if (sText.Compare("const") == 0)
{
sCurrentRecord += "const";
sFuncHead += " ";
sFuncHead += sCurrentRecord;
break;
}
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sFuncHead = "";
sCurrentRecord ="";
continue;
}
// Case: function assignment process
if (*nTagDBFlag == TAG_FUNCTION_COLON_ASSIGNMENT_STATE)
{
CString sTmpText;
int nLeftBracePos = sText.Find('{');
// '{' has not been found
if (nLeftBracePos == -1)
{
sTmpText = sText;
while (true)
{
int keywordPos = sTmpText.Find("const");
if (keywordPos == -1)
break;
sTmpText = sTmpText.Right(sTmpText.GetLength()-keywordPos-5);
sTmpText.TrimLeft();
sTmpText.TrimRight();
if (sTmpText.IsEmpty() && keywordPos != -1)
sFuncHead += "const";
}
break;
}
else
{
*nTagDBFlag = TAG_FUNCTION_RIGHT_PARENTESIS_FOUND_STATE;
sTmpText = sText.Left(nLeftBracePos);
while (true)
{
int keywordPos = sTmpText.Find("const");
if (keywordPos == -1)
break;
sTmpText = sTmpText.Right(sTmpText.GetLength()-keywordPos-5);
sTmpText.TrimLeft();
sTmpText.TrimRight();
if (sTmpText.IsEmpty() && keywordPos != -1)
sFuncHead += "const";
}
sText = sText.Right(sText.GetLength()-nLeftBracePos);
sText.TrimLeft();
if (!sText.IsEmpty())
continue;
break;
}
}
// Case: { has found and pass through the current function implementation
if (*nTagDBFlag == TAG_DB_FUNCTION_END_STATE)
{
//for the first time in this case it will be handled at once
sCurrentRecord = sFuncHead+sCurrentRecord;
sCurrentRecord.TrimLeft();
sCurrentRecord.TrimRight();
if (!sCurrentRecord.IsEmpty())
{
//// Create DB index
CString sClassName = "";
// Get class name if it exists
POSITION pos;
pos = ClassNameList.GetHeadPosition();
for (;pos!=NULL;)
{
sClassName += ClassNameList.GetAt(pos);
sClassName += "::"; // support anonymous class name
ClassNameList.GetNext(pos);
}
CString key;
CString paramNameList;
// Convert to the stored function prototype in the form of tag database
GetTagDBKeyFromFunc(sCurrentRecord, key, paramNameList, sClassName);
// Create tag database index
CreateTagDBIndex(pDBFuncItem, nFuncPos, key, paramNameList);
sFuncHead = "";
sCurrentRecord = "";
}
CheckFuncBraces(sText, nFuncBraceNum);
//// has reached the end of function implementation
if (*nFuncBraceNum == 0)
{
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
sText.TrimLeft();
sText.TrimRight();
if (sText.GetAt(0) == ';')
sText = sText.Right(sText.GetLength()-1);
sText.TrimLeft();
sText.TrimRight();
if (!sText.IsEmpty())
continue;
}
break;
}// end of case
}// end of while
if (*nTagDBFlag == TAG_DB_FUNCTION_BEGIN_STATE)
*nTagDBFlag = TAG_DB_CLASS_BEGIN_STATE;
return TRUE;
}
///////////////////////////////////////////////////////////////////////////////////////////
// DESCRIPTION: Create index in tag database
// INPUT: 1) pDBFuncItem: pointer to the recorded function information structure
// 2) nFuncPos: line number of function implementation
// 3) sKeyName: stored function prototype in tag database
// 4) sParamNameList: stored function parameters of stored function
//
// OUTPUT: TRUE: index created successfully
// FALSE:
///////////////////////////////////////////////////////////////////////////////////////////
BOOL CStateTreeCtrl::CreateTagDBIndex(TAG_DB_FUNC_INFO_T** pDBFuncItem, UINT nFuncPos, CString sKeyName, CString sParamNameList)
{
TAG_DB_FUNC_INFO_T* pNewRecord = (TAG_DB_FUNC_INFO_T*)new(TAG_DB_FUNC_INFO_T);
ASSERT(NULL != pNewRecord);
pNewRecord->key = (char*)new char[sKeyName.GetLength()+1];
ASSERT(NULL != pNewRecord->key);
pNewRecord->paramNameList = (char*)new char[sParamNameList.GetLength()+1];
ASSERT(NULL != pNewRecord->paramNameList);
memcpy(pNewRecord->key, (LPCTSTR)sKeyName, sKeyName.GetLength()+1);
memcpy(pNewRecord->paramNameList, (LPCTSTR)sParamNameList, sParamNameList.GetLength()+1);
pNewRecord->nPosLine = nFuncPos;
pNewRecord->pNextFunction = *pDBFuncItem;
*pDBFuncItem = pNewRecord;
return TRUE;
}