/* CodeCount
Copyright(C) 2023 Zhang Wenjie
All rights reserved. */
#include "pch.h"
#include "CodeCountDrv.h"
#include "resource.h"
CCodeCountDrv::CCodeCountDrv(void)
:m_bCreate(FALSE)
{
m_Ctrl.CountStatus = CODECOUNTDRV_COUNT_NONE;
m_Ctrl.CountCtrl.pbyData = NULL;
m_Ctrl.CountCtrl.pwDataConvert = NULL;
}
CCodeCountDrv::~CCodeCountDrv(void)
{
delete m_Ctrl.CountCtrl.pbyData;
delete m_Ctrl.CountCtrl.pwDataConvert;
m_Ctrl.CountCtrl.pbyData = NULL;
m_Ctrl.CountCtrl.pwDataConvert = NULL;
}
BOOL CCodeCountDrv::Create()
{
if(m_bCreate)
{
return FALSE;
}
m_pThread = AfxBeginThread(CodeCountTask, this);
if(m_pThread == NULL)
{
return FALSE;
}
m_Ctrl.CountStatus = CODECOUNTDRV_COUNT_IDLE;
m_bCreate = TRUE;
return TRUE;
}
void CCodeCountDrv::Delete()
{
CODECOUNTDRV_MSGBASE MsgBase;
if(!m_bCreate)
{
return;
}
MsgBase.iType = CODECOUNTDRV_MSG_EXIT;
if(m_MsgQueue.SendMsg(MsgBase) != MSGQUEUE_ERR_NONE)
{
TRACE("send CODECOUNTDRV_MSG_EXIT fail\n");
return;
}
WaitForSingleObject(m_Ctrl.EndEvent, 2000);
m_Ctrl.CountStatus = CODECOUNTDRV_COUNT_NONE;
m_bCreate = FALSE;
}
void CCodeCountDrv::Start(const CString &strPath)
{
CODECOUNTDRV_MSGBASE MsgBase;
if(!m_bCreate)
{
return;
}
MsgBase.iType = CODECOUNTDRV_MSG_START;
MsgBase.Data.strPath = strPath;
if(m_MsgQueue.SendMsg(MsgBase) != MSGQUEUE_ERR_NONE)
{
TRACE("send CODECOUNTDRV_MSG_START fail\n");
}
}
void CCodeCountDrv::Stop()
{
CODECOUNTDRV_MSGBASE MsgBase;
if(!m_bCreate)
{
return;
}
MsgBase.iType = CODECOUNTDRV_MSG_STOP;
if(m_MsgQueue.SendMsg(MsgBase) != MSGQUEUE_ERR_NONE)
{
TRACE("send CODECOUNTDRV_MSG_STOP fail\n");
}
}
UINT CCodeCountDrv::CodeCountTask(LPVOID pParam)
{
int Ret = 0;
BOOL bExit = FALSE;
CODECOUNTDRV_MSGBASE MsgBase;
UNUSED_ALWAYS(pParam);
CCodeCountDrv *pThis = static_cast<CCodeCountDrv *>(pParam);
ASSERT(pThis != NULL);
for(;;)
{
Ret = pThis->m_MsgQueue.RecvMsg(&MsgBase, INFINITE);
switch(Ret)
{
case MSGQUEUE_ERR_NONE:
if(MsgBase.iType == CODECOUNTDRV_MSG_EXIT)
{
pThis->m_Ctrl.EndEvent.SetEvent();
bExit = TRUE;
break;
}
pThis->CodeCountNormal(MsgBase);
break;
default:
Sleep(CODECOUNTDRV_NORMAL_WAIT_TIME);
break;
}
if(bExit)
{
break;
}
}
return 0;
}
void CCodeCountDrv::CodeCountNormal(const CODECOUNTDRV_MSGBASE &MsgBase)
{
switch(MsgBase.iType)
{
case CODECOUNTDRV_MSG_START:
CodeCountStart(&m_Ctrl, MsgBase.Data);
break;
case CODECOUNTDRV_MSG_CONTINUE:
CodeCountContinue(&m_Ctrl);
break;
case CODECOUNTDRV_MSG_STOP:
CodeCountStop(&m_Ctrl);
break;
default:
// do nothing
break;
}
}
void CCodeCountDrv::CodeCountStart(CODECOUNTDRV_CTRL *pCtrl, const CODECOUNTDRV_MSGDATA &MsgData)
{
CODECOUNTDRV_MSGBASE MsgBase;
if(pCtrl == NULL)
{
return;
}
pCtrl->CountCtrl.iCountNum = 0;
pCtrl->CountCtrl.CountData.clear();
try
{
ListFiles(pCtrl, MsgData.strPath);
}
catch(...)
{
// do nothing
}
pCtrl->CountStatus = CODECOUNTDRV_COUNT_RUN;
MsgBase.iType = CODECOUNTDRV_MSG_CONTINUE;
if(m_MsgQueue.SendMsg(MsgBase) != MSGQUEUE_ERR_NONE)
{
TRACE("send CODECOUNTDRV_MSG_CONTINUE fail\n");
}
}
void CCodeCountDrv::ListFiles(CODECOUNTDRV_CTRL *pCtrl, const CString &strPath)
{
HANDLE hFind = INVALID_HANDLE_VALUE;
CString strFind;
CString strFile;
WIN32_FIND_DATA FindFileData;
CODECOUNTDRV_COUNT_DATA CountData;
strFind = strPath + _T("\\*.*");
hFind = ::FindFirstFile(strFind, &FindFileData);
if(hFind == INVALID_HANDLE_VALUE)
{
return;
}
while(true)
{
if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if(FindFileData.cFileName[0] != '.')
{
strFile = strPath + _T("\\");
strFile += FindFileData.cFileName;
ListFiles(pCtrl, strFile);
}
}
else
{
if(ChkFileExtend(FindFileData.cFileName))
{
CountData.strPath = strPath + _T("\\") + FindFileData.cFileName;
pCtrl->CountCtrl.CountData.push_back(CountData);
}
TRACE("file name:%s\n", FindFileData.cFileName);
//fileList.push_back(FindFileData.cFileName);
}
if(!FindNextFile(hFind, &FindFileData))
{
break;
}
}
FindClose(hFind);
}
BOOL CCodeCountDrv::ChkFileExtend(CString strFileName)
{
BOOL bRet = FALSE;
int iPos = 0;
CString strExtend;
iPos = strFileName.ReverseFind(TEXT('.'));
if(iPos != 0)
{
strExtend = strFileName.Mid(iPos + 1);
}
if(strExtend == _T("h") || strExtend == _T("hpp") ||
strExtend == _T("c") || strExtend == _T("cpp") || strExtend == _T("cxx"))
{
bRet = TRUE;
}
return bRet;
}
void CCodeCountDrv::CodeCountContinue(CODECOUNTDRV_CTRL *pCtrl)
{
int iSize = 0;
int iProcess = 0;
CODECOUNTDRV_MSGBASE MsgBase;
if(pCtrl == NULL)
{
return;
}
if(pCtrl->CountStatus != CODECOUNTDRV_COUNT_RUN)
{
return;
}
iSize = static_cast<int>(pCtrl->CountCtrl.CountData.size());
if(pCtrl->CountCtrl.iCountNum >= iSize)
{
AfxGetMainWnd()->PostMessage(WM_CODECOUNTDRV_NOTIFY, CODECOUNTDRV_NOTIFY_END, pCtrl->CountCtrl.iCountNum);
}
else
{
CODECOUNTDRV_COUNT_DATA &Data = pCtrl->CountCtrl.CountData.at(pCtrl->CountCtrl.iCountNum);
ZeroMemory(&Data.DataInfo, sizeof(Data.DataInfo));
try
{
CountFile(pCtrl, Data.strPath, &Data.DataInfo);
}
catch(...)
{
// do nothing
}
pCtrl->CountCtrl.iCountNum++;
iProcess = pCtrl->CountCtrl.iCountNum * 100 / iSize;
AfxGetMainWnd()->PostMessage(WM_CODECOUNTDRV_NOTIFY, CODECOUNTDRV_NOTIFY_PROGRESS, iProcess);
MsgBase.iType = CODECOUNTDRV_MSG_CONTINUE;
if(m_MsgQueue.SendMsg(MsgBase) != MSGQUEUE_ERR_NONE)
{
TRACE("send CODECOUNTDRV_MSG_CONTINUE fail\n");
}
}
}
void CCodeCountDrv::CountFile(CODECOUNTDRV_CTRL *pCtrl, const CString &strPath, CODECOUNTDRV_COUNT_DATA_INFO *pDataInfo)
{
CFile File;
int i = 0;
int iLength = 0;
int iConvertLen = 0;
if(pCtrl == NULL || pDataInfo == NULL)
{
return;
}
pCtrl->CountCtrl.StepType = CODECOUNTDRV_COUNT_STEP_NONE;
if(!File.Open(strPath, CFile::modeRead))
{
return;
}
iLength = static_cast<int>(File.GetLength());
if(iLength <= 0)
{
File.Close();
return;
}
pDataInfo->iTotalLines = 1;
pCtrl->CountCtrl.iDataLen = 0;
delete pCtrl->CountCtrl.pbyData;
delete pCtrl->CountCtrl.pwDataConvert;
pCtrl->CountCtrl.pbyData = new BYTE[iLength];
pCtrl->CountCtrl.pwDataConvert = new WCHAR[iLength];
File.Read(pCtrl->CountCtrl.pbyData, iLength);
iConvertLen = MultiByteToWideChar(CP_ACP, 0, (LPSTR)pCtrl->CountCtrl.pbyData, iLength, pCtrl->CountCtrl.pwDataConvert, iLength);
for(i = 0; i < iConvertLen; i++)
{
CountFileData(pCtrl, pCtrl->CountCtrl.pwDataConvert[i], pDataInfo);
}
File.Close();
}
void CCodeCountDrv::CountFileData(CODECOUNTDRV_CTRL *pCtrl, WCHAR wData, CODECOUNTDRV_COUNT_DATA_INFO *pDataInfo)
{
if(wData == TCHAR('\r'))
{
return;
}
switch(pCtrl->CountCtrl.StepType)
{
case CODECOUNTDRV_COUNT_STEP_NONE:
if(wData == TCHAR('\n'))
{
pDataInfo->iTotalLines++;
if(pCtrl->CountCtrl.iDataLen <= 0)
{
pDataInfo->iBlankLines++;
}
else
{
pDataInfo->iCodeLines++;
}
pCtrl->CountCtrl.iDataLen = 0;
pCtrl->CountCtrl.StepType = CODECOUNTDRV_COUNT_STEP_NONE;
}
else if(wData == TCHAR('/'))
{
pCtrl->CountCtrl.StepType = CODECOUNTDRV_COUNT_STEP_SLANT;
}
else if(wData == TCHAR('\"'))
{
pCtrl->CountCtrl.iDataLen++;
pCtrl->CountCtrl.StepType = CODECOUNTDRV_COUNT_STEP_MARKS;
}
else
{
if(wData != TCHAR(' ') && wData != TCHAR('\t'))
{
pCtrl->CountCtrl.iDataLen++;
}
else
{
// do nothing
}
}
break;
case CODECOUNTDRV_COUNT_STEP_M