/************************************************************************
*
* Description : Defines the entry point for the LintProject application.
*
* (c) Copyright 2004-2008 by Anna-Jayne Metcalfe (anna@riverblade.co.uk)
* and Beth Mackenzie (beth@riverblade.co.uk) / Riverblade Limited
*
* Licence Terms:
*
* This code may be freely reused, subject to the licence terms below.
* Please do let us know of any bugs you find or improvements you make,
* so that we can pass them on to the rest of the development community.
*
* This code is free software; you can redistribute it and/or
* modify it under the terms of the Code Project Open License (CPOL)
* version 1.0 (http://www.codeproject.com/info/cpol10.aspx).
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Code Project Open Licence for further details.
*
************************************************************************
* $Archive: /Projects/Applications/LintProject/1.4/LintProject.cpp $
* $Revision: 23 $
* $Date: 23/10/08 13:28 $
* $Author: Anna $
*
* $Nokeywords: $
************************************************************************/
/// \file
/// \brief Application entry point.
#include "stdafx.h"
#include "Shared/ModuleVersion.h"
#include "Shared/SplitPath.h"
#include "Shared/StringUtils.h"
#include "Shared/FileUtils.h"
#include "Shared/PathUtils.h"
#include "Shared/SolutionFileReader.h"
#include "Shared/ProjectFileReader.h"
#include "SolutionLintAnalyser.h"
#include "ProjectLintAnalyser.h"
#include "resource.h"
/////////////////////////////////////////////////////////////////////////////
// The one and only application object
CLintProjectModule _Module;
using namespace std;
static void DisplayMessage(UINT uID)
{
CStringA sMsg;
ATLVERIFY(sMsg.LoadString(uID) );
cout << sMsg.GetString() << endl << endl;
}
static void DisplayErrorMessage(UINT uID)
{
CStringA sMsg;
ATLVERIFY(sMsg.LoadString(uID) );
cerr << sMsg.GetString() << endl << endl;
}
static void DisplayProjectConfigurations(const CString& sPathName, const CAtlArray<CString>& arrayConfigurations)
{
CString sMsg;
sMsg.Format( _T("Configurations for %s:"), sPathName);
cout << CStringA(sMsg).GetString() << endl << endl;
for (size_t n = 0; n < arrayConfigurations.GetCount(); n++)
{
const CString sConfig = arrayConfigurations[n];
ATLASSERT(!sConfig.IsEmpty() );
cout << " " << CStringA(sConfig).GetString() << endl;
}
cout << endl;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
UNREFERENCED_PARAMETER(envp);
_Module.SetResourceInstance(::GetModuleHandle(NULL) );
// BR 23/10/2008: Cannot be const if we need to change the return value
int nRetCode = 0;
bool bOk = false;
CAtlArray<CString> arrayAvailableConfigurations;
Utils::CModuleVersion ver;
ATLVERIFY(ver.GetFileVersionInfo() );
const CString sVersion = ver.GetValue( _T("FileVersion") );
CString sWelcomeMessage;
sWelcomeMessage.Format(IDS_LINT_COPYRIGHT_BANNER, sVersion);
cout << CStringA(sWelcomeMessage).GetString() << endl << endl;
// Determine if MSXML2 is available (we need it for generating output reports)
ATLVERIFY(SUCCEEDED(::CoInitialize(NULL) ) ); // Needed so we can use the XML DOM
MSXML2::IXMLDOMDocumentPtr ptrDOMDoc;
const HRESULT hr = ptrDOMDoc.CreateInstance("Msxml2.DOMDocument.3.0");
if (FAILED(hr) )
{
DisplayErrorMessage(IDP_LINT_ERR_MSXML_NOT_INSTALLED);
return -1;
}
// Work out which folder we're being run from. This will be the default folder
// we'll look for the PC-Lint executable in unless the user overrides it.
CString sExePathName;
(void)::GetModuleFileName(NULL, sExePathName.GetBuffer(_MAX_PATH + 1), _MAX_PATH);
sExePathName.ReleaseBuffer();
Utils::CSplitPath splitexe(sExePathName);
CString sLintFolder = splitexe.GetDrive() + splitexe.GetDirectory();
sLintFolder.TrimRight( _T("\\") );
CString sLintConfigFile = _T("std.lnt");
const CString sFolderSwitch = _T("/f");
const CString sConfigFileSwitch = _T("/configfile");
const CString sConfigSwitch = _T("/cfg");
const CString sConfigsSwitch = _T("/cfg?");
const CString sExternalParamsSwitch = _T("/param");
const CString sExternalProjectParamsSwitch = _T("/lntparam");
const CString sShowResultsSwitch = _T("/s");
const CString sExcludeProjectSwitch = _T("/exclude");
const CString sHelpSwitch = _T("/?");
CString sProjectFilePathName, sOutputFolder, sAdditionalParams, sAdditionalProjectParams, sConfiguration;
std::set<CString> setExcludedProjects;
bool bShowHtml = false;
bool bShowConfigs = false;
if (argc > 1)
{
for (int n = 1; n < argc; n++)
{
CString sParameter = argv[n];
if ( _T("/") != sParameter.Left(1) )
{
// Look for solution/project pathnames and output folder
if (sProjectFilePathName.IsEmpty() )
{
sProjectFilePathName = argv[n];
ATLASSERT(!sProjectFilePathName.IsEmpty() );
}
else if (sOutputFolder.IsEmpty() )
{
sOutputFolder = argv[n];
ATLASSERT(!sOutputFolder.IsEmpty() );
}
}
else
{
// Scan parameters
const CString sRawParameter = sParameter;
sParameter.MakeLower();
if (0 == sParameter.Find(sFolderSwitch) )
{
sLintFolder = Utils::After(sParameter, sFolderSwitch);
sLintFolder.TrimRight( _T("\\") );
ATLASSERT(!sLintFolder.IsEmpty() );
}
if (0 == sParameter.Find(sConfigFileSwitch) )
{
sLintConfigFile = Utils::After(sParameter, sConfigFileSwitch);
sLintConfigFile.TrimRight( _T("\\") );
ATLASSERT(!sLintConfigFile.IsEmpty() );
}
else if (0 == sParameter.Find(sConfigsSwitch) )
{
bShowConfigs = true;
}
else if (0 == sParameter.Find(sConfigSwitch) )
{
sConfiguration = Utils::After(sRawParameter, sConfigSwitch);
sConfiguration.TrimLeft(_T("=") );
sConfiguration.Trim( _T("\"") );
}
else if (0 == sParameter.Find(sExcludeProjectSwitch) )
{
// !!! new parameter /skip<project names>
// contains a comma separated list of project names
CString sProjects = Utils::After(sParameter, sExcludeProjectSwitch);
sProjects.TrimLeft(_T("=") );
sProjects.Trim(_T("\"") );
sProjects.MakeLower();
int nPos = 0;
while (nPos >= 0)
{
const CString sProject = sProjects.Tokenize(_T(","), nPos);
if (sProject.IsEmpty() )
{
break;
}
(void)setExcludedProjects.insert(sProject);
};
}
else if (0 == sParameter.Find(sShowResultsSwitch) )
{
bShowHtml = true;
}
else if (0 == sParameter.Find(sExternalProjectParamsSwitch) )
{
sAdditionalProjectParams = sParameter;
sAdditionalProjectParams.TrimLeft(sExternalProjectParamsSwitch);
sAdditionalProjectParams.TrimLeft( _T("\"") );
sAdditionalProjectParams.TrimRight( _T("\"") );
}
else if (0 == sParameter.Find(sExternalParamsSwitch) )
{
sAdditionalParams = sParameter;
sAdditionalParams.TrimLeft(sExternalParamsSwitch);
sAdditionalParams.TrimLeft( _T("\"") );
sAdditionalParams.TrimRight( _T("\"") );
}
else if (0 == sParameter.Find(sHelpSwitch) )
{
DisplayMessage(IDS_LINT_SYNTAX_MSG);
return nRetCode;
}
}
}
}
TCHAR szCurrentDir[_MAX_PATH + 1];
ATLVERIFY( ::GetCurrentDirectory(_MAX_PATH, szCurrentDir) > 0);
if (::PathIsRelative(sProjectFilePathName) )
{
sProjectFilePathName = Utils::CombinePath(szCurrentDir, sProjectFilePathName);
}
Utils::CSplitPath split(sProjectFilePathName);
CString sExt = split.GetExtension();
sExt.MakeLower();
const bool bIsSolution = ( (_T(".sln") == sExt) ||
(_T(".dsw") == sExt) ||
(_T(".vcw") == sExt) );
if (bShowConfigs)
{
if (bIsSolution)
{
ATLASSERT(!sProjectFilePathName.IsEmpty() );
CSolutionLintAnalyser sln( sProjectFilePathName,
sOutputFolder,
sLintConfigFile,
sAdditionalProjectParams,
sAdditionalParams,
sConfiguration);
(void)sln.GetConfigurations(arrayAvailableConfigurations);
DisplayProjectConfigurations(sProjectFilePathName, arrayAvailableConfigurations);
bOk = true;
}
else
{
ATLASSERT(!sProjectFilePathName.IsEmpty() );
CProjectLintAnalyser prj( NULL,
sProjectFilePathName,
_T(""),
sOutputFolder,
_T(""), // [Alex McCarthy 21.10.2008]
sLintConfigFile,
sAdditionalProjectParams,
sAdditionalParams,
sConfiguration);
(void)prj.GetConfigurations(arrayAvailableConfigurations);
DisplayProjectConfigurations(sProjectFilePathName, arrayAvailableConfigurations);
bOk = true;
}
}
else if (!Utils::FolderExists(sLintFolder) )
{
DisplayErrorMessage(IDP_LINT_ERR_FOLDER_NOT_FOUND);
// BR 23/10/2008: Set up for error return
nRetCode = 1;
}
else if (!Utils::FileExists(sLintFolder + _T("\\lint-nt.exe") ) )
{
CString sMsg;
sMsg.Format(IDP_LINT_ERR_EXECUTABLE_NOT_FOUND, sLintFolder);
cerr << CStringA(sMsg).GetString() << endl;
// BR 23/10/2008: Set up for error return
nRetCode = 1;
}
else if (!sProjectFilePathName.IsEmpty() && !sOutputFolder.IsEmpty() )
{
if (::PathIsRelative(sOutputFolder) )
{
sOutputFolder = Utils::CombinePath(szCurrentDir, sOutputFolder);
}
if (bIsSolution)
{
AddInSolutionModel::CSolutionFileReader parser;
ATLVERIFY(parser.Read(sProjectFilePathName) );
if (parser.IsValidConfiguration(sConfiguration) )
{
CSolutionLintAnalyser sln( sProjectFilePathName,
sOutputFolder,
sLintConfigFile,
sAdditionalProjectParams,
sAdditionalParams,
sConfiguration,
setExcludedProjects);
ATLVERIFY(sln.SetLintFolder(sLintFolder) );
ATLVERIFY(sln.ShowHtml(bShowHtml) );
bOk = sln.Analyse();
}
else
{
(void)parser.GetConfigurations(arrayAvailableConfigurations);
}
}
else
{
AddInSolutionModel::CProjectFileReader parser;
ATLVERIFY(parser.Read(sProjectFilePathName) );
if (parser.IsValidConfiguration(sConfiguration) )
{
ATLASSERT(!sProjectFilePathName.IsEmpty() );
CProjectLintAnalyser prj( NULL,
sProjectFilePathName,
_T(""),
sOutputFolder,
_T(""), // [Alex McCarthy 21.10.2008]
sLintConfigFile,
sAdditionalProjectParams,
sAdditionalParams,
sConfiguration);
ATLVERIFY(prj.SetLintFolder(sLintFolder) );
ATLVERIFY(prj.ShowHtml(bShowHtml) );
bOk = prj.Analyse();
}
else
{
(void)parser.GetConfigurations(arrayAvailableConfigurations);
}
}
}
if (!bOk)
{
DisplayMessage(IDS_LINT_SYNTAX_MSG);
// BR 23/10/2008: Set up for error return
nRetCode = 1;
if (arrayAvailableConfigurations.GetCount() > 0)
{
DisplayProjectConfigurations(sProjectFilePathName, arrayAvailableConfigurations);
}
}
return nRetCode;
} //lint !e818 (Information -- Pointer parameter could be declared as pointing to const)