diff -r 000000000000 -r dfb7c4ff071f commsfwtools/preparedefaultcommsdatabase/Tools/ced/src/ced.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commsfwtools/preparedefaultcommsdatabase/Tools/ced/src/ced.cpp Thu Dec 17 09:22:25 2009 +0200 @@ -0,0 +1,1609 @@ +// Copyright (c) 2003-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: +// + +/** + @file ced.cpp + @internalComponent +*/ + +#include +#include +#include +#include +#include +#include "dbdef.h" +#include "filedump.h" +#include "input.h" +#include "database.h" +#include "CXMLFile.h" +#include "CXMLContentHandler.h" +#include "CDBSTD.H" +#include + +/** max length of path/filename/column/table name */ +#define MAX_BUFFER_LEN 256 + +/** max length of path/filename/column/table name */ +#define MAX_ATTRIB_LEN 32 + +/** max length of arg list to program */ +#define MAX_ARG_LEN (MAX_BUFFER_LEN * 3) + +/** Application name */ +#define APPLICATIONNAME _L("CommsDat Configuration Utility") + +/** Version Info */ +#define CEDUNVERSIONED _L("CED deliberately un-versioned") /** refer DEF092743 */ + +#ifdef __TOOLS2__ + +_LIT(CFG_TARGET, "ced.cfg"); +_LIT(XML_TARGET, "ced.xml"); +_LIT(LOG_TARGET, "ced.log"); +_LIT(KMeshPrefaceFile, "meshpreface1.cfg"); + + #ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + #ifndef SYMBIAN_COMMSDAT_USE_INT_RECORD_LINKS + _LIT(SUPPORTED_OS, "95"); + #else + _LIT(SUPPORTED_OS, ""); + #endif + #else + #ifndef SYMBIAN_COMMSDAT_USE_INT_RECORD_LINKS + _LIT(SUPPORTED_OS, "94"); + #else + _LIT(SUPPORTED_OS, "93"); + #endif + #endif + +#else + +_LIT(CFG_TARGET, "c:\\ced.cfg"); +_LIT(XML_TARGET, "c:\\ced.xml"); +_LIT(LOG_TARGET, "c:\\ced.log"); +_LIT(KMeshPrefaceFile, "z:\\system\\data\\meshpreface1.cfg"); +_LIT(DEFAULT_SESSION_PATH, "c:\\"); +#endif + + +// GLOBALS +/** Logging */ +CFileDump* gMsg; +/** Database access */ +DBAccess* gDB; +/** .ini file parsing */ +CfgFile gCfg; +/** XML file parsing */ +XMLFile* gXML; +/** Console accessor */ +LOCAL_D CConsoleBase* gConsole; +/** Passed in arg list */ +HBufC* gArgumentLine; +/** Flag to indicate a successful run */ +TBool gProcessingSuccessful = ETrue; +/** Flag to indicate whether the '-V' arg was passed in */ +TBool gValidityChecking = EFalse; +/** flag to indicate whether the execution format is .dll or .exe*/ +TBool gIsExeDLL = EFalse; +/** flag to indicate whether the configuration file is in XML format */ +TBool gIsXML = ETrue; + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS +TBool gDeprecatedFields = EFalse; +#endif +//SYMBIAN_NETWORKING_3GPPDEFAULTQOS + +// PROTOTYPES + +TInt ParseCommandLineL(TInt &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut, TDes &aInPref); +TInt ParseArgument(TInt &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut); + +TInt DoProcessL(TBool aIsCfg); +void DoDeleteL(); + +TInt DoCfgTemplateL(TDesC &aTable, const TInt &aIndex); +TInt DoCfgInsertsL(TDesC &aTable, const TInt &aIndex); + +TInt DoXMLTemplateL(const TInt &aIndex); +TInt DoXMLInsertsL(const TInt &aIndex); + +TInt SetColumnDetailsL(TInt aIndex, TInt aRecordCount); +TInt SetXMLColumnDetailsL(TInt aEntryIndex, TInt aIndex, TInt aRecCount); + +void DisplayMessage(TPtrC aMessage, TInt aJustTheMessage = EFalse); +void HelpDump(); +void MainL(); +LOCAL_C void doMainL(); + +TInt DoProcessL(TBool aIsCfg) +/** Store the information provided in the configuration file to CommDB + +@param aIsCfg Whether the file to be parsed is an older style .cfg rather than .xml +@return TInt refer only called functions +@leave refer only called functions and dependant components +*/ + { + TRAPD(ret, gDB->InitCommsdatL()); + + // connect to DB manager + if (ret==KErrNone) + { + TVersion version = gDB->Version(); + gMsg->Msg(_L("Database Version Maj %d Min %d Build %d"), version.iMajor, version.iMinor, version.iBuild); + + gMsg->Dbg(_L("")); + gMsg->Dbg(_L("Session started")); + + // loop through tables + TInt i = 0; + TInt j = 0; + TBuf table = tableArray[i]; + TBuf tempColumn; + TBool changed; + + while (table.Compare(TPtrC(NO_MORE_RECORDS)) != 0) + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("%S Table"), &table); + // get a count of editable columns + j = 0; + tempColumn = ColumnArray[i][j]; + while(tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0) + { + j++; + tempColumn = ColumnArray[i][j]; + } + gMsg->Dbg(_L("(%d editable fields in table)"), j); + + TBool commitIndividualRecords = (table.CompareC(_L("ConnectionPreferences")) == 0); + + if(commitIndividualRecords) + { + // Commit any current changes + TInt ret = gDB->CommitTransaction(); + if(ret != KErrNone) + { + gMsg->Msg(_L("ERROR: CommitTransaction returned err [%d]"), ret); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + } + } + else + { + gDB->MaybeBeginTransactionL(); + } + gDB->SetCommitIndividualRecords(commitIndividualRecords); + + changed = EFalse; + //Create a recordset for the table + ret = KErrNone; + if(!commitIndividualRecords) + { + TRAP(ret, gDB->CreateOrInsertRecordL(DBAccess::ECreateNew,elementIdArray[i], 0)); + } + if(ret == KErrNone) + { + if (aIsCfg?DoCfgTemplateL(table,i):DoXMLTemplateL(i)) + { + gMsg->Msg(_L(" ")); + changed = ETrue; + } + + if (aIsCfg?DoCfgInsertsL(table, i):DoXMLInsertsL(i)) + { + gMsg->Msg(_L(" ")); + changed = ETrue; + } + + if (changed) + { + TInt commitErr = gDB->CommitChanges(); + + if (commitErr == KErrNone) + { + gMsg->Msg(_L("Insert successful")); + } + else + { + gMsg->Msg(_L("Insert failed [%d ]"), commitErr); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + } + } + else + { + gMsg->Dbg(_L("Nothing to process")); + } + + if(gDB->CommitIndividualRecords()) + { + ret = gDB->CommitChanges(); + } + gDB->CloseTable(); + + } + else + { + gMsg->Dbg(_L("(Creating Record set Failed [%d ])"), ret); + } + + i++; + table = tableArray[i]; + + } + ret = gDB->CommitTransaction(); + gDB->Close(); + } + else + { + gMsg->Dbg(_L("(Could not connect to Commsdat [%d ])"), ret); + } + + return ret; + } + +void DoDeleteL() +/** Completely erase the communications database, not used when the append flag set + +@return void +@leave refer only called functions and dependant components +*/ + { + gMsg->Msg(_L("The old database will be replaced ") ); + + // Get a session with the central repository + const TUid KCDCommsRepositoryId = { 0xCCCCCC00 }; + CRepository* storage = NULL; + + TRAPD(err, storage = CRepository::NewL(KCDCommsRepositoryId)); + if (KErrNone != err) + { + gMsg->Msg(_L("Failed to create Central Repository with ID : %x (error %d)"), KCDCommsRepositoryId, err); + _LIT(KCEDPanic, "CED"); + User::Panic(KCEDPanic, KErrNotFound); + } + CleanupStack::PushL(storage); + + // open transaction - if can't do this then fail. + User::LeaveIfError(storage->StartTransaction(CRepository::EReadWriteTransaction)); + + // Find everything in the database + RArray ids; + CleanupClosePushL(ids); + err = storage->FindL(0, 0, ids); + if(err != KErrNotFound) + { + User::LeaveIfError(err); + } + + // delete everything in the database + if (ids.Count()) + { + for ( TInt i = ids.Count()-1; i >=0 ; i--) + { + if( i == ids.Count()-1 || i>=10000 && i%10000==0 || i<10000 && i>= 1000 && i%1000==0 || + i<1000 && i>=100 && i%100==0 || i<100 && i>=10 && i%10==0 || i<10) + { + gMsg->Msg(_L("%d"),i); + } + User::LeaveIfError(storage->Delete(ids[i])); + } + } + + TUint32 aErrorId; + err = storage->CommitTransaction(aErrorId); + + CleanupStack::PopAndDestroy(2); + + if (err != KErrNone) + { + gMsg->Msg(_L("Central Repository CommitTransaction returned err [%d]"), err); + } + User::LeaveIfError(err); + } + +void MainL() +/** Central processing unit of CED + +@return void +@leave refer only called functions and dependant components +*/ + { + TInt bDebugOn = EFalse; + TBool bOverWrite = EFalse; + TBool bForceXMLProcessing = EFalse; + + TBuf fIn; + TBuf fOut; + TBuf fInPref; + RFs fsSession; // file system session + + // connect to file system + User::LeaveIfError(fsSession.Connect()); + CleanupClosePushL(fsSession); + + // check command line + TInt valid; + + if (gIsExeDLL == EFalse) + { + // exe's get arguments from the command line + valid = ParseCommandLineL(bDebugOn, bOverWrite, bForceXMLProcessing, fIn, fOut, fInPref); + } + else + { + // exedll'd get the parameters passed in + valid = ParseArgument(bDebugOn, bOverWrite, bForceXMLProcessing, fIn, fOut); + } + + if (valid) + { + // Get the type of the input file i.e. whether it is + // an XML file or a CFG file + (fIn.FindF(_L(".XML")) != KErrNotFound)?gIsXML = ETrue:gIsXML = EFalse; + + // display title + gConsole->Printf(_L("------------------------------------------------------------\n")); + gConsole->Printf(APPLICATIONNAME); + gConsole->Printf(_L("\n------------------------------------------------------------\n\n")); + gConsole->Printf(_L("CED is now processing the configuration file from [%S], \n"), &fIn); + + if ( bOverWrite ) gConsole->Printf(_L("The old database will be replaced \n") ); + + if ( gIsXML ) + { + gConsole->Printf(_L("The config file is in XML format \n") ); + if ( bForceXMLProcessing ) + { + gConsole->Printf(_L("Invalid table entry links will be allowed \n") ); + } + else + { + gConsole->Printf(_L("Invalid table entry links will not be allowed \n") ); + } + } + else + { + gConsole->Printf(_L("The config file is in CFG format \n") ); + } + + // initialise output log file + +#ifndef __TOOLS2__ + // Set up the session path for WINSCW / ARMv5 incase the log file name has no path. + fsSession.SetSessionPath( DEFAULT_SESSION_PATH ); +#endif + + gMsg = CFileDump::NewL(fsSession, fOut, TPtrC(APPLICATIONNAME), + TPtrC(CEDUNVERSIONED), bDebugOn, gConsole, EFalse); + CleanupStack::PushL(gMsg); + + if (!gMsg->IsInitialised()) + { + gConsole->Printf(_L("Failed to open the output log file [%S]\n"), &fOut); + } + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("====================================================")); + gMsg->Msg(APPLICATIONNAME); + gMsg->Msg(_L("====================================================")); + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("Processing configuration from [%S]"), &fIn); + + gIsXML?gMsg->Msg(_L("The config file is in XML format ")):gMsg->Msg(_L("The config file is in CFG format ") ); + + if(gProcessingSuccessful) + { + gDB = new (ELeave) DBAccess(gIsXML); + CleanupStack::PushL(gDB); + gDB->CheckElementValidity(gValidityChecking); + + //If the settings are not ovewritten we are appending + //This will take care of commdb ids + gDB->SetInAppendMode(!bOverWrite); + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + TBool isMeshCompatible(EFalse); + + if (bOverWrite) + //The database has to be re-built... + { + + CInputFileParser* fileParser = CInputFileParser::FactoryLC(gIsXML, fIn, gMsg); + + TRAPD(leaveVal, isMeshCompatible = fileParser->IsMeshCompatibleL()); + CleanupStack::PopAndDestroy(fileParser); + + if (leaveVal == KErrNone) + { + if (!isMeshCompatible) + { + gMsg->Msg(_L("MESHINFO: Configuration file [%S] is not mesh-compatible, inserting default meshtables"), &fIn); + + // Insert the new mesh related tables/records into the database. + + // The preface is a .cfg file, whatever the type of the original input file. + // + if (gCfg.OpenConfigFile(fInPref)) + { + if (bOverWrite) + { + DoDeleteL(); + } + /** + create a link resolver object which resolves all of the + link by tag linking (Link.TableName.Id) to link by recordId + (TableName.RecordId). + This is important because there can be circular referencing + between tables and if these tables contain link by tag refencing + to each other commsDat doesn't allow to commit those tables... + */ + //this object will resolve the linkByTag linking to simple linkByRecId format + LinkByTagResolver* resolver = LinkByTagResolver::NewLC(&gCfg, gMsg); + + //set the resolver object to the gDB object + gDB->SetLinkByTagResolver(resolver); + + //Set the iIsXML field to false as we are processing now a cfg file... + gDB->CfgXmlSetting() = EFalse; + + //The MeshPreface file will be processed first. This is important to know since here + //we don't want to do any mappings... + gDB->SetMeshProcessing(ETrue); + + DoProcessL(ETrue); + + //if originally xml processing was set then set it back now... + gDB->CfgXmlSetting() = gIsXML; + + //remove the resolver object form the gDB because it's not needed anymore + gDB->RemoveLinkByTagResolver(); + CleanupStack::PopAndDestroy(resolver); + resolver = NULL; + + gCfg.CloseConfigFile(); + if (!gValidityChecking) + { + gProcessingSuccessful = ETrue; + } + } + else + { + gMsg->Error(_L("MESHERR: Configuration file [%S] could not be opened"), &fInPref); + gProcessingSuccessful = EFalse; + } + } + else + { + gMsg->Msg(_L("MESHINFO: Configuration file [%S] is mesh-compatible"), &fIn); + } + } + else + { + gMsg->Error(_L("MESHERR: Configuration file [%S], processing failed, reason=<%d>"), &fIn, leaveVal); + gProcessingSuccessful = EFalse; + } + } + else + { + gMsg->Msg(_L("Appending data to the DB - no need to use the meshpreface config file")); + } + + + if (gProcessingSuccessful) + { +#endif + // Process the XML configuration file + if (gIsXML) + { + // Create the XML database + CXMLDatabase* xmlDb = CXMLDatabase::NewL(); + CleanupStack::PushL(xmlDb); + + gXML = new (ELeave) XMLFile; + CleanupStack::PushL(gXML); + + if (gXML->OpenConfigFile(fsSession,fIn,xmlDb,bForceXMLProcessing, !bOverWrite)) + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if (isMeshCompatible) + { +#endif + if (bOverWrite) + { + DoDeleteL(); + } +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + + + if (isMeshCompatible) + { + gDB->SetMeshProcessing(ETrue); + } + else + +#endif + { + gDB->SetMeshProcessing(EFalse); + } + + TRAPD(ret, DoProcessL(EFalse)); + gXML->CloseConfigFile(); + + if (gValidityChecking && ret != KErrNone) + { + gProcessingSuccessful = EFalse; + } + } + else + { + gMsg->Msg(_L("ERR: A problem was encountered while processing the configuration file [%S]"), &fIn); + gProcessingSuccessful = EFalse; + } + + // Cleanup + CleanupStack::PopAndDestroy(gXML); + CleanupStack::PopAndDestroy(xmlDb); + + gXML=NULL; + xmlDb=NULL; + } + else + { + if (gCfg.OpenConfigFile(fIn)) + { +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + if (isMeshCompatible) + { +#endif + if (bOverWrite) + { + DoDeleteL(); + } +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } + /** + create a link resolver object which resolves all of the + link by tag linking (Link.TableName.Id) to link by recordId + (TableName.RecordId). + This is important because there can be circular referencing + between tables and if these tables contain link by tag refencing + to each other commsDat doesn't allow to commit those tables... + */ + LinkByTagResolver* resolver = LinkByTagResolver::NewLC(&gCfg, gMsg); + + if (isMeshCompatible) + { + //our config file is a mesh compatible one so we can use the latestVersion in the DBSession + gDB->SetMeshProcessing(ETrue); + } + else + { + //our config file is not a mesh compatible one so we can should the version 1_1 in the + //DBSession + gDB->SetMeshProcessing(EFalse); + } + + gDB->SetLinkByTagResolver(resolver); +#endif + TRAPD(ret, DoProcessL(ETrue)); + gCfg.CloseConfigFile(); + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + gDB->RemoveLinkByTagResolver(); + CleanupStack::PopAndDestroy(resolver); + resolver = NULL; +#endif + + if (gValidityChecking && ret != KErrNone) + { + gProcessingSuccessful = EFalse; + } + } + else + { + gMsg->Msg(_L("ERR: Configuration file [%S] could not be opened"), &fIn); + gProcessingSuccessful = EFalse; + } + } + +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + } +#endif + CleanupStack::PopAndDestroy(gDB); + gDB=NULL; + } + + gMsg->Dbg(_L("")); + gMsg->Dbg(_L("Session finished")); + gMsg->Dbg(_L("")); + gMsg->Msg(_L("===================")); + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS + if (gDeprecatedFields) + { + gMsg->Msg(_L("WARNING: USE OF DEPRECATED FIELDS")); + } +#endif +//SYMBIAN_NETWORKING_3GPPDEFAULTQOS + + // write our processing indicater to the log file + gProcessingSuccessful?gMsg->Msg(_L("SUCCESS")):gMsg->Msg(_L("ERROR")); + + CleanupStack::PopAndDestroy(gMsg); + } + + CleanupStack::PopAndDestroy(&fsSession); + } + +LOCAL_C void doMainL() + { + // allocate a gConsole + gConsole = Console::NewL(APPLICATIONNAME, TSize(KConsFullScreen, KConsFullScreen)); + CleanupStack::PushL(gConsole); + + // call main routine + MainL(); + + CleanupStack::PopAndDestroy(gConsole); + } + +TInt E32Main() + { + __UHEAP_MARK; + + // set up trap cleanup framework + CTrapCleanup* theCleanup = CTrapCleanup::New(); + + // call main routine and trap any exceptions + TRAPD(ret,doMainL()); + if(ret != KErrNone && gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + + // clean up when finished + delete theCleanup; + + __UHEAP_MARKEND; + + // Convert the boolean idea of "success" into the customary process idea of errorlevel, where zero + // is success and anything else designates particular kinds of failure. Specific failure reasons aren't + // provided, so the caller should only look for process exit != 0 to mean failure, and then examine the + // log to see what failed. + return !gProcessingSuccessful; + } + + +TInt ParseCommandLineL(TBool &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut, TDes &aInPref) +/** Parse the command line for any overriding settings from exe command line + +@param bDebugOn Wether to output debug messages to the log file using CFileDump::Dbg(TPtrC text, ...) +@param bOverWrite Determines whether to append to or erase any existing databases +@param bForceXMLProcessing Determines if invalid table entry links will be allowed +@param fIn Path and filename of the configuration database file +@param fOut Filename of the file to send logging too +@return ETrue if Successful else EFalse +*/ + { + TInt valid = EFalse; + CCommandLineArguments *pCmd; + pCmd = CCommandLineArguments::NewL(); + CleanupStack::PushL(pCmd); + + // set defaults + aIn = XML_TARGET; + aOut = LOG_TARGET; + aInPref = KMeshPrefaceFile; + + // Flags for encountering the specification + // of an input and an output file + TBool bInFound = EFalse; + TBool bOutFound = EFalse; + TBool bDatabaseSpecified = EFalse; + + //By default delete old database + aOverWrite = ETrue; + + if (pCmd) + { + TBuf arg; + + // check all arguments for switches + TInt i = 0; + while( ++i < pCmd->Count() ) + { + arg = pCmd->Arg(i); + arg.UpperCase(); + + // CED will report all the failures on the end, unlike success in all the cases except missing cfg file + // Switch introduced because of high impact on test results and to avoid BC break + if ( arg.FindF(_L("-V")) != KErrNotFound ) + { + gValidityChecking = ETrue; + continue; + } + + //Display help + if ( arg.FindF(_L("-H")) != KErrNotFound ) + { + HelpDump(); + CleanupStack::Pop(pCmd); + delete pCmd; + return valid; + } + + // Append database switch + if ( arg.FindF(_L("-A")) != KErrNotFound ) + { + aOverWrite = EFalse; + continue; + } + + // Debug switch + if ( arg.FindF(_L("-D")) != KErrNotFound ) + { + aDebugOn = ETrue; + continue; + } + + // Debug switch + if ( arg.FindF(_L("-M")) != KErrNotFound ) + { + aInPref = pCmd->Arg(++i); + continue; + } + + // Presence of invalid table entry links + // will not cause an error + if ( arg.FindF(_L("-F")) != KErrNotFound ) + { + aForceXMLProcessing = ETrue; + continue; + } + + // Specification of an input file + if ( arg.FindF(_L("-I")) != KErrNotFound ) + { + if( i != pCmd->Count()-1 ) + { + aIn = pCmd->Arg(++i); + bInFound = ETrue; + continue; + } + else + { + gConsole->Printf(_L("Argument missing after '-i' switch\n")); +#ifndef __TOOLS2__ + gConsole->Printf(_L("\nPress any key to finish")); + gConsole->Getch(); +#endif + CleanupStack::Pop(pCmd); + delete pCmd; + return valid; + } + } + // Specification of an output file + if ( arg.FindF(_L("-O")) != KErrNotFound ) + { + if( i != pCmd->Count()-1 ) + { + aOut = pCmd->Arg(++i); + bOutFound = ETrue; + continue; + } + else + gConsole->Printf(_L("Argument missing after '-o' switch\n")); +#ifndef __TOOLS2__ + gConsole->Printf(_L("\nPress any key to finish")); + gConsole->Getch(); +#endif + CleanupStack::Pop(pCmd); + delete pCmd; + return valid; + } +#ifdef __TOOLS2__ + // Specification of the database binary version + // This must be specified on the tools2 platform. + TBuf<16> databaseVersion; + + if ( arg.FindF(_L("-B")) != KErrNotFound ) + { + if( i != pCmd->Count()-1 ) + { + databaseVersion = pCmd->Arg(++i); + if(databaseVersion.Compare(SUPPORTED_OS) == 0) + { + bDatabaseSpecified = ETrue; + continue; + } + else + { + gConsole->Printf(_L("O/S version '%S' is not supported by this version of CED"), &databaseVersion); + CleanupStack::Pop(pCmd); + delete pCmd; + return valid; + } + } + else + { + gConsole->Printf(_L("Argument missing after '-b' switch")); + CleanupStack::Pop(pCmd); + delete pCmd; + return valid; + } + } +#endif + // No flag is supplied: first file encountered is the input + // file and the following one is the output file + + if ( !bInFound ) + { + aIn = pCmd->Arg(i); + bInFound = ETrue; + continue; + } + if ( !bOutFound ) + { + aOut = pCmd->Arg(i); + bOutFound = ETrue; + continue; + } + } + + if (aIn.Length() > 0) + valid = ETrue; + + //If here then no prefered config file has been specified. + //Find default input file + if ( !bInFound ) + { + RFs fs; + fs.Connect(); + CleanupClosePushL(fs); + TUint dummy; + + if(fs.Att(XML_TARGET,dummy)==KErrNone) + { + aIn = XML_TARGET; + } + else if(fs.Att(CFG_TARGET,dummy)==KErrNone) + { + aIn = CFG_TARGET; + } + else + { + gConsole->Printf(_L("No configuration files found please specify a .cfg or .xml file\n")); +#ifndef __TOOLS2__ + gConsole->Printf(_L("\nPress any key to finish")); + gConsole->Getch(); +#endif + valid=EFalse; + } + CleanupStack::PopAndDestroy(&fs); + } + +#ifdef __TOOLS2__ + if ( !bDatabaseSpecified ) + { + gConsole->Printf(_L("Must specify the '-b' switch\n")); + valid=EFalse; + } +#endif + CleanupStack::Pop(pCmd); + delete pCmd; + } + + return valid; +} + +void HelpDump() +/** +Prints basic help information to the emulator window including command switches +*/ + { + gConsole->Printf(_L("Creates/Updates a Comms Database using an input file")); + gConsole->Printf(_L("\n\nCED [-a] [-d] [-f] [-i [path]filename] [-o [path]filename]")); + gConsole->Printf(_L("\n\n-a\tAppends the data read from the input file to the existing Comms Database.")); + gConsole->Printf(_L("\n-d\tSwitches debug mode on giving more data in the log file.")); + gConsole->Printf(_L("\n-f\tAllows invalid data entries. Primarily used for testing.")); +#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY + gConsole->Printf(_L("\n-m Specifies the default mesh configuration file to CED. Defaults to reading '%S'."), &KMeshPrefaceFile); +#endif + gConsole->Printf(_L("\n-v Enables validation of the configuration data while writing to the database.")); + gConsole->Printf(_L("\n-i Specifies an input file to CED. Must be either *.xml or *.cfg. Defaults to reading '%S' or '%S'."), &CFG_TARGET, &XML_TARGET); + gConsole->Printf(_L("\n-o Specifies an output file for CED to log to. Defaults to '%S'."), &LOG_TARGET); +#ifdef __TOOLS2__ + gConsole->Printf(_L("\n-b Specifies the binary output should be compatible with this Symbian OS version.\n")); +#endif +#ifndef __TOOLS2__ + gConsole->Printf(_L("\nPress any key to finish")); + gConsole->Getch(); +#endif + } + +TInt ParseArgument(TBool &aDebugOn, TBool &aOverWrite, TBool &aForceXMLProcessing, TDes &aIn, TDes &aOut) +/** Parse the command line for any overriding settings from DLL call + +@param bDebugOn Wether to output debug messages to the log file using CFileDump::Dbg(TPtrC text, ...) +@param bOverWrite Determines whether to append to or erase any existing databases +@param bForceXMLProcessing Determines if invalid table entry links will be allowed +@param fIn Path and filename of the configuration database file +@param fOut Filename of the file to send logging too +@return ETrue if Successful else EFalse +*/ + { + // use Tlex to decode the cmd line + TLex lex(gArgumentLine->Des()); + + // By default delete old database + aOverWrite = ETrue; + + // get the input file + aIn=lex.NextToken(); + if ( aIn.Length() == 0 ) + aIn = XML_TARGET; + + // get the output file + aOut = lex.NextToken(); + if ( aOut.Length() == 0 ) // if valid potential + aOut = LOG_TARGET; + + // get the debug switch parameters + if ( gArgumentLine->FindF(_L("-D")) != KErrNotFound ) + aDebugOn = ETrue; + + if ( gArgumentLine->FindF(_L("-O")) != KErrNotFound ) + aDebugOn = ETrue; + + // append switch + if ( gArgumentLine->FindF(_L("-A")) != KErrNotFound ) + aOverWrite = EFalse; + + // force processing of XML file even in the + // presence of invalid table entry links + if ( gArgumentLine->FindF(_L("-F")) != KErrNotFound ) + aForceXMLProcessing = ETrue; + + delete gArgumentLine; + + return ETrue; + } + +LOCAL_C TInt ProcessCfgDataL(TDesC &aTable,const TInt &aIndex) +/** Process old style .cfg database file + +@param aTable Name of the entry being processed +@param aIndex Counted table number being processed +@return ETrue if Successful else EFalse +*/ + { + TInt recordsInserted(0); + TInt fatalErr(KErrNone); + TBool firstRec(ETrue); + TInt valid(KErrNotReady); + + _LIT(KConnectionPrefTableName, "ConnectionPreferences"); + while(fatalErr == KErrNone && (firstRec || gCfg.StepToNextBlock())) + { + if (!firstRec) + { + gMsg->Msg(_L(" ")); // blank line between records + } + + if(gDB->CommitIndividualRecords()) + { + gDB->CreateOrInsertRecordL(firstRec? DBAccess::ECreateNew: DBAccess::ECreateInsert,elementIdArray[aIndex], 0); + } + firstRec = EFalse; + + TInt value = recordsInserted + 1; + TPtrC idText; + _LIT(KCommDbIDTag, "COMMDB_ID "); + valid = gCfg.GetSetting(KCommDbIDTag, idText); + if (valid == KErrNone) + { + TLex lex(idText); + if(lex.Val(value) != KErrNone) + { + gMsg->Dbg(_L("Missing COMMDB_ID - defaulting to record count")); + } + } + gDB->CreateOrInsertRecordL(DBAccess::EInsert, 0, value); + + // find out how many fields we are expecting in this insert + TPtrC result = NO_MORE_RECORDS; + TInt iValue; + valid = gCfg.GetSetting(FIELD_COUNT, result); + if (valid == KErrNone) + { + TLex iResult = result; + iValue = 0; + if (iResult.Val(iValue) == KErrNone) + gDB->SetFieldCount(iValue); + } + + //Write column info + TInt err = SetColumnDetailsL(aIndex, recordsInserted + 1); + iValue = gDB->GetFieldCount(); //If Recordname was not supplied, SetColumnDetailsL fn would have added the misisng name..so refresh he actual field count + + if(err == KErrNone) + { + if(gDB->GetActualFieldCount() != iValue) + { + gMsg->Msg(_L(" ERR Table %S Expected [%d] values, read [%d].Field count mismatch!"), &aTable, iValue, gDB->GetActualFieldCount()); + gDB->RemoveCurrentRecord(); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + continue; // it's not fatal + } + + if(aTable.Compare(KConnectionPrefTableName) == 0) + { + CMDBRecordBase* dontDelete = gDB->GetCurrentRecord(); + if(!gDB->IsConnectionPrefValid(*(static_cast(dontDelete)))) + { + fatalErr = KErrArgument; // or should we continue? + } + } + if(gDB->CommitIndividualRecords()) + { + err = gDB->CommitChanges(); + } + if(err != KErrNone) + { + gMsg->Msg(_L("Error %d inserting record #%d to %S"), err, recordsInserted + 1, &aTable); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + } + else + { + recordsInserted++; + } + } + else if(err != KErrCancel) //to ignore cancels called by ced itself, used to process unused entries produced by older ceddumpers + { + gMsg->Msg(_L("Error %d inserting record #%d to %S"), err, recordsInserted + 1, &aTable); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + + gDB->RemoveRecord(recordsInserted); + //fatalErr = err; + } + } + + return ((fatalErr == KErrNone)?recordsInserted:fatalErr); + } + +TInt DoCfgTemplateL(TDesC &aTable, const TInt &aIndex) +/** +Applying the templates + + @param table A reference to a descriptor containing the name of a table + @param index Index in the Table + @return ETrue if Successful else EFalse + */ + { + // look for template and load it + if (!gCfg.OpenTemplateBlock(aTable)) + return EFalse; + + DisplayMessage(_L("Processing template"), ETrue); + gDB->RecordIsTemplate(ETrue); + + TInt templateRecordsInserted = ProcessCfgDataL(aTable,aIndex); + + if (templateRecordsInserted > 0) + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("[%d] Template record(s) successfully inserted"), templateRecordsInserted); + } + else + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("Insert record failed Err:[%d]"), templateRecordsInserted); + } + + return templateRecordsInserted; + } + +TInt DoCfgInsertsL(TDesC &aTable, const TInt &aIndex) +/** +Runs through all the steps involved in applying an insert to a particular table. + + @param table A reference to a descriptor containing the name of a table + @param index Index in the Table + @return ETrue if Successful else EFalse + */ + { + + // look for any inserts and load the first one + if (!gCfg.OpenAddBlock(aTable)) + return EFalse; + + DisplayMessage(_L("Processing inserts"), ETrue); + gDB->RecordIsTemplate(EFalse); + + TInt recordsInserted = ProcessCfgDataL(aTable,aIndex); + + if (recordsInserted >= 0) + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("[%d] record(s) successfully inserted"), recordsInserted); + } + else + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("Insert record failed Err:[%d]"), recordsInserted); + } + return recordsInserted; + } + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS +/** +Loops through the table of deprecated columns/parameters and gives an information +to the user question column/parameter is deprecated. + + @param aIndex Index in the elementIdArray Table + @param aColumnName Name of the questioned column/parameter +*/ +void VerifyDeprecatedFields(TInt aIndex, TPtrC& aColumnName) + { + TBuf tempColumn; + TInt i = 0; + if (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord + || elementIdArray[aIndex] == KCDTIdIncomingGprsRecord ) + { + tempColumn = DeprecParamArray[i]; + while(tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0) + { + if (aColumnName.Compare(tempColumn) == 0 ) + { + gMsg->Msg(_L(" Warning - Use of deprecated parameter [%S]"), &aColumnName); + gDeprecatedFields = ETrue; + } + tempColumn = DeprecParamArray[++i]; + } + } + } +#endif +// SYMBIAN_NETWORKING_3GPPDEFAULTQOS + +TBool IsGprsGatewayField(TInt aIndex, const TPtrC& aColumnName) +/** +Determine if a field being processed is the IpGateway field in OutgoingGPRS table + +@param aIndex index into elementIdArray[] for identifying table +@param aColumnName descriptor identifying the field +*/ + { + return (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord && aColumnName.Compare(TPtrC(GPRS_IP_GATEWAY)) == 0); + } + +TInt SetupIpGatewayFieldDefaultL(TInt aIndex) +/** +Setup a safe default value for the IpGateway field in OutgoingGPRS tables. If a value has not +been specified in the CFG or XML file, then it would ordinarily default to 0.0.0.0. However, +this value will mean that the TCP/IP stack will not setup a default route. Consequently, +we must setup a safe default of 0.0.0.1. + +@param aIndex index into elementIdArray[] for identifying the table +*/ + { + if (elementIdArray[aIndex] == KCDTIdOutgoingGprsRecord) // only for OutgoingGPRS table records ! + { + // Only setup IpGateway field if it is not already present in the OutgoingGPRS template record. + if (!gDB->TemplateFieldPresentL(KCDTIdOutgoingGprsRecord | KCDTIdWCDMAIPGateway)) + { + TPtrC setting; + TPtrC column; + _LIT(KGprsIpGateway, "0.0.0.1"); + setting.Set(KGprsIpGateway()); + column.Set(TPtrC(GPRS_IP_GATEWAY)); + gMsg->Msg(_L(" NOTE [%S] set to default value of %S"), &column, &setting); + TInt ret = gDB->SetColAndAttribL(column, setting); + gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the gateway field + return ret; + } + } + return KErrNone; + } + +void HandleConnPrefWithoutDefaultIap() +/** +Handle special case of ConnPref record without default IAP set (empty db use case) +*/ + { + if(gDB->GetCurrentRecord()->TableId() == KCDTIdConnectionPrefsRecord) + { + CCDConnectionPrefsRecord* connPref = static_cast(gDB->GetCurrentRecord()); + if(!(connPref->iDefaultIAP.ElementId() & KCDChangedFlag)) + { + connPref->iDefaultIAP = 0; + } + } + } + +TInt SetColumnDetailsL(TInt aIndex, TInt aRecordCount) +/** +Loops through all the columns of a particular table. If any of the columns match the setting +in the log file, it is stored, along with the value to write into this field. + +@param aTable A reference to a descriptor containing the name of a table +@param aIndex Index in the Table +@param aRecCnt Index of the Record in the table +@return ETrue if Successful else EFalse +*/ + { + + static TBuf tempColumn; + TPtrC column; + TPtrC setting; + TInt valid(KErrNone); + TInt i = 0; + tempColumn = ColumnArray[aIndex][i]; + TInt fieldValueRead(KErrNone); + TBool gprsGatewayFieldIsSet = EFalse; // whether IpGateway field in OutgoingGPRS table record has been set + + // loop through columns of table + while( (valid==KErrNone) && (tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0)) + { + // get a column from the config file + gMsg->Dbg(_L(" Looking for [%S]"), &tempColumn); + // set the read value to the column + fieldValueRead = gCfg.GetSetting(tempColumn,setting); + if(fieldValueRead == KErrNone) + { + column.Set(tempColumn); + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS + VerifyDeprecatedFields(aIndex, column); +#endif +// SYMBIAN_NETWORKING_3GPPDEFAULTQOS + + // Determine whether the GPRS IP Gateway field has been set or not + if (IsGprsGatewayField(aIndex, column)) + { + gprsGatewayFieldIsSet = ETrue; + } + + if( (tempColumn.Compare(TPtrC(COMMDB_NAME)) == 0) && + (setting.Compare(TPtrC(COMMDB_UNUSED_NAME)) == 0) + ) + { + //this record is not valid,,,remove + gDB->RemoveCurrentRecord(); + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + return KErrCancel; + } + + valid = gDB->SetColAndAttribL(column,setting); + } + // decrement the field count for fields simply left blank + else if(fieldValueRead == KErrArgument) + { + gDB->SetFieldCount(gDB->GetFieldCount() - 1); + } + i++; + tempColumn = ColumnArray[aIndex][i]; + } + + //if the record is not empty and also has its name field or fieldvalue missing, set a default name, using the + //record id if set, else simply the record count + //Only do this if not entering a Template Record + if(gDB->GetCurrentRecord()->RecordId() != KCDDefaultRecord && + ((!gDB->IsNameSet() && gDB->GetActualFieldCount()) || + (!gDB->IsNameSet() && KErrArgument)) ) + { + _LIT(KNameTemplate, "DefaultRecordName-%d"); + TBuf recordName; + TInt recId = gDB->GetCurrentRecord()->RecordId(); + recordName.Format(KNameTemplate, recId? recId: aRecordCount); + column.Set(TPtrC(COMMDB_NAME)); + setting.Set(TPtrC(recordName)); + valid = gDB->SetColAndAttribL(column,setting); + gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the missing name + } + + if (valid == KErrNone && !gprsGatewayFieldIsSet) + { + // If required, setup a suitable default value for IpGateway field in OutgoingGPRS table records + valid = SetupIpGatewayFieldDefaultL(aIndex); + } + + // Handle special case of ConnPref record without default IAP set (empty db use case) + HandleConnPrefWithoutDefaultIap(); + + return valid; + } + +LOCAL_C TInt ProcessXmlDataL(TBool aIsTemplate,const TInt &aIndex) +/** Runs through all the steps involved in applying an insert to a particular table + (for the XML configuration file) + +@param aIsTemplate Wether the entry being processed is a template or add entry +@param aIndex Counted table number being processed +@return Number of successfully inserted records +*/ + { + TBuf xmlTableName = xmlTableArray[aIndex]; + xmlTableName.Append(_L("Table")); + + // look for template + TInt startIndex = gXML->GetStartingIndex(xmlTableName); + TInt lastIndex = gXML->GetLastIndex(xmlTableName); + + if(startIndex == -1 || lastIndex == -1) + return EFalse; + + if(aIsTemplate) + { + DisplayMessage(_L("Processing template"), ETrue); + gDB->RecordIsTemplate(ETrue); + } + else + { + DisplayMessage(_L("Processing inserts"), ETrue); + gDB->RecordIsTemplate(EFalse); + } + + TInt recordsInserted(0); + TInt ret(KErrNone); + + for(TInt iEntryIndex = startIndex; iEntryIndex <= lastIndex; iEntryIndex++) + { + if(aIsTemplate) + { + if(gXML->GetOperation(iEntryIndex).Compare(_L("template")) != 0) + { + continue; + } + } + else + { + if(gXML->GetOperation(iEntryIndex).Compare(_L("add")) != 0) + { + continue; + } + } + + gMsg->Msg(_L("Record Number: #[%d]"), gXML->GetElementRecordID(iEntryIndex)); + if(gDB->CommitIndividualRecords()) + { + gDB->CreateOrInsertRecordL(iEntryIndex == startIndex? DBAccess::ECreateNew: DBAccess::ECreateInsert,elementIdArray[aIndex], 0); + } + + //!!!!!!!!!!!!!!!!!the record ID of the given xmlDBentry should be read here... + + //gDB->CreateOrInsertRecordL(DBAccess::EInsert,0,0); + + gDB->CreateOrInsertRecordL(DBAccess::EInsert,0,gXML->GetElementRecordID(iEntryIndex)); + + // find out how many fields we are expecting in this insert + TInt iValue = gXML->GetEntryNumberParameters(iEntryIndex); + gDB->SetFieldCount(iValue); + + //Write column info + ret = SetXMLColumnDetailsL(iEntryIndex,aIndex,iEntryIndex - startIndex + 1); + /*if(ret != KErrNone) + return ret;*/ + + if(gDB->CommitIndividualRecords()) + { + ret = gDB->CommitChanges(); + } + if(ret != KErrNone) + { + gMsg->Msg(_L("Error %d inserting record #%d to %S"), ret, iEntryIndex - startIndex + 1, &xmlTableName); + + if (gValidityChecking) + { + gProcessingSuccessful = EFalse; + } + + gDB->RemoveRecord(gXML->GetElementRecordID(iEntryIndex)-1); + + } + else + { + recordsInserted++; + } + } + + if (recordsInserted) + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L("[%d] record(s) successfully inserted"), recordsInserted); + } + + return recordsInserted; + } + + +TInt DoXMLInsertsL(const TInt &aIndex) +/** +Runs through all the steps involved in applying an insert to a particular table. + +@param index Index in the Table +@return Number of successfully inserted records +*/ + { + return (ProcessXmlDataL(EFalse,aIndex)); + } + +TInt DoXMLTemplateL(const TInt &aIndex) +/** +Applying the templates (for the XML configuration file) + +@param index Index in the Table +@return Number of successfully inserted records +*/ + { + return (ProcessXmlDataL(ETrue,aIndex)); + } + +TInt SetXMLColumnDetailsL(TInt aEntryIndex, TInt aIndex, TInt aRecCount) +/** Loops through all the columns of a particular table. If any of the columns match the setting + in the log file, it is stored, along with the value to write into this field. + +@param aEntryIndex +@param aIndex +@param aRecCount +@return True if successful else false +*/ + { + static TBuf tempColumn; + TPtrC setting; + TPtrC column; + TInt valid(KErrNone); + TInt i = 0; + TBool gprsGatewayFieldIsSet = EFalse; // whether IpGateway field in OutgoingGPRS table record has been set + + tempColumn = ColumnArray[aIndex][i]; + + + // loop through columns of table + while( (valid==KErrNone) && tempColumn.Compare(TPtrC(NO_MORE_RECORDS)) != 0) + { + // get a column from the config file + gMsg->Dbg(_L(" Looking for [%S]"), &tempColumn); + + if (gXML->GetSetting(aEntryIndex, tempColumn, setting)) + { + column.Set(ColumnArray[aIndex][i]); + valid = gDB->SetColAndAttribL(column,setting); + +#ifdef SYMBIAN_NETWORKING_3GPPDEFAULTQOS + VerifyDeprecatedFields(aIndex, column); +#endif +// SYMBIAN_NETWORKING_3GPPDEFAULTQOS + + // Determine whether the GPRS IP Gateway field has been set or not + if (IsGprsGatewayField(aIndex, column)) + { + gprsGatewayFieldIsSet = ETrue; + } + } + i++; + tempColumn = ColumnArray[aIndex][i]; + } + + //if the record is not empty and also has its name missing, set a default name + //only do this if not processing a template record + if(!gDB->IsNameSet() && + gDB->GetActualFieldCount() && + gDB->GetCurrentRecord()->RecordId() != KCDDefaultRecord) + { + _LIT(KNameTemplate, "DefaultRecordName-%d"); + TBuf recordName; + recordName.Format(KNameTemplate, aRecCount); + column.Set(TPtrC(COMMDB_NAME)); + setting.Set(TPtrC(recordName)); + valid = gDB->SetColAndAttribL(column,setting); + gDB->SetFieldCount(gDB->GetFieldCount() + 1); //field count increment by one because we added the missing name + } + + if (valid == KErrNone && !gprsGatewayFieldIsSet) + { + // If required, setup a suitable default value for IpGateway field in OutgoingGPRS table records + valid = SetupIpGatewayFieldDefaultL(aIndex); + } + + // Handle special case of ConnPref record without default IAP set (empty db use case) + HandleConnPrefWithoutDefaultIap(); + + return valid; + } + +void DisplayMessage(TPtrC aMessage, TInt aJustTheMessage) +/** +Writes a message to the log file, along with any associated error. + +@param aMessage Message to be written +@param aJustTheMessage Output only the plain message to the log file +*/ + { + if (aJustTheMessage) + { + gMsg->Msg(_L("%S"), &aMessage); + } + else + { + if (gDB->ErrorCode() != KErrAlreadyExists && gDB->ErrorCode() != E_ALREADYEXISTS) + gMsg->Msg(_L(" ")); + + gMsg->Msg(_L(" ")); + + if (gDB->ErrorCode()) + { + static TBuf errorText; + errorText = gDB->ErrorText(); + + if (gDB->ErrorCode() == KErrAlreadyExists || gDB->ErrorCode() == E_ALREADYEXISTS) + gMsg->Msg(_L("WARN: %S failed: %S [%d]"), &aMessage, &errorText, gDB->ErrorCode()); + else if (gDB->ErrorCode() < 0) + gMsg->Msg(_L("ERR: %S failed: %S [%d]"), &aMessage, &errorText, gDB->ErrorCode()); + else + gMsg->Msg(_L("ERR: %S failed: %S"), &aMessage, &errorText); + } + else + { + gMsg->Msg(_L("ERR: %S failed"), &aMessage); + } + + // don't fail when the record is there already + if (gDB->ErrorCode() != KErrAlreadyExists && gDB->ErrorCode() != E_ALREADYEXISTS) + { + gMsg->Msg(_L(" ")); + gMsg->Msg(_L(" ")); + gProcessingSuccessful = EFalse; + } + } + } + + +#ifndef __TOOLS2__ +EXPORT_C TInt NewApplicationL(const TDesC& aText) +/** +entry point used in WINS when ced is build as a exedll + +@param Text Command line argument +*/ + { + // save the command line info + gArgumentLine=aText.AllocL(); + + // record that ced is running as a exe dll + gIsExeDLL = ETrue; + + // call main + return E32Main(); + } +#endif + +