apicompatanamdw/compatanalysercmd/headeranalyser/src/CommandLine.cpp
changeset 0 638b9c697799
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/apicompatanamdw/compatanalysercmd/headeranalyser/src/CommandLine.cpp	Tue Jan 12 14:52:39 2010 +0530
@@ -0,0 +1,681 @@
+/*
+* 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);    
+}