1. Licenses updated to EPL.
2. New components test cases added to BC Drivers
3. Some minor fixes and few feature additions to CA.
/*
* Copyright (c) 2008, 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include "CmdGlobals.h"
#ifdef __WIN__
#pragma warning(disable:4786)
#endif
#ifndef _MSC_VER
#define stricmp strcasecmp
#endif
#include <iostream>
#include <sstream>
#include <map>
#include "CommandLine.h"
#include "HAException.h"
#include "CmdGlobals.h"
#include "CommandFile.h"
#include "BBCFileUtils.h"
#include "Utils.h"
#include "ReportGeneratorConstants.h"
using namespace std;
// ----------------------------------------------------------------------------
// CommandLine::CommandLine
// Constructor
// ----------------------------------------------------------------------------
//
CommandLine::CommandLine() : iParametersValid(-1)
{
initializeAcceptableParametersList();
}
// ----------------------------------------------------------------------------
// CommandLine::CommandLine
// Constructor
// ----------------------------------------------------------------------------
//
CommandLine::CommandLine(char** args, int argc) : iParametersValid(-1)
{
// first check if the command line parameters contain any help command
int i=1;
while (i<argc)
{
if (stricmp("-?", args[i])==0 || stricmp("-h", args[i])==0 || stricmp("--help", args[i])==0)
{
showCommandLineOptionsAndExit();
}
i++;
}
initializeAcceptableParametersList();
iArgList = args;
iArgCount = argc;
}
// ----------------------------------------------------------------------------
// CommandLine::~CommandLine
// Destructor
// ----------------------------------------------------------------------------
//
CommandLine::~CommandLine()
{
iAcceptableParameterMap.clear();
parameterSpecifierSet.clear();
requiredParametersSet.clear();
}
// ----------------------------------------------------------------------------
// CommandLine::getParameter
// Returns the parameter value for a given parameter
// ----------------------------------------------------------------------------
//
string CommandLine::getParameter(string aParm)
{
map<string, string>::iterator mapitem = iParameterMap.find(aParm);
bool isValidParm = mapitem == iParameterMap.end() ? false : true;
if (!isValidParm)
{
string excstr = "No such parameter: ";
excstr += aParm;
throw HAException(excstr);
}
return mapitem->second;
}
const map <string, string>& CommandLine::getParameters()
{
return iParameterMap;
}
// ----------------------------------------------------------------------------
// CommandLine::CommandLine
// ----------------------------------------------------------------------------
//
void CommandLine::insertParameter(string paramName, bool specifierRequired, bool optional)
{
mapentry parm(paramName, "");
iAcceptableParameterMap.insert(parm);
if (specifierRequired)
{
parameterSpecifierSet.insert(paramName);
}
if (!optional)
{
requiredParametersSet.insert(paramName);
}
}
// ----------------------------------------------------------------------------
// CommandLine::parameterExists
// Check parameter existence
//
// ----------------------------------------------------------------------------
//
bool CommandLine::parameterExists(const string& aParmName)
{
bool ret = false;
map<string, string>::iterator mapitem = iParameterMap.find(aParmName);
if (mapitem != iParameterMap.end())
{
ret = true;
}
return ret;
}
// ----------------------------------------------------------------------------
// CommandLine::initializeAcceptableParametersList
// Initialize acceptable parameter list
//
// ----------------------------------------------------------------------------
//
void CommandLine::initializeAcceptableParametersList()
{
// note: baseline/current may be long strings (ie. many filenames separated by semicolons)
insertParameter(BASELINE, true);
insertParameter(CURRENT, true);
insertParameter(BASELINEDIR, true);
insertParameter(CURRENTDIR, true);
insertParameter(REPORTFILE, true, false);
insertParameter(BASELINEVERSION, true);
insertParameter(CURRENTVERSION, true);
insertParameter(COMMANDFILE, false);
insertParameter(BASEPLATFORMDATA, true);
insertParameter(CURRENTPLATFORMDATA, true);
insertParameter(RECURSIVE, false);
insertParameter(FILEREPLACE, true);
insertParameter(HEADERSET, true);
insertParameter(BASELINEPLAT, true, false);
insertParameter(CURRENTPLAT, true, false);
insertParameter(BUNDLESIZE, true);
insertParameter(TRIMXML, true);
insertParameter(TEMPDIR, true, false);
insertParameter(BASEFORCEDHEADERSFILE, true);
insertParameter(CURRENTFORCEDHEADERSFILE, true);
insertParameter(DOCURL, true);
insertParameter(DISCARDDIRS, true);
#if defined(_DEBUG) || defined(DEBUG)
insertParameter(COMMANDLINETEST, false);
#endif
insertParameter(USETHREAD, false);
}
// ----------------------------------------------------------------------------
// CommandLine::validateParameters
// Validate parameters
//
// ----------------------------------------------------------------------------
//
string CommandLine::validateParameters()
{
ostringstream ret;
parse(iArgList, iArgCount);
map<string, string>::iterator mapitem = iParameterMap.find(TEMPDIR);
if (mapitem == iParameterMap.end() || mapitem->second.length() < 1)
{
const char* env2 = getenv("TEMP");
if (env2 != NULL)
{
string tempfiles(env2);
if (mapitem != iParameterMap.end())
{
mapitem->second = tempfiles;
} else
{
pair <string,string> parm(TEMPDIR, tempfiles);
iParameterMap.insert(parm);
}
}
}
mapitem = iParameterMap.find(BASELINEPLAT);
if (mapitem == iParameterMap.end() || mapitem->second.length() < 1)
{
string envvar = BASELINEPLAT;
const char* env2 = getenv(toUpperCase(envvar).c_str());
if (env2 != NULL)
{
string tempfiles(env2);
if (mapitem != iParameterMap.end())
{
mapitem->second = tempfiles;
} else
{
pair <string,string> parm(TEMPDIR, tempfiles);
iParameterMap.insert(parm);
}
}
}
mapitem = iParameterMap.find(CURRENTPLAT);
if (mapitem == iParameterMap.end() || mapitem->second.length() < 1)
{
string envvar = CURRENTPLAT;
const char* env2 = getenv(toUpperCase(envvar).c_str());
if (env2 != NULL)
{
string tempfiles(env2);
if (mapitem != iParameterMap.end())
{
mapitem->second = tempfiles;
} else
{
pair <string,string> parm(TEMPDIR, tempfiles);
iParameterMap.insert(parm);
}
}
}
// START -- Support for multiple header directories --
mapitem = iParameterMap.find(BASELINEDIR);
if (mapitem == iParameterMap.end() || mapitem->second.length() < 1)
{
string envvar = BASELINEDIR;
const char* env2 = getenv(toUpperCase(envvar).c_str());
if (env2 != NULL)
{
string tempfiles(env2);
if (mapitem != iParameterMap.end())
{
mapitem->second = tempfiles;
} else
{
pair <string,string> parm(TEMPDIR, tempfiles);
iParameterMap.insert(parm);
}
}
}
mapitem = iParameterMap.find(CURRENTDIR);
if (mapitem == iParameterMap.end() || mapitem->second.length() < 1)
{
string envvar = CURRENTDIR;
const char* env2 = getenv(toUpperCase(envvar).c_str());
if (env2 != NULL)
{
string tempfiles(env2);
if (mapitem != iParameterMap.end())
{
mapitem->second = tempfiles;
} else
{
pair <string,string> parm(TEMPDIR, tempfiles);
iParameterMap.insert(parm);
}
}
}
// END -- Support for multiple header directories --
set<string>::iterator setitem = requiredParametersSet.begin();
while (setitem != requiredParametersSet.end())
{
string s = *setitem;
map<string, string>::iterator mapitem = iParameterMap.find(s);
if (mapitem == iParameterMap.end())
{
if (ret.str().length() == 0)
{
ret << "Missing required parameters: ";
}
ret << s;
ret << " ";
} else
{
// else branch not required anymore
if (mapitem->second.length() == 0)
{
if (ret.str().length() == 0)
{
ret << "Missing required parameters: ";
}
ret << s;
ret << " ";
}
}
setitem++;
}
if (ret.str().length() > 0)
{
ret << "\n";
}
if (!parameterExists(BASELINE) && !parameterExists(BASELINEDIR) && !parameterExists(CURRENT) && !parameterExists(CURRENTDIR))
{
ret << "One of the parameter listed next must be given: -"<< BASELINEDIR <<" -"<< BASELINE <<"\n";
ret << "One of the parameter listed next must be given: -"<< CURRENTDIR <<" -"<< CURRENT <<"\n";
}
// check for parameter conflicts in baseline parameters
if (parameterExists(BASELINE) && parameterExists(BASELINEDIR))
{
ret << "Parameter conflict: -"<< BASELINEDIR <<" and -"<< BASELINE <<" cannot co-exist\n";
} else
{
if (parameterExists(BASELINE) && !parameterExists(CURRENT))
{
ret << "Parameter conflict: When -"<< BASELINE <<" is specified then also -"<< CURRENT <<" is required.\n";
}
if (parameterExists(BASELINEDIR) && !parameterExists(CURRENTDIR))
{
ret << "Parameter conflict: When -"<< BASELINEDIR <<" is specified then also -"<< CURRENTDIR <<" is required.\n";
}
}
// Same for current headers
if (parameterExists(CURRENT) && parameterExists(CURRENTDIR))
{
ret << "Parameter conflict: -"<< CURRENTDIR <<" and -"<< CURRENT <<" cannot co-exist\n";
} else
{
if (parameterExists(CURRENT) && !parameterExists(BASELINE))
{
ret << "Parameter conflict: When -"<< CURRENT <<" is specified then also -"<< BASELINE <<" is required.\n";
}
if (parameterExists(CURRENTDIR) && !parameterExists(BASELINEDIR))
{
ret << "Parameter conflict: When -"<< CURRENTDIR <<" is specified then also -"<< BASELINEDIR <<" is required.\n";
}
}
// Check for parameters which are specific only for baselinedir/currentdir
if (parameterExists(BASELINE) || parameterExists(CURRENT))
{
if (parameterExists(FILEREPLACE))
{
ret << "Parameter conflict: -"<< FILEREPLACE <<" cannot be used in combination with file parameters (-"<< CURRENT <<"/-"<< BASELINE <<")\n";
}
if (parameterExists(RECURSIVE))
{
ret << "Parameter conflict: -"<< RECURSIVE <<" cannot be used in combination with file parameters (-"<< CURRENT <<"/-"<< BASELINE <<")\n";
}
if (parameterExists(HEADERSET))
{
ret << "Parameter conflict: -"<< HEADERSET <<" cannot be used in combination with file parameters (-"<< CURRENT <<"/-"<< BASELINE <<")\n";
}
}
if (!parameterExists(RECURSIVE) && parameterExists(DISCARDDIRS))
{
ret << "Parameter conflict: -"<< DISCARDDIRS <<" requires -"<< RECURSIVE <<"\n";
}
// Check that all the parameters that require a specifier
// indeed contain a specifier. If not, it's an error and must
// be reported
set<string>::iterator specIt = parameterSpecifierSet.begin();
while (specIt != parameterSpecifierSet.end())
{
map<string,string>::iterator parmIt = iParameterMap.find(*specIt);
if (parmIt != iParameterMap.end())
{
if (parmIt->second.length() < 1)
{
ret << "Missing required specifier for parameter -";
ret << *specIt;
ret << "\n";
}
}
specIt++;
}
return ret.str();
}
// ----------------------------------------------------------------------------
// CommandLine::validParamValue
// Check if the parameter value is valid.
// ----------------------------------------------------------------------------
//
void CommandLine::validParamValue(string parm,string val)
{
string ret;
// Don't check parameter 'recursive' , 'usethread' or any other that
// doesn't need a value.
int dontCheckParm = parm.compare( RECURSIVE);
int threadParm = parm.compare( USETHREAD);
if ( dontCheckParm !=0 && threadParm != 0 )
{
if ( parm.compare( BASELINEVERSION )==0 || parm.compare( CURRENTVERSION )==0 || parm.compare( BUNDLESIZE )==0 || parm.compare( HEADERSET )==0 )
{
//check for atleast one char long
if( val.length()<=0 )
{
ret = "Invalid value for parameter: " + parm + '\n';
throw HAException(ret);
}
}
else
{
//check for atleast two char long
if ( val.length()<=1 )
{
ret = "Invalid value for parameter: " + parm + '\n';
throw HAException(ret);
}
}
}
}
// ----------------------------------------------------------------------------
// CommandLine::storeParameter
// Stores a parameter.
// ----------------------------------------------------------------------------
//
void CommandLine::storeParameter(string parm, string val, int parmType)
{
map<string, string>::iterator mapitem;
bool isValidParm = false;
string errormsg;
mapitem = iAcceptableParameterMap.find(parm);
isValidParm = mapitem == iAcceptableParameterMap.end() ? false : true;
validParamValue(parm, val);
if (isValidParm && parm.length() > 0)
{
// Valid parameters are those that the map structure has been initialised with;
// any other parameter is invalid, and will yield an error.
bool needsSpecifier = parameterSpecifierSet.find(parm) == parameterSpecifierSet.end() ? false : true;
map<string, string>::iterator mapitem2;
mapitem2 = iParameterMap.find(parm);
pair<string,string> parmToInsert(parm, val);
if (needsSpecifier)
{
// Arguments that need specifier must have both the ARGUMENT_NAME and VALUE
// (ie. both fields in the map must be of nonzero length)
if (val.length() > 0)
{
if (parmType == EParmCommandFile)
{
// command file arguments can't replace (already existing) command-line
// arguments; command-file args will only be used when no similar
// argument was given in commandline.
if (mapitem2 != iParameterMap.end())
{
#if ( defined(_DEBUG) || defined(DEBUG) ) && !defined(NO_DBG)
cout << "Not overriding parameter from file: " << parm << "\n";
#endif
} else
{
#if ( defined(_DEBUG) || defined(DEBUG) ) && !defined(NO_DBG)
cout << "Got command-file parameter: "<<parm<<" value: "<<val<<"\n";
#endif
iParameterMap.insert(parmToInsert);
}
} else if (parmType == EParmCommandLine)
{
// command-line argument always overrides
#if ( defined(_DEBUG) || defined(DEBUG) ) && !defined(NO_DBG)
cout << "Got command-line parameter: "<<parm<<" value: "<<val<<"\n";
#endif
iParameterMap.insert(parmToInsert);
} else if (parmType == EParmEnvironment)
{
}
} else {
errormsg = "Expected non-empty specifier for parameter \"-" + parm + "\"\n";
throw(new HAException(errormsg));
}
} else
{
#if ( defined(_DEBUG) || defined(DEBUG) ) && !defined(NO_DBG)
cout << "Got switch: "<<parm<<"\n";
#endif
iParameterMap.insert(parmToInsert);
}
} else {
// Throw an exception containing the list of valid parameter names.
string errormsg = "Invalid parameter: " + parm + "\n";
/*
errormsg += "Valid parameters are:\n";
map<string,string>::iterator iter;
iter = iAcceptableParameterMap.begin();
while (iter != iAcceptableParameterMap.end())
{
errormsg += "\t" + iter->first + "\n";
iter++;
}
*/
HAException e(errormsg);
throw(e);
}
}
// ----------------------------------------------------------------------------
// CommandLine::parse
// ----------------------------------------------------------------------------
//
void CommandLine::parse(char** parms, size_t count, int parmsType)
{
// "Key" string
string currentstr;
// "Value" string
string currentparam;
bool hasSpace = false;
bool isString = false;
int lastPos = -1;
// Iterate through the parameters, char by char.
// argument names have a preceding '-' (and whitespace),
// argument values only have a preceding ' ' (whitespace).
for (unsigned int i = 1; i < count; i++)
{
int j = 0;
char ch = parms[i][j];
if (i > 1 && j == 0 && ch == '-')
{
if (hasSpace == true && currentparam == FILEREPLACE)
{
if (currentstr.at(lastPos) != '\"')
{
currentstr = currentstr.substr(0, lastPos) + "\"" + currentstr.substr(lastPos);
}
currentstr = currentstr + "\"";
}
storeParameter(currentparam, currentstr, parmsType);
currentparam = "";
currentstr = "";
isString = false;
hasSpace = false;
} else if (i > 1 && j == 0 && isString == false)
{
isString = true;
hasSpace = false;
lastPos = 0;
} else if (i > 1 && j == 0)
{
if (hasSpace == true && currentparam == FILEREPLACE)
{
if (currentstr.at(lastPos) != '\"')
{
currentstr = currentstr.substr(0, lastPos) + "\"" + currentstr.substr(lastPos);
}
currentstr = currentstr + "\"";
}
currentstr += ' ';
hasSpace = false;
lastPos = (int)currentstr.length();
}
while (ch != '\0')
{
if (ch == '\\' || ch == '/')
{
ch = DIR_SEPARATOR;
}
if (!isString)
{
if (j > 0)
{
currentparam += ch;
}
} else
{
if (ch == ' ') hasSpace = true;
currentstr += ch;
}
j++;
ch = parms[i][j];
}
}
// Dump the last one as well
if ( count > 1)
{
if (hasSpace == true && currentparam == FILEREPLACE)
{
currentstr = "\"" + currentstr + "\"";
}
storeParameter(currentparam, currentstr, parmsType);
}
// If the processed arguments didn't come from command file,
// check out if one exists and parse it if necessary.
if (parmsType != EParmCommandFile && parameterExists(COMMANDFILE))
{
string s = BBCFileUtils::getFullPath(getParameter(COMMANDFILE));
storeParameter(COMMANDFILE, s);
if (s.size() > 0)
{
CommandFile f = CommandFile(s);
char** commands = f.getCommandBuffer();
size_t length = f.commandBufferLength();
parse(commands, length , EParmCommandFile);
}
}
iParametersValid = true;
}
// ----------------------------------------------------------------------------
// CommandLine::showCommandLineOptionsAndExit
// Show options and exit
// ----------------------------------------------------------------------------
//
void CommandLine::showCommandLineOptionsAndExit()
{
cout << "HeaderAnalyser v" << HEADER_ANALYSER_VERSION << " - " << HEADER_ANALYSER_DATE << endl;
cout << "Copyright (c) 2001-2009 Nokia Corporation and/or its subsidiary(-ies). All rights reserved.\n"
"\n"
"Usage: ha [parameters]\n"
"\n"
"Parameters:\n"
" -baseline FILE Baseline FILE used when comparing two files\n"
" -current FILE Current release FILE used when comparing two files\n"
" -baselinedir Baseline directory WILDCARDS used when comparing two files\n"
" WILDCARDS;WILDCARDS\n"
" -currentdir Current release DIR used when comparing two files\n"
" DIR;DIR\n"
" -baselineversion NAME NAME of the baseline\n"
" -currentversion NAME NAME of the current release\n"
" -reportfile FILE Save report to FILE\n"
" -commandfile FILE Read command line parameters from FILE\n"
" -baseplatformheaders Read baseline platform headers from DIR\n"
" DIR;DIR\n"
" -currentplatformheaders Read current release platform headers from DIR\n"
" DIR;DIR\n"
" -forcebaseinclude Force to include this FILE always for baseline\n"
" FILE;FILE\n"
" -forcecurrentinclude Force to include this FILE always for current release\n"
" FILE;FILE\n"
" -recursive Include sub directories when scanning files\n"
" -excludedirs DIR;DIR When recursive is in use, exclude DIR\n"
" -set FILE;FILE Include only this FILE to the analysis. Wildcards can be used also.\n"
" -replace FILE NEWFILE Notify FILE has been renamed as NEWFILE in current\n"
" -bundlesize COUNT Specifies COUNT files are processed in one go\n"
" -temp DIRECTORY DIRECTORY to store intermediate files\n"
" -docurl URL Includes documentation URL for each issue\n"
" -baseplatformdata FILE Read baseline platform data from FILE.\n"
" The data is used when compiling the baseline headers\n"
" -currentplatformdata FILE Read current platform data from FILE.\n"
" The data is used when compiling the current headers\n"
" -usethread Enables multiple threading logic.Useful for Public vs Rnd\n"
" Sdk analysis or small no of headers (<3000).\n"
"\n";
exit(0);
}