cdlcompiler/src/CdlCompiler.cpp
changeset 0 f58d6ec98e88
child 1 b700e12870ca
--- /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