--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cdlcompiler/src/CdlCompiler.cpp Thu Dec 17 09:14:18 2009 +0200
@@ -0,0 +1,624 @@
+/*
+* Copyright (c) 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:
+*
+*/
+#pragma warning (disable:4786) // disable "identifier was truncated to '255' characters in the browser information" warning
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <iostream>
+#include <list>
+#include <sstream>
+#include <iomanip>
+#include <direct.h>
+#include <cdlcompilertoolkit/cdltkutil.h>
+#include <cdlcompilertoolkit/cdltkprocess.h>
+using namespace std;
+using namespace CdlCompilerToolkit;
+
+#ifndef _DEBUG
+#define EXCEPTION_HANDLING
+#endif
+
+
+typedef list<string> TArgsList;
+auto_ptr<CCdlTkInterfaceList> ParseList(const TArgsList& aFiles);
+
+//
+// MainArgsErr
+//
+
+class MainArgsErr : public CdlCompilerToolkitErr
+ {
+public:
+ MainArgsErr(const string& aExtraInfo = "");
+ void Show(ostream& aStream) const;
+private:
+ string iExtraInfo;
+ };
+
+MainArgsErr::MainArgsErr(const string& aExtraInfo)
+: iExtraInfo(aExtraInfo)
+ {
+ }
+
+void MainArgsErr::Show(ostream& stream) const
+ {
+ if (iExtraInfo.size())
+ {
+ stream << endl;
+ stream << iExtraInfo << endl;
+ }
+ stream << endl;
+ stream << "CdlCompiler <mode> [<options>] <mode specific parameters>" << endl;
+ stream << " <mode> is:" << endl;
+ stream << " \"client\" mode creates the API for a customisable component." << endl;
+ stream << " \"instance\" mode creates customisation instance C++ files." << endl;
+ stream << " \"package\" mode creates package instance C++ files." << endl;
+ stream << " \"dll\" mode creates C++ and project files to collect together customisation instances in a DLL." << endl;
+ stream << " \"compare\" compares two CDL interfaces." << endl;
+ stream << " <options> are:" << endl;
+ stream << " -p<output path> path for the output files." << endl;
+ stream << " -v show CdlCompiler version." << endl;
+ stream << " -h show help information for a <mode>." << endl;
+ }
+
+
+//
+// CCompilerMode
+//
+
+class CCompilerMode
+ {
+public:
+ virtual ~CCompilerMode();
+ virtual void ProcessOption(const std::string& aOpt);
+ virtual int Process(const TArgsList& aArgs) = 0;
+ virtual void ShowHelp(ostream& aStream) = 0;
+ };
+
+CCompilerMode::~CCompilerMode()
+ {
+ }
+
+void CCompilerMode::ProcessOption(const std::string& aOpt)
+ {
+ throw MainArgsErr(string("unrecognised option for this mode ") + aOpt);
+ }
+
+
+//
+// CClientMode
+//
+
+class CClientMode : public CCompilerMode
+ {
+public:
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+ };
+
+int CClientMode::Process(const TArgsList& aArgs)
+ {
+ auto_ptr<CCdlTkInterfaceList> cdls(ParseList(aArgs));
+ for (CCdlTkInterfaceList::iterator pCdl = cdls->begin(); pCdl != cdls->end(); ++pCdl)
+ {
+ CCdlTkWriteClientHeader processor(**pCdl);
+ processor.Process();
+ }
+ return 0;
+ }
+
+void CClientMode::ShowHelp(ostream& aStream)
+ {
+ aStream << "CdlCompiler client <options> [<CDL files>]" << endl;
+ aStream << " client mode creates the API for a customisable component." << endl;
+ aStream << " For each CDL file parameter, it creates C++ header files containing the API." << endl;
+ aStream << " By default, these headers are placed in \\epoc32\\include." << endl;
+ }
+
+//
+// CInstanceMode
+//
+
+class CInstanceMode : public CCompilerMode
+ {
+public:
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+ };
+
+int CInstanceMode::Process(const TArgsList& aArgs)
+ {
+ TArgsList::const_iterator pArg = aArgs.begin();
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing CDL file name");
+
+ CCdlTkCdlFileParser parser(*pArg);
+ auto_ptr<CCdlTkInterface> cdl = parser.LoadAndParse(true);
+
+ ++pArg;
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing instance name");
+ CCdlTkInstance inst(*cdl);
+ inst.SetName(*pArg);
+ inst.TemplateAllImplementations();
+
+ ++pArg;
+ if (pArg != aArgs.end())
+ {
+ inst.SetId(CdlTkUtil::ParseInt(*pArg));
+ ++pArg;
+ }
+
+ if (pArg != aArgs.end())
+ throw MainArgsErr("Too many parameters");
+
+ CCdlTkWriteInstance processor(inst);
+ processor.Process();
+
+ return 0;
+ }
+
+void CInstanceMode::ShowHelp(ostream& aStream)
+ {
+ aStream << "CdlCompiler instance <options> <CDL file> <instance name> [<id>]" << endl;
+ aStream << " instance mode creates C++ files containing a template customisation instance." << endl;
+ aStream << " The customisation instance will implement the interface defined in <CDL file>." << endl;
+ aStream << " It and its source files will be called <instance name>." << endl;
+ aStream << " It will have an instance id of <id>, if specified. Otherwise," << endl;
+ aStream << " the instance id will come from the host DLL." << endl;
+ }
+
+
+//
+// CPackageMode
+//
+
+class CPackageMode : public CCompilerMode
+ {
+public:
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+ };
+
+int CPackageMode::Process(const TArgsList& aArgs)
+ {
+ TArgsList::const_iterator pArg = aArgs.begin();
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing package CDL file name");
+
+ CCdlTkCdlFileParser parser(*pArg);
+ auto_ptr<CCdlTkInterface> cdl = parser.LoadAndParse(true);
+
+ ++pArg;
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing package name");
+ CCdlTkPackage pckg(*cdl);
+ pckg.SetName(*pArg);
+ pckg.TemplateAllImplementations();
+
+ ++pArg;
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing package instance id");
+
+ if (count_if(pArg->begin(), pArg->end(), CdlTkUtil::IsNumeric) == pArg->size())
+ {
+ pckg.SetId(CdlTkUtil::ParseInt(*pArg));
+ ++pArg;
+ }
+
+ for (; pArg != aArgs.end(); ++pArg)
+ pckg.AddLocalContent(*pArg);
+
+ CCdlTkWriteInstance processor(pckg);
+ processor.Process();
+
+ return 0;
+ }
+
+void CPackageMode::ShowHelp(ostream& aStream)
+ {
+ aStream << "CdlCompiler package <options> <CDL file> <package name> [<id>] [<instance names>]" << endl;
+ aStream << " package mode creates template package instance C++ files." << endl;
+ aStream << " The package instance will implement the interface defined in <CDL file>." << endl;
+ aStream << " It and its source files will be called <package name>." << endl;
+ aStream << " It will have an instance id of <id> if <id> is a number." << endl;
+ aStream << " The package contents will be references to the customisation instances <instance names>." << endl;
+ aStream << " Note: the package contents will assume that all instances are in the same DLL." << endl;
+ }
+
+
+//
+// CDllMode
+//
+
+class CDllMode : public CCompilerMode
+ {
+public:
+ CDllMode();
+ void ProcessOption(const std::string& aOpt);
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+private:
+ CCdlTkDll::CLibraries iLibs;
+ string iExtraMmp;
+ int iVersion;
+ };
+
+CDllMode::CDllMode()
+: iVersion(1)
+ {
+ }
+
+void CDllMode::ProcessOption(const std::string& aOpt)
+ {
+ if (aOpt[1] == 'l')
+ {
+ iLibs.push_back(aOpt.substr(2));
+ }
+ else if (aOpt[1] == 's')
+ {
+ CdlTkUtil::AppendString(iExtraMmp, string("SOURCE "));
+ CdlTkUtil::AppendString(iExtraMmp, aOpt.substr(2));
+ CdlTkUtil::AppendString(iExtraMmp, "\n");
+ }
+ else if (aOpt[1] == 'e')
+ {
+ CdlTkUtil::AppendString(iExtraMmp, aOpt.substr(2));
+ CdlTkUtil::AppendString(iExtraMmp, "\n");
+ }
+ else if(aOpt[1] == 'n')
+ {
+ iVersion = CdlTkUtil::ParseInt(aOpt.substr(2));
+ if(iVersion < 1) iVersion = 1;
+ }
+ else
+ {
+ CCompilerMode::ProcessOption(aOpt);
+ }
+ }
+
+int CDllMode::Process(const TArgsList& aArgs)
+ {
+ TArgsList::const_iterator pArg = aArgs.begin();
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing DLL name");
+
+ CCdlTkDll dll;
+ dll.SetName(*pArg);
+ ++pArg;
+
+ dll.SetVersion(iVersion);
+
+ if (pArg == aArgs.end())
+ throw MainArgsErr("Missing DLL UID");
+
+ dll.SetUid(CdlTkUtil::ParseInt(*pArg));
+ ++pArg;
+
+ for (; pArg != aArgs.end(); ++pArg)
+ {
+ const string& inst = *pArg;
+ if (inst[0]!='@')
+ {
+ dll.AddInstance(*pArg);
+ }
+ else
+ {
+ // read instance list from a file
+ ifstream argFile;
+ CdlTkUtil::OpenInput(argFile, inst.substr(1));
+ string line;
+ while (!argFile.eof())
+ {
+ getline(argFile, line);
+ if (line.length())
+ dll.AddInstance(line);
+ }
+ argFile.close();
+ }
+ }
+
+ dll.Libraries().insert(dll.Libraries().end(), iLibs.begin(), iLibs.end());
+ dll.SetExtraMmp(dll.ExtraMmp() + iExtraMmp);
+
+ CCdlTkWriteDll processor(dll);
+ processor.Process();
+
+ return 0;
+ }
+
+void CDllMode::ShowHelp(ostream& aStream)
+ {
+ aStream << "CdlCompiler dll <options> <dll name> <uid> [<instance names>]" << endl;
+ aStream << " dll mode creates C++ and project files to collect together customisation instances in a DLL." << endl;
+ aStream << " The DLL and its source files will be called <dll name>." << endl;
+ aStream << " It will have a UID of <uid>." << endl;
+ aStream << " The DLL will contain customisation instances <instance names>." << endl;
+ aStream << " If an instance name starts with @, this will be treated as the name of a file" << endl;
+ aStream << " which contains a list of instance names, one per line." << endl;
+ aStream << " Options:" << endl;
+ aStream << " -l<libName> to add a library to the DLL." << endl;
+ aStream << " -s<sourceFileName> to add a source file to the DLL." << endl;
+ aStream << " -e<extraMmp> to add more statements to the DLL's MMP file." << endl;
+ aStream << " -n<version> to set the DLL version number in format x, defaults to 1 when not specified or invalid." << endl;
+ aStream << " Does not accept a minor version number." << endl;
+ }
+
+
+//
+// CCompareModeChecker
+//
+
+class CCompareModeChecker : public MCdlTkApiCheckObserver
+ {
+public:
+ CCompareModeChecker(const string& aLeft, const string& aRight);
+ virtual void StartCheck();
+ virtual void CheckComplete();
+ virtual void ApiInBoth(const CCdlTkApi& aApi);
+ virtual void ApiNotInLeft(const CCdlTkApi& aApi);
+ virtual void ApiNotInRight(const CCdlTkApi& aApi);
+
+private:
+ int iErrs;
+ string iLeft;
+ string iRight;
+ };
+
+CCompareModeChecker::CCompareModeChecker(const string& aLeft, const string& aRight)
+: iLeft(aLeft), iRight(aRight)
+ {
+ }
+
+void CCompareModeChecker::StartCheck()
+ {
+ iErrs = 0;
+ }
+
+void CCompareModeChecker::CheckComplete()
+ {
+ cout << "Check complete, " << iErrs << " differences found" << endl;
+ }
+
+void CCompareModeChecker::ApiInBoth(const CCdlTkApi& /*aApi*/)
+ {
+ }
+
+void CCompareModeChecker::ApiNotInLeft(const CCdlTkApi& aApi)
+ {
+ cout << iRight << ": " << aApi.Name() << aApi.ParamsTypeAndNameList() << " not found in " << iLeft << endl;
+ iErrs++;
+ }
+
+void CCompareModeChecker::ApiNotInRight(const CCdlTkApi& aApi)
+ {
+ cout << iLeft << ": " << aApi.Name() << aApi.ParamsTypeAndNameList() << " not found in " << iRight << endl;
+ iErrs++;
+ }
+
+
+//
+// CCompareMode
+//
+
+class CCompareMode : public CCompilerMode
+ {
+public:
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+ };
+
+int CCompareMode::Process(const TArgsList& aArgs)
+ {
+ auto_ptr<CCdlTkInterfaceList> cdls(ParseList(aArgs));
+ if (cdls->size() != 2)
+ throw MainArgsErr("Exactly 2 CDL files required");
+ CCompareModeChecker reporter(*aArgs.begin(), *++(aArgs.begin()));
+ CCdlTkApiChecker checker(*(*cdls)[0], *(*cdls)[1], reporter);
+ checker.Process();
+
+ return 0;
+ }
+
+void CCompareMode::ShowHelp(ostream& aStream)
+ {
+ aStream << "CdlCompiler compare <options> <left CDL file> <right CDL file>" << endl;
+ aStream << " compare mode reports the difference between two CDL interfaces." << endl;
+ }
+
+
+//
+// CCompareMode
+//
+
+class CBigApiTestMode : public CCompilerMode
+ {
+public:
+ int Process(const TArgsList& aArgs);
+ void ShowHelp(ostream& aStream);
+ };
+
+string MakeApiName(int i)
+ {
+ return string("Api")+CdlTkUtil::IntToString(i);
+ }
+
+int CBigApiTestMode::Process(const TArgsList& aArgs)
+ {
+ string name = "BigApi";
+ int size = CdlTkUtil::ParseInt(*aArgs.begin());
+
+ // make a CDL interface
+ CCdlTkInterface iface;
+ iface.SetFileName(name+".cdl");
+ CCdlTkInterfaceHeader& header = iface.Header();
+ header.SetName(name);
+ header.SetUid(0x0fffffff);
+ CCdlTkApiList& apiList = iface.ApiList();
+ for (int ii=0; ii<size; ii++)
+ {
+ auto_ptr<CCdlTkFunctionApi> api(new CCdlTkFunctionApi(iface));
+ api->SetName(MakeApiName(ii));
+ api->SetReturnType("TInt");
+ apiList.push_back(api.get());
+ api.release();
+ }
+
+ // write the CDL file
+ CCdlTkWriteCdlFile cdlWriter(iface);
+ cdlWriter.Process();
+
+ // make an instance
+ CCdlTkInstance inst(iface);
+ inst.SetName(name+"Inst");
+ inst.TemplateAllImplementations();
+ CCdlTkImplementations& impls = inst.Impl();
+ for (CCdlTkImplementations::iterator pImpl = impls.begin(); pImpl != impls.end(); ++pImpl)
+ {
+ CCdlTkImplementation& imp = **pImpl;
+ string defn = imp.Definition();
+ defn = CdlTkUtil::Replace("//TODO: Implement this function.", "return 0;", defn);
+ imp.SetDefinition(defn);
+ }
+
+ // write the instance
+ CCdlTkWriteInstance instWriter(inst);
+ instWriter.Process();
+
+ return 0;
+ }
+
+void CBigApiTestMode::ShowHelp(ostream& /*aStream*/)
+ {
+ }
+
+
+//
+// static functions
+//
+
+bool ProcessOptions(TArgsList::iterator& aArgIter, const TArgsList::iterator& aEnd, CCompilerMode& aMode)
+ {
+ while (aArgIter != aEnd && (*aArgIter)[0] == '-')
+ {
+ string& arg = *aArgIter;
+ if (arg.size() < 2)
+ throw MainArgsErr("bad option \"-\"");
+ switch (arg[1])
+ {
+ case 'p':
+ CdlTkUtil::SetOutputPath(arg.substr(2));
+ break;
+ case 'v':
+ cout << "CdlCompiler version " << KCdlCompilerMajorVersion << "." << KCdlCompilerMinorVersion << endl;
+ return true; // exit CdlCompiler
+ case 'h':
+ aMode.ShowHelp(cerr);
+ return true; // exit CdlCompiler
+ default:
+ aMode.ProcessOption(arg);
+ break;
+ }
+ ++aArgIter;
+ }
+ return false; // continue execution of the CdlCompiler
+ }
+
+auto_ptr<CCdlTkInterfaceList> ParseList(const TArgsList& aFiles)
+ {
+ auto_ptr<CCdlTkInterfaceList> ifaceList(new CCdlTkInterfaceList);
+
+ for (TArgsList::const_iterator pFile = aFiles.begin(); pFile != aFiles.end(); ++pFile)
+ {
+ CCdlTkCdlFileParser parser(*pFile);
+ auto_ptr<CCdlTkInterface> cdl = parser.LoadAndParse(true);
+ ifaceList->push_back(cdl.get());
+ cdl.release();
+ }
+
+ return ifaceList;
+ }
+
+int DoMain(int argc, char* argv[])
+ {
+ CdlTkUtil::SetCommandLine(argc, argv);
+
+ if (argc < 2)
+ throw MainArgsErr("Missing mode");
+
+ TArgsList args;
+ copy(argv + 1, argv + argc, back_inserter(args));
+ TArgsList::iterator pArg = args.begin();
+
+ // process mode arg
+ auto_ptr<CCompilerMode> mode;
+ if (*pArg == "client")
+ {
+ mode = auto_ptr<CCompilerMode>(new CClientMode);
+ CdlTkUtil::SetOutputPath(CdlTkUtil::CurrentDrive() + "\\epoc32\\include\\");
+ }
+ else if (*pArg == "instance")
+ {
+ mode = auto_ptr<CCompilerMode>(new CInstanceMode);
+ }
+ else if (*pArg == "dll")
+ {
+ mode = auto_ptr<CCompilerMode>(new CDllMode);
+ }
+ else if (*pArg == "package")
+ {
+ mode = auto_ptr<CCompilerMode>(new CPackageMode);
+ }
+ else if (*pArg == "compare")
+ {
+ mode = auto_ptr<CCompilerMode>(new CCompareMode);
+ }
+ else if (*pArg == "BigApiTest")
+ {
+ mode = auto_ptr<CCompilerMode>(new CBigApiTestMode);
+ }
+ else
+ throw MainArgsErr(string("Unrecognised mode ") + *pArg);
+ ++pArg;
+
+ // process options args
+ if (ProcessOptions(pArg, args.end(), *mode))
+ return 0;
+
+ // process mode args
+ return mode->Process(TArgsList(pArg, args.end()));
+ }
+
+int main(int argc, char* argv[])
+ {
+#ifdef EXCEPTION_HANDLING
+ try
+ {
+#endif
+ return DoMain(argc, argv);
+#ifdef EXCEPTION_HANDLING
+ }
+ catch (const CdlCompilerToolkitErr& aErr)
+ {
+ aErr.Show(cerr);
+ }
+
+ return 1;
+#endif
+ }
+
+// End of File