diff -r 000000000000 -r f58d6ec98e88 cdlcompiler/src/CdlCompiler.cpp --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +using namespace CdlCompilerToolkit; + +#ifndef _DEBUG +#define EXCEPTION_HANDLING +#endif + + +typedef list TArgsList; +auto_ptr 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 [] " << endl; + stream << " 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 << " are:" << endl; + stream << " -p path for the output files." << endl; + stream << " -v show CdlCompiler version." << endl; + stream << " -h show help information for a ." << 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 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 []" << 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 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 []" << endl; + aStream << " instance mode creates C++ files containing a template customisation instance." << endl; + aStream << " The customisation instance will implement the interface defined in ." << endl; + aStream << " It and its source files will be called ." << endl; + aStream << " It will have an instance id of , 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 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 [] []" << endl; + aStream << " package mode creates template package instance C++ files." << endl; + aStream << " The package instance will implement the interface defined in ." << endl; + aStream << " It and its source files will be called ." << endl; + aStream << " It will have an instance id of if is a number." << endl; + aStream << " The package contents will be references to the customisation instances ." << 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 []" << 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 ." << endl; + aStream << " It will have a UID of ." << endl; + aStream << " The DLL will contain customisation instances ." << 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 to add a library to the DLL." << endl; + aStream << " -s to add a source file to the DLL." << endl; + aStream << " -e to add more statements to the DLL's MMP file." << endl; + aStream << " -n 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 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 " << 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 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 ParseList(const TArgsList& aFiles) + { + auto_ptr ifaceList(new CCdlTkInterfaceList); + + for (TArgsList::const_iterator pFile = aFiles.begin(); pFile != aFiles.end(); ++pFile) + { + CCdlTkCdlFileParser parser(*pFile); + auto_ptr 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 mode; + if (*pArg == "client") + { + mode = auto_ptr(new CClientMode); + CdlTkUtil::SetOutputPath(CdlTkUtil::CurrentDrive() + "\\epoc32\\include\\"); + } + else if (*pArg == "instance") + { + mode = auto_ptr(new CInstanceMode); + } + else if (*pArg == "dll") + { + mode = auto_ptr(new CDllMode); + } + else if (*pArg == "package") + { + mode = auto_ptr(new CPackageMode); + } + else if (*pArg == "compare") + { + mode = auto_ptr(new CCompareMode); + } + else if (*pArg == "BigApiTest") + { + mode = auto_ptr(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