TEST(TStr, LeftOfRightOf) { TStr Str = "abcdef"; TStr Empty = ""; EXPECT_EQ(Str.LeftOf('d'), "abc"); EXPECT_EQ(Str.RightOf('c'), "def"); EXPECT_EQ(Str.LeftOf('a'), ""); EXPECT_EQ(Empty.RightOf('c'), ""); // edge cases EXPECT_EQ(Str.RightOf('f'), ""); EXPECT_EQ(Empty.LeftOf('d'), ""); TStr Str2 = "abcdefabcdef"; EXPECT_EQ(Str2.LeftOfLast('d'), "abcdefabc"); EXPECT_EQ(Str2.RightOfLast('c'), "def"); EXPECT_EQ(Empty.LeftOfLast('d'), ""); EXPECT_EQ(Empty.RightOfLast('c'), ""); // edge cases Str2 = "xabcdefabcdef"; EXPECT_EQ(Str2.LeftOfLast('x'), ""); EXPECT_EQ(Str2.RightOfLast('f'), ""); }
int main(int argc, char* argv[]) { #ifndef NDEBUG // report we are running with all Asserts turned on printf("*** Running in debug mode ***\n"); #endif try { // initialize QMiner environment TQm::TEnv::Init(); // create app environment Env = TEnv(argc, argv, TNotify::StdNotify); Env.SetNoLine(); // making output prettier // command line parameters Env.PrepArgs("QMiner " + TQm::TEnv::GetVersion(), 0); // read the action const bool ConfigP = Env.IsArgStr("config"); const bool CreateP = Env.IsArgStr("create"); const bool StartP = Env.IsArgStr("start"); const bool StopP = Env.IsArgStr("stop"); //const bool ReloadP = Env.IsArgStr("reload"); const bool DebugP = Env.IsArgStr("debug"); // stop if no action given const bool ActionP = (ConfigP || CreateP || StartP || StopP /*|| ReloadP*/ || DebugP); // provide basic instruction when no action given if (!ActionP) { printf("\n"); printf("Usage: qm ACTION [OPTION]...\n"); printf("\n"); printf("Actions: config, create, start, stop, reload, debug\n"); } else { Env.SetSilent(); } // configuration file const TStr ConfFNm = Env.GetIfArgPrefixStr("-conf=", "qm.conf", "Configration file"); // read config-specific parameters if (!Env.IsSilent()) { printf("\nConfiguration parameters:\n"); } const int PortN = Env.GetIfArgPrefixInt("-port=", 8080, "Port number"); const int CacheSizeMB = Env.GetIfArgPrefixInt("-cache=", 1024, "Cache size"); const bool OverwriteP = Env.IsArgStr("-overwrite", "Overwrite existing configuration file"); // read create-specific parameters if (!Env.IsSilent()) { printf("\nCreate parameters:\n"); } const TStr SchemaFNm = Env.GetIfArgPrefixStr("-def=", "", "Store definition file"); // read start-specific parameters if (!Env.IsSilent()) { printf("\nStart parameters:\n"); } const bool RdOnlyP = Env.IsArgStr("-rdonly", "Open database in Read-only mode"); const bool NoLoopP = Env.IsArgStr("-noserver", "Do not start server after script execution"); TStr OnlyScriptNm = Env.GetIfArgPrefixStr("-script=", "", "Only run this script"); // read stop-specific parameters if (!Env.IsSilent()) { printf("\nStop parameters:\n"); } const int ReturnCode = Env.GetIfArgPrefixInt("-return=", 0, "Return code"); // read reload-specific parameters //if (!Env.IsSilent()) { printf("\nReload parameters:\n"); } //TStrV ReloadNmV = Env.GetIfArgPrefixStrV("-name=", "Script name"); // read debug request parameters if (!Env.IsSilent()) { printf("\nDebug parameters:\n"); } TStr DebugFNm = Env.GetIfArgPrefixStr("-prefix=", "Debug-", "Prefix of debug output files"); TStrV DebugTaskV = Env.GetIfArgPrefixStrV("-task=", "Debug tasks [indexvoc, index, stores, <store>, <store>_ALL]"); const int JsStatRate = Env.GetIfArgPrefixInt("-jsmemstat=", 0, "Frequency of JavaScript memory statistics"); // read logging specific parameters if (!Env.IsSilent()) { printf("\nLogging parameters:\n"); } TStr LogFPath = Env.GetIfArgPrefixStr("-log=", "std", "Log Folder (std for standard output, null for silent)"); const bool Verbose = Env.IsArgStr("-v", "Verbose output (used for debugging)"); if (!Env.IsSilent()) { printf("\nPre-run file:\n"); } const TStr PreRunFNm = Env.GetIfArgPrefixStr("-prerun=", "", "Pre-run file name"); if (!Env.IsSilent()) { printf("\n"); } // execute pre-run command when provided if (!PreRunFNm.Empty()) { const int ReturnCd = system(PreRunFNm.CStr()); if (ReturnCd != 0) { TQm::ErrorLog(TStr::Fmt("Error running prerun script: %d", ReturnCd)); } } // stop if no action specified if (!ActionP) { return 0; } // initialize notifier TQm::TEnv::InitLogger(Verbose ? 2 : 1, LogFPath, true); printf("\n"); // Create directory structure with basic qm.conf file if (ConfigP) { // check so we don't overwrite any existing configuration file if (TFile::Exists(ConfFNm) && ! OverwriteP) { TQm::InfoLog("Configuration file already exists (" + ConfFNm + ")"); TQm::InfoLog("Use -overwrite to force overwrite"); return 2; } // create configuration file PJsonVal ConfigVal = TJsonVal::NewObj(); ConfigVal->AddToObj("port", PortN); PJsonVal CacheVal = TJsonVal::NewObj(); CacheVal->AddToObj("index", CacheSizeMB); CacheVal->AddToObj("store", CacheSizeMB); ConfigVal->AddToObj("cache", CacheVal); // save configuration file ConfigVal->SaveStr().SaveTxt(ConfFNm); // make folders if needed if (!TFile::Exists("db")) { TDir::GenDir("db"); } if (!TFile::Exists("src")) { TDir::GenDir("src"); } if (!TFile::Exists("src/lib")) { TDir::GenDir("src/lib"); } if (!TFile::Exists("sandbox")) { TDir::GenDir("sandbox"); } } // parse configuration file TQmParam Param(ConfFNm); // prepare lock TFileLock Lock(Param.LockFNm); // Initialize empty database if (CreateP) { // do not mess with folders with existing running qminer instance Lock.Lock(); { // parse schema (if no given, create an empty array) PJsonVal SchemaVal = SchemaFNm.Empty() ? TJsonVal::NewArr() : TJsonVal::GetValFromStr(TStr::LoadTxt(SchemaFNm)); // initialize base TQm::PBase Base = TQm::TStorage::NewBase(Param.DbFPath, SchemaVal, 16, 16); // save base TQm::TStorage::SaveBase(Base); } // remove lock Lock.Unlock(); } // Start QMiner engine if (StartP) { // do not mess with folders with running qminer instance Lock.Lock(); // load database and start the server { // resolve access type TFAccess FAccess = RdOnlyP ? faRdOnly : faUpdate; // load base TQm::PBase Base = TQm::TStorage::LoadBase(Param.DbFPath, FAccess, Param.IndexCacheSize, Param.DefStoreCacheSize, Param.StoreNmCacheSizeH); // initialize javascript contexts TQm::TJsUtil::SetObjStatRate(JsStatRate); TVec<TQm::PScript> ScriptV; InitJs(Param, Base, OnlyScriptNm, ScriptV); // start server if (!NoLoopP) { // prepare server functions TSAppSrvFunV SrvFunV; // used to stop the server SrvFunV.Add(TSASFunExit::New()); // admin webservices TQm::TSrvFun::RegDefFun(Base, SrvFunV); // initialize static content serving thingies for (int WwwRootN = 0; WwwRootN < Param.WwwRootV.Len(); WwwRootN++) { const TStrPr& WwwRoot = Param.WwwRootV[WwwRootN]; const TStr& UrlPath = WwwRoot.Val1, FPath = WwwRoot.Val2; TQm::TEnv::Logger->OnStatusFmt("Registering '%s' at '/%s/'", FPath.CStr(), UrlPath.CStr()); SrvFunV.Add(TSASFunFPath::New(UrlPath, FPath)); } // register admin services SrvFunV.Add(TQm::TJsAdminSrvFun::New(ScriptV, "qm_status")); // register javascript contexts for (int ScriptN = 0; ScriptN < ScriptV.Len(); ScriptN++) { // register server function ScriptV[ScriptN]->RegSrvFun(SrvFunV); } // start server PWebSrv WebSrv = TSAppSrv::New(Param.PortN, SrvFunV, TQm::TEnv::Logger, true, true); // report we started TQm::TEnv::Logger->OnStatusFmt("Server started on port %d", Param.PortN); // wait for the end TLoop::Run(); } // save base TQm::TStorage::SaveBase(Base); } // remove lock Lock.Unlock(); } // Stop QMiner engine if (StopP) { ExecUrl(TStr::Fmt("http://127.0.0.1:%d/exit?return=%d", Param.PortN, ReturnCode), "Server stop procedure initiated", "Error stopping server: "); } // Reload QMiner script //if (ReloadP) { // for (int ReloadNmN = 0; ReloadNmN < ReloadNmV.Len(); ReloadNmN++) { // TStr ScriptNm = ReloadNmV[ReloadNmN]; // ExecUrl(TStr::Fmt("http://127.0.0.1:%d/%s/admin/reload", Param.PortN, ScriptNm.CStr()), // "Initializing reload of script '" + ScriptNm + "'", // "Error reloading script '" + ScriptNm + "': "); // } //} // Debug dumps of database and index if (DebugP) { // do not mess with folders with existing running qminer instance Lock.Lock(); { // load base TQm::PBase Base = TQm::TStorage::LoadBase(Param.DbFPath, faRdOnly, Param.IndexCacheSize, Param.DefStoreCacheSize, Param.StoreNmCacheSizeH); // go over task lists and prepare outputs for (int TaskN = 0; TaskN < DebugTaskV.Len(); TaskN++) { TStr Task = DebugTaskV[TaskN]; if (Task == "index") { Base->PrintIndex(DebugFNm + "index.txt", true); } else if (Task == "indexvoc") { Base->PrintIndexVoc(DebugFNm + "indexvoc.txt"); } else if (Task == "stores") { Base->PrintStores(DebugFNm + "stores.txt"); } else if (Task.IsSuffix("_ALL")) { TStr StoreNm = Task.LeftOfLast('_'); Base->GetStoreByStoreNm(StoreNm)->PrintAll(Base, DebugFNm + Task + ".txt"); } else if (Base->IsStoreNm(Task)) { Base->GetStoreByStoreNm(Task)->PrintTypes(Base, DebugFNm + Task + ".txt"); } else { TQm::InfoLog("Unkown debug task '" + Task + "'"); } } } // remove lock Lock.Unlock(); } } catch (const PExcept& Except) { // GLib exception TQm::ErrorLog("Error: " + Except->GetMsgStr()); return 2; } catch (...) { // other exceptions TQm::ErrorLog("Unknown error"); return 1; } return TQm::TEnv::ReturnCode.Val; }