/***************************************************************************/
/* NOTE: */
/* This document is copyright (c) by Oz Solomonovich, and is bound by the */
/* MIT open source license (www.opensource.org/licenses/mit-license.html). */
/* See License.txt for more information. */
/***************************************************************************/
#include "stdafx.h"
#include "LineCount.h"
#include "export.h"
#include "Config.h"
#include "WorkspaceInfo.h"
#include "Shlwapi.h"
// Converts a file's path to a relative path (based on user options).
// Based on original code and idea by Bassam Abdul-Baki
// [babdulbaki@digitalaccess.com]
CString ConvertPathToRelative(LPCTSTR pszSrcPath,
LPCTSTR pszProjectPath, LPCTSTR pszWorkspacePath)
{
char szOut[MAX_PATH + 1] = "";
switch (cfg_PathUsage)
{
case PU_FILTER:
{
PathRelativePathTo(szOut,
pszProjectPath,
FILE_ATTRIBUTE_NORMAL,
pszSrcPath,
FILE_ATTRIBUTE_DIRECTORY);
break;
}
case PU_FULL:
{
return pszSrcPath;
}
case PU_DSW:
default:
{
PathRelativePathTo(szOut,
pszWorkspacePath,
FILE_ATTRIBUTE_NORMAL,
pszSrcPath,
FILE_ATTRIBUTE_DIRECTORY);
break;
}
}
return szOut;
}
bool ExportAsCSV(CString sFileName, ProjectList& projects,
LPCTSTR pszWorkspaceName)
{
CString s;
bool bSuccess = false;
TRY
{
CStdioFile cFile(sFileName, CFile::modeCreate | CFile::modeWrite);
s.LoadString(IDS_CSV_COLUMNS);
cFile.WriteString(s + "\n");
POSITION p = projects.GetHeadPosition();
while (p)
{
const IWorkspaceProject * const pPrj = projects.GetNext(p);
const int cFiles = pPrj->GetFileCount();
for (int f = 0; f < cFiles; ++f)
{
IProjectFile *pFile = pPrj->GetFile(f);
const CFileInfo& fi = ::GetStats(pFile->GetPath());
delete pFile;
if (fi.m_stat == CFileInfo::filtered &&
!CHK_FLAG(cfg_ShowFiltered, SF_EXPORT))
{
// not including filtered files
continue;
}
if (fi.m_stat != CFileInfo::full &&
!CHK_FLAG(cfg_ShowBadFiles, SF_EXPORT))
{
// not including bad files
continue;
}
const CString sPath = ConvertPathToRelative(
fi.m_sFilePath, pPrj->GetName(), pszWorkspaceName);
s.Format("%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
pPrj->GetName(),
sPath,
fi.m_sFileName,
fi.m_sFileExt,
fi.GetTotalLinesStr(false),
fi.GetLinesWithCodeStr(false),
fi.GetLinesWithCommentsStr(false),
fi.GetMixedLinesStr(false),
fi.GetBlankLinesStr(false));
cFile.WriteString(s);
}
}
bSuccess = true;
}
CATCH(CFileException, e)
{
TCHAR szCause[255];
CString msg;
e->GetErrorMessage(szCause, 255);
AfxFormatString1(msg, IDS_WRITEERROR, szCause);
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
}
AND_CATCH_ALL(e)
{
AfxMessageBox("Error writing to file!",
MB_OK | MB_ICONEXCLAMATION);
}
END_CATCH_ALL
return bSuccess;
}
bool ExportAsXML(CString sFileName, ProjectList& projects,
LPCTSTR pszWorkspaceName)
{
CString s;
bool bSuccess = false;
TRY
{
CStdioFile cFile(sFileName, CFile::modeCreate | CFile::modeWrite);
CString sXSLT;
if (cfg_XSLTUsage != none)
{
CString sXSLFileName;
if (cfg_XSLTUsage == fixed_name)
{
sXSLFileName = cfg_sXSLTTemplate;
}
else
{
if (sFileName.Find('.'))
{
sXSLFileName =
sFileName.Left(sFileName.ReverseFind('.'));
sXSLFileName += ".xsl";
}
else
{
sXSLFileName = sFileName;
}
}
sXSLT.Format(
"<?xml-stylesheet type=\"text/xsl\" href=\"%s\"?>\n",
sXSLFileName);
}
// the header
s.Format(
// header
"<?xml version=\"1.0\"?>\n"
"\n"
"<!--\n"
"\n"
" Project statistics generated by Project Line Counter\n"
"\n"
"\tlines-total: count of all lines in the file\n"
"\tlines-code: count of lines with code, including lines that are mixed code/comments\n"
"\tlines-comments: count of lines with comments, including lines that are mixed code/comments\n"
"\tlines-mixed: count of lines that have both code and comments\n"
"\tlines-blank: count of lines without code or comments\n"
"\tlines-not-blank: same as (lines-total - lines-blank) and (lines-code + lines-comments - lines-mixed)\n"
"\n"
"-->\n\n"
// style sheet
"%s"
// root
"<statistics workspace=\"%s\" date=\"%s\" plc_ver=\"%d.%02d\">\n",
sXSLT, pszWorkspaceName,
CTime::GetCurrentTime().Format("%A, %B %d, %Y"),
g_iVerMaj, g_iVerMin);
cFile.WriteString(s);
POSITION p = projects.GetHeadPosition();
while (p)
{
const IWorkspaceProject * const pPrj = projects.GetNext(p);
const int cFiles = pPrj->GetFileCount();
s.Format("\t<project path=\"%s\">\n", pPrj->GetName());
cFile.WriteString(s);
for (int f = 0; f < cFiles; ++f)
{
IProjectFile *pFile = pPrj->GetFile(f);
const CFileInfo& fi = ::GetStats(pFile->GetPath());
delete pFile;
if (fi.m_stat == CFileInfo::filtered &&
!CHK_FLAG(cfg_ShowFiltered, SF_EXPORT))
{
// not including filtered files
continue;
}
if (fi.m_stat != CFileInfo::full &&
!CHK_FLAG(cfg_ShowBadFiles, SF_EXPORT))
{
// not including bad files
continue;
}
const CString sPath = ConvertPathToRelative(
fi.m_sFilePath, pPrj->GetName(), pszWorkspaceName);
s.Format(
"\t\t<file id=\"%s\">\n"
"\t\t\t<path>%s</path>\n"
"\t\t\t<name>%s</name>\n"
"\t\t\t<ext>%s</ext>\n"
"\t\t\t<lines-total>%s</lines-total>\n"
"\t\t\t<lines-code>%s</lines-code>\n"
"\t\t\t<lines-comments>%s</lines-comments>\n"
"\t\t\t<lines-mixed>%s</lines-mixed>\n"
"\t\t\t<lines-blank>%s</lines-blank>\n"
"\t\t\t<lines-not-blank>%d</lines-not-blank>\n"
"\t\t</file>\n",
fi.m_sFullFileName,
sPath,
fi.m_sFileName,
fi.m_sFileExt,
fi.GetTotalLinesStr(false),
fi.GetLinesWithCodeStr(false),
fi.GetLinesWithCommentsStr(false),
fi.GetMixedLinesStr(false),
fi.GetBlankLinesStr(false),
fi.m_iTotalLines - fi.m_iBlankLines);
cFile.WriteString(s);
}
cFile.WriteString("\t</project>\n");
}
cFile.WriteString("</statistics>\n");
bSuccess = true;
}
CATCH(CFileException, e)
{
TCHAR szCause[255];
CString msg;
e->GetErrorMessage(szCause, 255);
AfxFormatString1(msg, IDS_WRITEERROR, szCause);
AfxMessageBox(msg, MB_OK | MB_ICONEXCLAMATION);
}
AND_CATCH_ALL(e)
{
AfxMessageBox("Error writing to file!",
MB_OK | MB_ICONEXCLAMATION);
}
END_CATCH_ALL
return bSuccess;
}