diff --git a/config/online_monitor.conf b/config/online_monitor.conf
new file mode 100644
index 0000000000000000000000000000000000000000..da29f68cc146abcbb4a0d24e82c23fbf880b1983
--- /dev/null
+++ b/config/online_monitor.conf
@@ -0,0 +1,10 @@
+# configuration for online monitoring
+
+host = clrlpc.jlab.org
+port = 11111
+etfile = /tmp/et_test
+modules = ${THIS_DIR}/esb_module.conf
+output = ${THIS_DIR}/../processed_data/online.root
+update_interval = 2000 # ms
+
+
diff --git a/include/utils.h b/include/utils.h
index 7f8fbfad76719d416a5065a7c24d4938320debe7..1d3f4d27e1d2520f4935dfd8bbeb3d3495c97ae3 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -114,9 +114,9 @@ std::vector<Module> read_modules(const std::string &path, bool verbose=false)
// module attributes
Module mod;
- mod.crate = conf.GetConfigValue("crate").Int();
- mod.slot = conf.GetConfigValue("slot").Int();
- mod.type = str2ModuleType(conf.GetConfigValue("type").c_str());
+ mod.crate = conf.Value("crate").Int();
+ mod.slot = conf.Value("slot").Int();
+ mod.type = str2ModuleType(conf.Value("type").c_str());
// channels
for (auto &sub : btext.blocks) {
diff --git a/online/monitor.cxx b/online/monitor.cxx
index 46af8c3c319636c18e962d713dc629c244573510..8a4c42f2d0a1aecbbd3342d6c7d3e0763017b882 100644
--- a/online/monitor.cxx
+++ b/online/monitor.cxx
@@ -17,7 +17,6 @@
#define FADC_BANK 3
-#define PROGRESS_COUNT 100
volatile sig_atomic_t term = 0;
@@ -309,19 +308,29 @@ void processEvent(const uint32_t *buf, int &count, TTree *tree, bool &init_tree,
}
}
-void monitor(const std::string &addr = "clrlpc", int port = 11111, const std::string &etfile = "/tmp/et_test",
- const std::string &opath = "processed_data/online.root",
- const std::string &module_conf = "config/esb_module.conf",
- int nev = -1)
+void monitor(const std::string &cpath = "config/online_monitor.conf")
{
- auto modules = read_modules(module_conf);
+ // read configuration
+ ConfigObject conf;
+ conf.ReadConfigFile(cpath);
+ auto host = conf.Value<std::string>("host", "clrlpc.jlab.org");
+ auto port = conf.Value<int>("port", 11111);
+ auto etfile = conf.Value<std::string>("etfile", "/tmp/et_test");
+ auto modconf = conf.Value<std::string>("modules", "config/esb_module.conf");
+ auto up_intvl = conf.Value<double>("update_interval", 5000);
+ auto outfile = conf.Value<std::string>("output", "processed_data/online.root");
+ auto nev = conf.Value<int>("number_events", -1);
+
+ // connect et
ETChannel et_chan(100, 100);
- if (et_chan.Connect(addr.c_str(), port, etfile.c_str(), "TCD_MONITOR") != ET_OK) {
+ if (et_chan.Connect(host.c_str(), port, etfile.c_str(), "TCD_MONITOR") != ET_OK) {
+ std::cout << fmt::format("Failed to connect to the et system {}:{}:{}, abort monitoring!", host, port, etfile)
+ << std::endl;
return;
}
+ et_chan.Open();
- auto *hfile = new TFile(opath.c_str(), "RECREATE", "MAPMT test results");
- auto tree = new TTree("EvTree", "Cherenkov Test Events");
+ auto modules = read_modules(modconf);
// set up branches and a container to be combined with the branches
std::unordered_map<std::string, BranchData> brdata;
for (auto &mod : modules) {
@@ -334,25 +343,34 @@ void monitor(const std::string &addr = "clrlpc", int port = 11111, const std::st
}
}
+ // root file and event tree
+ auto *hfile = new TFile(outfile.c_str(), "RECREATE", "MAPMT test results");
+ auto tree = new TTree("EvTree", "Cherenkov Test Events");
+
+ // display plots
auto dply = CreateMonitorDisplay("/online/latest/", 9100, tree);
dply->InitAll();
+
+ // timer
+ auto timer = std::chrono::steady_clock::now();
+
+ // start monitoring
int count = 0;
- bool init_tree = false;
int data_mode = -1;
- int status = ETChannel::READ_EMPTY;
- et_chan.Open();
- signal (SIGINT, handle_sig);
-
+ bool init_tree = false;
+ signal(SIGINT, handle_sig);
while (true) {
if (term > 0 || (nev > 0 && nev < count)) { break; }
- if (count % PROGRESS_COUNT == 0 && count > 0) {
- std::cout << "Read and processed events - " << count << std::endl;
+ auto now = std::chrono::steady_clock::now();
+ if (std::chrono::duration_cast<std::chrono::milliseconds>(now - timer).count() > up_intvl) {
+ timer = now;
+ std::cout << "Monitor update, processed events - " << count << std::endl;
dply->Process();
dply->UpdateAll();
}
- status = et_chan.ReadEvent();
+ int status = et_chan.ReadEvent();
switch (status) {
case ETChannel::READ_ERROR:
diff --git a/rootlogon.C b/rootlogon.C
new file mode 100644
index 0000000000000000000000000000000000000000..fbc218253cd3703d407784214e490c976ee6a209
--- /dev/null
+++ b/rootlogon.C
@@ -0,0 +1,10 @@
+{
+ gInterpreter->AddIncludePath("./include");
+ gInterpreter->AddIncludePath("./third_party/et_coda_3.10/include");
+ gInterpreter->AddIncludePath("./third_party/simple");
+ gInterpreter->AddIncludePath("./third_party/prconf/include");
+ // gSystem->Load("libcoda_et.so");
+ gSystem->Load("./third_party/et_coda_3.10/lib/libet.so");
+ gSystem->Load("./third_party/prconf/libprconf.so");
+ gSystem->Load("./third_party/simple/libsimple.so");
+}
diff --git a/src/esb_analyze_online.cpp b/src/esb_analyze_online.cpp
index 9cafff5d092cdcf907b4c9c74102e416b33a32d0..f7a896264a78ac536f2c11e468ec183ce417df22 100644
--- a/src/esb_analyze_online.cpp
+++ b/src/esb_analyze_online.cpp
@@ -6,10 +6,6 @@
#include "ConfigParser.h"
#include "ConfigObject.h"
#include "ConfigOption.h"
-#include "THaCodaFile.h"
-#include "THaEvData.h"
-#include "CodaDecoder.h"
-#include "evio.h"
#include "TSpectrum.h"
#include "TTree.h"
#include "TFile.h"
@@ -23,28 +19,17 @@
#define PROGRESS_COUNT 100
-volatile sig_atomic_t sig_caught = 0;
+volatile sig_atomic_t terminate = 0;
void handle_sig(int signum)
{
- /* in case we registered this handler for multiple signals */
- if (signum == SIGINT) {
- sig_caught = 1;
- }
- if (signum == SIGTERM) {
- sig_caught = 2;
- }
- if (signum == SIGABRT) {
- sig_caught = 3;
- }
+ terminate = 1;
}
-void write_raw_data(const std::string &addr, int port, const std::string &etfile,
- const std::string &opath, int nev, const std::vector<Module> &modules);
-bool parseEvent(const uint32_t *buf, bool verbose);
-uint32_t parseBlock(const uint32_t *buf);
+void monitor(const std::string &addr, int port, const std::string &etfile,
+ const std::string &opath, const std::string &modules_conf, int nev);
uint32_t swap_endian32(uint32_t num)
@@ -56,6 +41,21 @@ uint32_t swap_endian32(uint32_t num)
return b0 | b1 | b2 | b3;
}
+
+uint32_t parseBlock(const uint32_t *buf)
+{
+ auto header = (ETChannel::CodaEvHeader*) buf;
+ const uint32_t buf_size = header->length + 1;
+ std::cout << "ROC header: " << std::dec << buf_size << "\n"
+ << (int) header->etype << ", " << (int) header->dtype << ", " << (int) header->num
+ << std::endl;
+ std::cout << std::hex;
+ for (uint32_t i = 0; i < buf_size; ++i) {
+ std::cout << "0x" << std::setw(8) << std::setfill('0') << buf[i] << "\n";
+ }
+ return buf_size;
+}
+
// parse an evio event
bool parseEvent(const uint32_t *buf, bool verbose = false)
{
@@ -99,21 +99,6 @@ bool parseEvent(const uint32_t *buf, bool verbose = false)
}
-uint32_t parseBlock(const uint32_t *buf)
-{
- auto header = (ETChannel::CodaEvHeader*) buf;
- const uint32_t buf_size = header->length + 1;
- std::cout << "ROC header: " << std::dec << buf_size << "\n"
- << (int) header->etype << ", " << (int) header->dtype << ", " << (int) header->num
- << std::endl;
- std::cout << std::hex;
- for (uint32_t i = 0; i < buf_size; ++i) {
- std::cout << "0x" << std::setw(8) << std::setfill('0') << buf[i] << "\n";
- }
- return buf_size;
-}
-
-
int main(int argc, char* argv[])
{
// setup input arguments
@@ -166,9 +151,7 @@ int main(int argc, char* argv[])
}
}
- auto modules = read_modules(mconf);
-
- write_raw_data(host, port, etfile, conf_opt.GetArgument(0), nev, modules);
+ monitor(host, port, etfile, conf_opt.GetArgument(0), mconf, nev);
}
@@ -339,7 +322,7 @@ void fill_tree(TTree *tree, std::unordered_map<std::string, BranchData> &brdata,
void processEvent(const uint32_t *buf, int &count, TTree *tree, bool &init_tree, int &data_mode,
const std::vector<Module> &modules, std::unordered_map<std::string, BranchData> &brdata)
{
- if (!parseEvent(buf)) {
+ if (!parseEvent(buf, false)) {
return;
}
@@ -388,15 +371,17 @@ void processEvent(const uint32_t *buf, int &count, TTree *tree, bool &init_tree,
}
-void write_raw_data(const std::string &addr, int port, const std::string &etfile,
- const std::string &opath, int nev, const std::vector<Module> &modules)
+void monitor(const std::string &addr, int port, const std::string &etfile,
+ const std::string &opath, const std::string &mconf, int nev)
{
ETChannel et_chan(100, 100);
if (et_chan.Connect(addr.c_str(), port, etfile.c_str(), "TCD_MONITOR") != ET_OK) {
return;
}
- auto *hfile = new TFile(opath.c_str(), "RECREATE", "MAPMT test results");
+ auto modules = read_modules(mconf);
+
+ auto *hfile = new TFile(opath.c_str(), "RECREATE", "MAPMT online monitor");
auto tree = new TTree("EvTree", "Cherenkov Test Events");
// set up branches and a container to be combined with the branches
std::unordered_map<std::string, BranchData> brdata;
@@ -413,26 +398,33 @@ void write_raw_data(const std::string &addr, int port, const std::string &etfile
int count = 0;
bool init_tree = false;
int data_mode = -1;
+ int status = ETChannel::READ_EMPTY;
et_chan.Open();
- int status = et_chan.ReadEvent();
signal (SIGINT, handle_sig);
- while (status != ETChannel::READ_ERROR && status != ETChannel::READ_EOF) {
- if (sig_caught || (nev > 0 && nev < count)) { break; }
- // read-in data
- if (status == ETChannel::READ_EMPTY) {
- std::cout << "ET station is empty, wating 5 secs..." << std::endl;
- std::this_thread::sleep_for(std::chrono::seconds(5));
- status = et_chan.ReadEvent();
- continue;
- }
- if((count % PROGRESS_COUNT) == 0) {
+ while (true) {
+ if (terminate > 0 || (nev > 0 && nev < count)) { break; }
+ if (count % PROGRESS_COUNT == 0) {
std::cout << "Read and processed events - " << count << std::endl;
}
- processEvent(et_chan.GetEvBuffer(), count, tree, init_tree, data_mode, modules, brdata);
status = et_chan.ReadEvent();
- }
+
+ switch (status) {
+ case ETChannel::READ_ERROR:
+ case ETChannel::READ_EOF:
+ terminate = 1;
+ break;
+ case ETChannel::READ_EMPTY:
+ std::cout << "ET station is empty, wait 2 secs..." << std::endl;
+ std::this_thread::sleep_for(std::chrono::seconds(2));
+ break;
+ case ETChannel::READ_OK:
+ processEvent(et_chan.GetEvBuffer(), count, tree, init_tree, data_mode, modules, brdata);
+ break;
+ }
+ }
+
std::cout << "Read and processed events - " << count << std::endl;
hfile->Write();
diff --git a/third_party/prconf/include/ConfigObject.h b/third_party/prconf/include/ConfigObject.h
index aa3bd1c82e8582cd994dca214d910b6edaf9076c..757f32eda3d1029ecdb142e57b91051938fd8814 100644
--- a/third_party/prconf/include/ConfigObject.h
+++ b/third_party/prconf/include/ConfigObject.h
@@ -8,17 +8,18 @@
#include "ConfigParser.h"
-#define CONF_CONN(val, str, def, warn) val=GetConfigValue<decltype(val)>(str, def, warn)
-#define CONF_CONN2(val, def, warn) val=GetConfiValue<decltype(val)>(str, def, warn)
-#define GET_CONF(obj, val, str, def, warn) val=obj.GetConfiValue<decltype(val)>(str, def, warn)
-#define GET_CONF2(obj, val, def, warn) val=GetConfiValue<decltype(val)>(#val, def, warn)
+#define CONF_CONN(val, str, def, warn) val=Value<decltype(val)>(str, def, warn)
+#define CONF_CONN2(val, def, warn) val=Value<decltype(val)>(str, def, warn)
+#define GET_CONF(obj, val, str, def, warn) val=obj.Value<decltype(val)>(str, def, warn)
+#define GET_CONF2(obj, val, def, warn) val=Value<decltype(val)>(#val, def, warn)
class ConfigObject
{
public:
// constructor, desctructor
- ConfigObject(const std::string &spliiter = ":=", const std::string &ignore = " _\t", bool case_ins = true);
+ ConfigObject(const std::string &spliiter = ":=", const std::string &ignore = " _\t",
+ const std::string &var_open = "${", const std::string &var_close = "}", bool case_ins = true);
virtual ~ConfigObject();
@@ -29,36 +30,37 @@ public:
bool HasKey(const std::string &name) const;
bool ReadConfigFile(const std::string &path);
- void ReadConfigString(const std::string &content);
+ void ReadConfigString(const std::string &content, const std::string &path = ".");
void SetConfigValue(const std::string &var_name, const ConfigValue &c_value);
void SetIgnoreChars(const std::string &ignore) {ignore_chars = ignore;}
void SetSplitChars(const std::string &splitter) {split_chars = splitter;}
- void SetReplacePair(const std::string &open, const std::string &close)
+ void SetVariablePair(const std::string &open, const std::string &close)
{
- replace_pair = std::make_pair(open, close);
+ variable_pair = std::make_pair(open, close);
}
// get members
- ConfigValue GetConfigValue(const std::string &var_name) const;
+ ConfigValue Value(const std::string &var_name) const;
template<typename T>
- T GetConfigValue(const std::string &var_name)
+ T Value(const std::string &var_name)
const
{
- return GetConfigValue(var_name).Convert<T>();
+ return Value(var_name).Convert<T>();
}
- ConfigValue GetConfigValue(const std::string &var_name, const ConfigValue &def_value, bool verbose = true);
+ ConfigValue Value(const std::string &var_name, const ConfigValue &def_value, bool verbose = true);
template<typename T>
- T GetConfigValue(const std::string &var_name, const T &val, bool verbose = true)
+ T Value(const std::string &var_name, const T &val, bool verbose = true)
{
- return GetConfigValue(var_name, ConfigValue(val), verbose).Convert<T>();
+ return Value(var_name, ConfigValue(val), verbose).Convert<T>();
}
const std::string &GetConfigPath() const {return config_path;}
const std::string &GetSplitChars() const {return split_chars;}
const std::string &GetSpaceChars() const {return ignore_chars;}
- const std::pair<std::string, std::string> &GetReplacePair() const {return replace_pair;}
+ const std::pair<std::string, std::string> &GetVariablePair() const {return variable_pair;}
std::vector<std::string> GetKeyList() const;
+ const std::unordered_map<std::string, std::string> &GetMap() const {return config_map;}
// functions that to be overloaded
@@ -77,8 +79,8 @@ private:
protected:
std::string split_chars;
std::string ignore_chars;
+ std::pair<std::string, std::string> variable_pair;
bool case_insensitive;
- std::pair<std::string, std::string> replace_pair;
std::string config_path;
std::unordered_map<std::string, std::string> config_map;
diff --git a/third_party/prconf/include/ConfigParser.h b/third_party/prconf/include/ConfigParser.h
index 5e2810b4b0ea14d3f0167fa05e9089c5542eed1d..65faeb2529d45adcc0ebcefad12ac19b96ad4025 100644
--- a/third_party/prconf/include/ConfigParser.h
+++ b/third_party/prconf/include/ConfigParser.h
@@ -3,10 +3,12 @@
#include <string>
#include <vector>
+#include <queue>
#include <deque>
#include <fstream>
#include "ConfigValue.h"
+
// a macro to auto generate enum2str and str2enum
// name mapping begins at bias and continuously increase, split by '|'
// an example:
@@ -32,79 +34,39 @@ class ConfigParser
public:
struct Format
{
+ struct StrPair { std::string open, close; };
std::string split; // element splitters (chars)
std::string white; // white spaces (chars)
std::string delim; // line delimiter (string)
std::string glue; // line glue (string)
- std::string cmtmark; // comment marks (string), until the line breaker '\n'
- std::string cmtopen; // comment-block opening mark (string)
- std::string cmtclose; // comment-block closing mark (string)
-
- static Format Basic() {return {" \t,", " \t", "\n", "", "", "", ""};}
- static Format BashLike() {return {" \t,", " \t", "\n", "\\", "#", "\'", "\'"};}
- static Format CLike() {return {" \t,\n", " \t\n", ";", "", "//", "/*", "*/"};}
- };
-
- struct CharBuffer
- {
- std::vector<char> data;
- size_t begin, end;
-
- CharBuffer(size_t cap = 256) : begin(0), end(0)
- {
- data.resize(cap);
- }
-
- void Reset() {begin = 0; end = 0; data.clear();}
- void Add(char ch)
- {
- if(data.size() <= end)
- data.resize(2*data.size());
+ std::string linecmt; // comment marks (string), until the line breaker '\n'
+ StrPair blockcmt; // block commenting marks (open string, close string)
+ StrPair quote; // quote marks (open string, close string)
- data[end++] = ch;
- }
-
- std::string String()
- const
- {
- std::string str;
- if(end > begin)
- str.assign(&data[begin], end - begin);
- return str;
- }
-
- inline const char &operator [] (size_t idx) const {return data[idx];}
- inline char &operator [] (size_t idx) {return data[idx];}
+ static Format Basic() { return {" \t,", " \t", "\n", "", "", {"", ""}, {"\"", "\""}}; }
+ static Format BashLike() { return {" \t,", " \t", "\n", "\\", "#", {"\'", "\'"}, {"\"", "\""}}; }
+ static Format CLike() { return {" \t,\n", " \t\n", ";", "", "//", {"/*", "*/"}, {"\"", "\""}}; }
};
public:
ConfigParser(Format f = Format::BashLike());
- ConfigParser(ConfigParser &&that);
- ConfigParser(const ConfigParser &that);
-
- virtual ~ConfigParser();
-
- ConfigParser &operator = (ConfigParser &&rhs);
- ConfigParser &operator = (const ConfigParser &rhs);
-
// format related
- inline void SetFormat(Format &&f) {form = f;}
- inline void SetFormat(const Format &f) {form = f;}
- inline void SetSplitters(std::string s) {form.split = s;}
- inline void SetWhiteSpaces(std::string w) {form.white = w;}
- inline void SetCommentMark(std::string c) {form.cmtmark = c;}
- inline void SetCommentPair(std::string o, std::string c) {form.cmtopen = o; form.cmtclose = c;}
- inline void SetLineGlues(std::string g) {form.glue = g;}
- inline void SetLineBreaks(std::string b) {form.delim = b;}
-
- const Format &GetFormat() const {return form;}
+ inline void SetFormat(Format &&f) { fmt = f; }
+ inline void SetFormat(const Format &f) { fmt = f; }
+ inline void SetSplitters(std::string s) { fmt.split = s; }
+ inline void SetWhiteSpaces(std::string w) { fmt.white = w; }
+ inline void SetCommentMark(std::string c) { fmt.linecmt = c; }
+ inline void SetCommentPair(std::string o, std::string c) { fmt.blockcmt = {o, c}; }
+ inline void SetLineGlues(std::string g) { fmt.glue = g; }
+ inline void SetLineBreaks(std::string b) { fmt.delim = b; }
+ inline void SetQuotePair(std::string o, std::string c) { fmt.quote = {o, c}; }
+
+ const Format &GetFormat() const {return fmt;}
// dealing with file/buffer
- bool OpenFile(const std::string &path, size_t cap = 64*1024);
bool ReadFile(const std::string &path);
void ReadBuffer(const char*);
- void CloseFile();
void Clear();
// parse line, return false if no more line to parse
@@ -116,9 +78,9 @@ public:
// get current parsing status
bool CheckElements(int num, int optional = 0);
- int NbofElements() const {return elements.size();}
- int LineNumber() const {return line_number;}
- std::string CurrentLine() const {return cur_line.String();}
+ int NbofElements() const { return elements.size(); }
+ int LineNumber() const { return line_number; }
+ std::string CurrentLine() const;
// take the elements
ConfigValue TakeFirst();
@@ -179,22 +141,35 @@ public:
private:
// private functions
- bool getBuffer();
- bool getLine(CharBuffer &line_buf, bool recursive = false);
- int parseBuffer(const CharBuffer &line);
+ void toLines(std::string buf);
+ void parseBuffer();
+ void retrieveLine();
private:
// private members
- Format form;
- std::ifstream infile;
- CharBuffer buf, cur_line;
+ Format fmt;
int line_number;
- std::deque<std::string> elements;
+ std::string curr_line;
+ std::vector<std::string> quotes;
+ std::deque<std::string> lines, elements;
+
public:
// static functions
static void comment_line(std::string &str, const std::string &cmt, const std::string &brk);
+ static void comment_line(std::string &str, const std::string &cmt, const std::string &brk,
+ const std::string &qmark);
static void comment_between(std::string &str, const std::string &open, const std::string &close);
+ static void comment_between(std::string &str, const std::string &open, const std::string &close,
+ const std::string &qmark);
+ static void tokenize(std::string &str, std::vector<std::string> &contents, const std::string &token,
+ const std::string &open, const std::string &close);
+ static inline void tokenize(std::string &str, std::vector<std::string> &contents, const std::string &token,
+ const std::string &qmark) { tokenize(str, contents, token, qmark, qmark); }
+ static void untokenize(std::string &str, const std::vector<std::string> &contents, const std::string &token,
+ const std::string &open, const std::string &close);
+ static inline void untokenize(std::string &str, const std::vector<std::string> &contents, const std::string &token,
+ const std::string &qmark = "") { untokenize(str, contents, token, qmark, qmark); }
static std::string trim(const std::string &str, const std::string &w);
static std::deque<std::string> split(const std::string &str, const std::string &s);
static std::deque<std::string> split(const char* str, const size_t &len, const std::string &s);
diff --git a/third_party/prconf/include/ConfigValue.h b/third_party/prconf/include/ConfigValue.h
index aaf3a36103cf96af200f2b68f1f330278a8ae46a..425912a7a56ca1800402f93fb8e0c1b0d22cebe3 100644
--- a/third_party/prconf/include/ConfigValue.h
+++ b/third_party/prconf/include/ConfigValue.h
@@ -82,6 +82,8 @@ public:
const std::string &String() const {return _value;}
bool IsEmpty() const {return _value.empty();}
+ ConfigValue &Trim(const std::string &white);
+
operator std::string()
const
{
diff --git a/third_party/prconf/src/ConfigObject.cpp b/third_party/prconf/src/ConfigObject.cpp
index ee18cd36afcc2b782b33a642e35618379256f7c6..33a98a898862f2bf6c3835427170dfa131efa5a3 100644
--- a/third_party/prconf/src/ConfigObject.cpp
+++ b/third_party/prconf/src/ConfigObject.cpp
@@ -9,6 +9,7 @@
// 10/31/2016 //
//============================================================================//
+#include <cstdlib>
#include <fstream>
#include <iostream>
#include <iomanip>
@@ -16,17 +17,17 @@
#include "ConfigObject.h"
-
//============================================================================//
// Constructor, Destructor //
//============================================================================//
// constructor
-ConfigObject::ConfigObject(const std::string &splitter, const std::string &ignore, bool case_ins)
-: split_chars(splitter), ignore_chars(ignore), case_insensitive(case_ins), __empty_value("")
+ConfigObject::ConfigObject(const std::string &splitter, const std::string &ignore, const std::string &var_open,
+ const std::string &var_close, bool case_ins)
+: split_chars(splitter), ignore_chars(ignore), variable_pair({var_open, var_close}), case_insensitive(case_ins),
+ __empty_value("")
{
- // set default replace bracket
- replace_pair = std::make_pair("{", "}");
+ // place holder
}
// destructor
@@ -79,36 +80,39 @@ bool ConfigObject::ReadConfigFile(const std::string &path)
}
// read the configuration string directly
-void ConfigObject::ReadConfigString(const std::string &content)
+void ConfigObject::ReadConfigString(const std::string &content, const std::string &path)
{
ConfigParser c_parser;
c_parser.SetSplitters(split_chars);
c_parser.ReadBuffer(content.c_str());
- parserProcess(c_parser, "buffer_string");
+ parserProcess(c_parser, path);
}
// continue parse the terms
void ConfigObject::parserProcess(ConfigParser &c_parser, const std::string &source)
{
- std::string cur_dir = ConfigParser::decompose_path(source).dir;
+ char abs_path[2048];
+ realpath(source.c_str(), abs_path);
+ std::string cur_dir = ConfigParser::decompose_path(abs_path).dir;
+
+ // THIS_DIR needs special treatment as many files in different dirs may be loaded into one instance
+ std::string dir_key = variable_pair.first + "THIS_DIR" + variable_pair.second;
while (c_parser.ParseLine()) {
// possible control words
if (c_parser.NbofElements() == 1) {
std::string control = c_parser.TakeFirst();
- size_t pos = control.find("{THIS_DIR}");
- if(pos != std::string::npos)
- control.replace(pos, 10, cur_dir);
+ size_t pos = control.find(dir_key);
+ if(pos != std::string::npos) { control.replace(pos, dir_key.size(), cur_dir); }
parseControl(control);
// var_name and var_value
} else if (c_parser.NbofElements() == 2) {
std::string var_name, key, var_value;
c_parser >> var_name >> var_value;
- size_t pos = var_value.find("{THIS_DIR}");
- if(pos != std::string::npos)
- var_value.replace(pos, 10, cur_dir);
+ size_t pos = var_value.find(dir_key);
+ if(pos != std::string::npos) { var_value.replace(pos, dir_key.size(), cur_dir); }
parseTerm(std::move(var_name), std::move(var_value));
// unsupported format
} else {
@@ -174,7 +178,7 @@ const
}
// get configuration value by its name/key
-ConfigValue ConfigObject::GetConfigValue(const std::string &var_name)
+ConfigValue ConfigObject::Value(const std::string &var_name)
const
{
// convert to lower case and remove uninterested characters
@@ -185,7 +189,7 @@ const
return __empty_value;
} else {
ConfigValue result(it->second);
- reform(result._value, replace_pair.first, replace_pair.second);
+ reform(result._value, variable_pair.first, variable_pair.second);
return result;
}
}
@@ -202,7 +206,7 @@ void ConfigObject::SetConfigValue(const std::string &var_name, const ConfigValue
// get configuration value from the map
// if no such config value exists, it will fill the default value in
-ConfigValue ConfigObject::GetConfigValue(const std::string &var_name, const ConfigValue &def_value, bool verbose)
+ConfigValue ConfigObject::Value(const std::string &var_name, const ConfigValue &def_value, bool verbose)
{
auto key = formKey(var_name);
@@ -222,7 +226,7 @@ ConfigValue ConfigObject::GetConfigValue(const std::string &var_name, const Conf
}
ConfigValue result(it->second);
- reform(result._value, replace_pair.first, replace_pair.second);
+ reform(result._value, variable_pair.first, variable_pair.second);
return result;
}
@@ -243,7 +247,7 @@ const
return key;
}
-// replace the contents inside replace_pair with the configuration value
+// replace the contents inside variable_pair with the configuration value
void ConfigObject::reform(std::string &input, const std::string &op, const std::string &cl)
const
{
@@ -258,17 +262,7 @@ const
reform(var, op, cl);
// replace content
- std::string val;
-
- // environment variable
- if (rpair.first > 0 && input.at(rpair.first - 1) == '$') {
- val = std::getenv(var.c_str());
- // replace $ mark also
- rpair.first--;
- // ConfigObject variable
- } else {
- val = GetConfigValue(var)._value;
- }
+ std::string val = HasKey(var) ? Value(var)._value : std::getenv(var.c_str());
// replace variable with configuration value
input.replace(rpair.first, rpair.second - rpair.first + cl.size(), val);
@@ -304,7 +298,7 @@ void ConfigObject::parseControl(const std::string &word)
int length = p.second - begin;
std::string new_path = word.substr(begin, length);
- reform(new_path, replace_pair.first, replace_pair.second);
+ reform(new_path, variable_pair.first, variable_pair.second);
ReadConfigFile(new_path);
}
diff --git a/third_party/prconf/src/ConfigParser.cpp b/third_party/prconf/src/ConfigParser.cpp
index ad496d48e13bfeacdfda01dd92178482dd778c69..36e63537ace3fee0ce063451926478ea28077542 100644
--- a/third_party/prconf/src/ConfigParser.cpp
+++ b/third_party/prconf/src/ConfigParser.cpp
@@ -12,6 +12,10 @@
using namespace std;
+#define TOKEN_DIGITS 5
+
+// TODO radmonize token that has no conflic with the format marks
+static const string config_token = "Gc2xConfig6R";
//============================================================================//
@@ -20,114 +24,53 @@ using namespace std;
// constructor, with format input
ConfigParser::ConfigParser(Format f)
-: form(f), line_number(0)
-{
- // place holder
-}
-
-// copy constructor, only copy format
-ConfigParser::ConfigParser(const ConfigParser &that)
-: form(that.form), line_number(0)
+: fmt(f), line_number(0)
{
// place holder
}
-// move constructor, only move format
-ConfigParser::ConfigParser(ConfigParser &&that)
-: form(that.form), line_number(0)
-{
- // place holder
-}
-
-// desctructor
-ConfigParser::~ConfigParser()
-{
- CloseFile();
-}
-
-// copy assignment operator
-ConfigParser &ConfigParser::operator = (const ConfigParser &rhs)
-{
- form = rhs.form;
- return *this;
-}
-
-// move assignment operator
-ConfigParser &ConfigParser::operator = (ConfigParser &&rhs)
-{
- form = rhs.form;
- return *this;
-}
-
//============================================================================//
// Public Member Function //
//============================================================================//
-// open a file for future parsing
-bool ConfigParser::OpenFile(const string &path, size_t cap)
-{
- Clear();
-
- infile.open(path);
-
- if(!infile.is_open())
- return false;
-
- buf.data.resize(cap);
-
- // success!
- return true;
-}
-
// read the whole file into a buffer and break it into lines
bool ConfigParser::ReadFile(const string &path)
{
- Clear();
-
- infile.open(path);
+ ifstream inf(path);
- if(!infile.is_open())
+ if(!inf.is_open())
return false;
- infile.seekg(0, ios::end);
- buf.end = infile.tellg();
- buf.data.resize(buf.end);
- infile.seekg(0, ios::beg);
+ // read the whole file in
+ string str;
+
+ inf.seekg(0, ios::end);
+ str.reserve(inf.tellg());
+ inf.seekg(0, ios::beg);
- infile.read(&buf.data[0], buf.end);
- infile.close();
+ str.assign((istreambuf_iterator<char>(inf)), istreambuf_iterator<char>());
+ inf.close();
+
+ toLines(str);
return true;
}
-// close file
-void ConfigParser::CloseFile()
+// read a buffer in
+void ConfigParser::ReadBuffer(const char *buf_in)
{
- return infile.close();
+ toLines(buf_in);
}
// clear stored lines
void ConfigParser::Clear()
{
- buf.Reset();
+ lines.clear();
+ elements.clear();
// reset line
line_number = 0;
- cur_line.Reset();
-
- // close file
- CloseFile();
-}
-
-// read a buffer in
-void ConfigParser::ReadBuffer(const char *buf_in)
-{
- Clear();
-
- buf.end = strlen(buf_in);
- buf.data.resize(buf.end + 2);
-
- strncpy(&buf.data[0], buf_in, buf.end);
+ curr_line.clear();
}
// parse a line from the file or buffer
@@ -135,57 +78,38 @@ void ConfigParser::ReadBuffer(const char *buf_in)
// return false if reached the end
bool ConfigParser::ParseLine()
{
- elements.clear();
-
- while(elements.empty())
- {
- if(!getLine(cur_line))
- return false;
-
- // count the line number
- ++line_number;
-
- parseBuffer(cur_line);
+ if (lines.empty()) {
+ return false;
}
- return true;
+ elements.clear();
+ parseBuffer();
+
+ return static_cast<bool>(elements.size());
}
+
// parse the whole file or buffer
// return false if nothing was found
bool ConfigParser::ParseAll()
{
elements.clear();
- while(true)
- {
- if(!getLine(cur_line))
- return !elements.empty();
-
- // count the line number
- ++line_number;
-
- parseBuffer(cur_line);
+ while (lines.size()) {
+ parseBuffer();
}
+
+ return static_cast<bool>(elements.size());
}
// parse an input string, split the string into elements
// the trail white spaces in the elements will be trimmed
int ConfigParser::ParseString(const string &line)
{
- deque<string> eles = split(line.c_str(), line.size(), form.split);
+ toLines(line);
+ ParseAll();
- int count = 0;
- for(auto &ele : eles)
- {
- string trim_ele = trim(ele, form.white);
- if(!trim_ele.empty()) {
- elements.emplace_back(move(trim_ele));
- count++;
- }
- }
-
- return count;
+ return elements.size();
}
// check if the current elemtns number is in the range [num, num + optional]
@@ -223,12 +147,20 @@ bool ConfigParser::CheckElements(int num, int optional)
<< line_number
<< ", expecting " << num_str << " elements. "
<< endl
- << "\"" << cur_line.String() << "\""
+ << "\"" << CurrentLine() << "\""
<< endl;
return false;
}
+// get current line
+string ConfigParser::CurrentLine() const
+{
+ string res = curr_line;
+ untokenize(res, quotes, config_token, fmt.quote.open, fmt.quote.close);
+ return res;
+}
+
// take the first element
ConfigValue ConfigParser::TakeFirst()
{
@@ -249,165 +181,102 @@ ConfigValue ConfigParser::TakeFirst()
//============================================================================//
// Private Member Function //
//============================================================================//
-
-// get buffer from the file or the input buffer
-// return false if reached input end
-bool ConfigParser::getBuffer()
+// helper function
+inline bool compare_str(const char *buf1, const char *buf2, size_t n)
{
- if(buf.begin < buf.end)
- return true;
-
- if(!infile.is_open() || infile.bad() || infile.eof())
- return false;
-
- infile.read(&buf.data[0], buf.data.size());
-
- buf.begin = 0;
- buf.end = infile.gcount();
-
+ for (size_t i = 0; i < n; ++i) {
+ if (buf1[i] != buf2[i]) {
+ return false;
+ }
+ }
return true;
}
-// trim white spaces
-inline void trimbuf(const vector<char> &buf, size_t &begin, size_t &end, const string &w)
+// helper function
+inline string break_line(const string &buf, const std::string &delim, size_t &i, const std::string &glue)
{
- while(begin < end)
- {
- if(w.find(buf[begin]) == string::npos)
- break;
-
- begin++;
+ size_t beg = i;
+ if (delim.empty()) {
+ i = buf.size();
+ return buf.substr(beg);
}
- while(end > begin)
- {
- if(w.find(buf[end - 1]) == string::npos)
- break;
-
- end--;
+ for (; i <= buf.size() - delim.size(); ++i) {
+ if (compare_str(&buf[i], delim.c_str(), delim.size())) {
+ string res = buf.substr(beg, i - beg);
+ i += delim.size();
+ if (glue.size() && (res.size() > glue.size())) {
+ size_t pos = res.size() - glue.size();
+ if (compare_str(&res[pos], glue.c_str(), glue.size())) {
+ return res.substr(0, pos) + break_line(buf, delim, i, glue);
+ }
+ }
+ return res;
+ }
}
+ i = buf.size();
+ return buf.substr(beg);
}
-inline bool compare(const char ch, const string &str, size_t &c1)
+// parse the buffer string, remove comments, tokenize quotes, and split it in lines
+void ConfigParser::toLines(string buf)
{
- if(str.empty())
- return false;
+ Clear();
- c1 = (ch == str[c1]) ? (c1 + 1) : 0;
+ if (buf.empty()) {
+ return;
+ }
- return (c1 >= str.size());
+ // break into lines
+ size_t ibuf = 0;
+ while (ibuf < buf.size()) {
+ lines.emplace_back(break_line(buf, fmt.delim, ibuf, fmt.glue));
+ }
}
-inline bool rcompare(const ConfigParser::CharBuffer &buf, const string &str)
+void ConfigParser::retrieveLine()
{
- if(str.empty() || buf.end <= buf.begin || buf.end - buf.begin < str.size())
- return false;
+ curr_line += move(lines.front());
+ lines.pop_front();
+ tokenize(curr_line, quotes, config_token, fmt.quote.open, fmt.quote.close);
+ comment_between(curr_line, fmt.blockcmt.open, fmt.blockcmt.close);
+ comment_line(curr_line, fmt.linecmt, fmt.delim);
- for(size_t i = 1; i <= str.size(); ++i)
- {
- if(str[str.size() - i] != buf[buf.end - i])
- return false;
+ if (lines.empty()) { return; }
+ if (curr_line.empty() || (curr_line.find(fmt.blockcmt.open) != string::npos)) {
+ retrieveLine();
}
-
- return true;
}
-// a helper structure to check context status
-struct TextStatus
+// parse buffered lines
+void ConfigParser::parseBuffer()
{
- int val;
- size_t cmt1, cmt2, delim;
+ size_t count = 0;
+ curr_line.clear();
+ quotes.clear();
- TextStatus() : val(0), cmt1(0), cmt2(0), delim(0) {}
- inline void Set(int i) {val = i; cmt1 = 0; cmt2 = 0;}
-};
+ while (!count && lines.size())
+ {
+ retrieveLine();
-// get a line from the file or buffer
-// it deals with comments, white spaces
-// return false if reached the end
-bool ConfigParser::getLine(CharBuffer &line_buf, bool recursive)
-{
- if(!recursive)
- line_buf.Reset();
- bool success = false;
- TextStatus stat;
+ trim(curr_line, fmt.white);
+ auto eles = split(curr_line, fmt.split);
- while(getBuffer())
- {
- success = true;
-
- while(buf.begin < buf.end)
- {
- auto &ch = buf[buf.begin++];
- switch(stat.val)
- {
- default:
- case 0:
- line_buf.Add(ch);
- // check if it is the end
- if(compare(ch, form.delim, stat.delim)) {
- line_buf.end -= form.delim.size();
- trimbuf(line_buf.data, line_buf.begin, line_buf.end, form.white);
- // glue lines
- if(rcompare(line_buf, form.glue)) {
- line_buf.end -= form.glue.size();
- return getLine(line_buf, true);
- } else {
- return success;
- }
- } else if(compare(ch, form.cmtopen, stat.cmt1)) {
- stat.Set(1);
- line_buf.end -= form.cmtopen.size();
- } else if(compare(ch, form.cmtmark, stat.cmt2)) {
- stat.Set(2);
- line_buf.end -= form.cmtmark.size();
- }
- break;
- case 1:
- if(compare(ch, form.cmtclose, stat.cmt1)) {
- stat.Set(0);
- }
- break;
- case 2:
- if(ch == '\n') {
- stat.Set(0);
- buf.begin -= 1;
- }
- break;
+ // trim every element and replace token with info
+ for (auto &ele : eles) {
+ ele = trim(ele, fmt.white);
+ if (ele.empty()) {
+ continue;
}
+ untokenize(ele, quotes, config_token);
+ elements.emplace_back(move(ele));
+ count++;
}
+ line_number++;
}
-
- trimbuf(line_buf.data, line_buf.begin, line_buf.end, form.white);
- return success;
}
-// parse an input char buffer, split the string into elements
-// the trail white spaces in the elements will be trimmed
-int ConfigParser::parseBuffer(const CharBuffer &line)
-{
- if(line.begin >= line.end)
- return 0;
- size_t ele_begin = line.begin;
- int count = 0;
-
- // intended to visit i == line.end, so the rest of the string get parsed
- for(size_t i = 0; i <= line.end; ++i)
- {
- if(i == line.end || form.split.find(line[i]) != string::npos) {
- size_t ele_end = i;
- trimbuf(line.data, ele_begin, ele_end, form.white);
- if(ele_begin < ele_end) {
- elements.emplace_back(&line[ele_begin], ele_end - ele_begin);
- count++;
- }
- ele_begin = i + 1;
- }
- }
-
- return count;
-}
//============================================================================//
// Public Static Function //
@@ -443,22 +312,77 @@ void ConfigParser::comment_line(string &str, const string &c, const string &b)
}
}
+// comment out a string, consider quotes
+void ConfigParser::comment_line(string &str, const string &c, const string &b, const string &qmark)
+{
+ vector<string> quotes;
+ tokenize(str, quotes, config_token, qmark, qmark);
+ comment_line(str, c, b);
+ untokenize(str, quotes, config_token, qmark, qmark);
+}
+
+// tokenize the content between quote marks, no nested structure supported
+void ConfigParser::tokenize(string &str, vector<string> &contents, const string &token,
+ const string &open, const string &close)
+{
+ if (str.empty() || open.empty() || close.empty())
+ return;
+
+ string padzero(TOKEN_DIGITS, '0');
+ while (true) {
+ size_t pos1 = str.find(open);
+ if (pos1 != string::npos) {
+ size_t pos2 = str.find(close, pos1 + open.size());
+ // found pair
+ if (pos2 != string::npos) {
+ string digits = (padzero + to_string(contents.size()));
+ contents.emplace_back(str.substr(pos1 + open.size(), pos2 - pos1 - open.size()));
+ str.replace(pos1, pos2 + close.size() - pos1, token + digits.substr(digits.size() - TOKEN_DIGITS));
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+// reversal of tokenize
+void ConfigParser::untokenize(string &str, const vector<string> &contents, const string &token,
+ const string &open, const string &close)
+{
+ if (contents.empty() || str.empty() || token.empty()) {
+ return;
+ }
+
+ auto pos = str.find(token);
+ auto size = token.size() + TOKEN_DIGITS;
+ while ((pos != string::npos) && ((pos + size) <= str.size())) {
+ size_t id = stoul(str.substr(pos + token.size(), TOKEN_DIGITS));
+ if (open.empty() || close.empty()) {
+ str.replace(pos, size, contents[id]);
+ } else {
+ str.replace(pos, size, open + contents[id] + close);
+ }
+ pos = str.find(token);
+ }
+}
+
// comment out between a pair of comment marks
// NOTICE: does not support nested structure of comment marks
void ConfigParser::comment_between(string &str, const string &open, const string &close)
{
// no need to continue
- if(str.empty() || open.empty() || close.empty())
+ if (str.empty() || open.empty() || close.empty())
return;
- while(true)
- {
+ while (true) {
// find the openning comment mark
size_t pos1 = str.find(open);
- if(pos1 != string::npos) {
+ if (pos1 != string::npos) {
size_t pos2 = str.find(close, pos1 + open.size());
// found pair
- if(pos2 != string::npos) {
+ if (pos2 != string::npos) {
// remove everything between, including this pair
str.erase(pos1, pos2 + close.size() - pos1);
// comment pair not found
@@ -472,6 +396,15 @@ void ConfigParser::comment_between(string &str, const string &open, const string
}
}
+// comment out a string, consider quotes
+void ConfigParser::comment_between(string &str, const string &open, const string &close, const string &qmark)
+{
+ vector<string> quotes;
+ tokenize(str, quotes, config_token, qmark, qmark);
+ comment_between(str, open, close);
+ untokenize(str, quotes, config_token, qmark, qmark);
+}
+
// trim all the characters defined as white space at both ends
string ConfigParser::trim(const string &str, const string &w)
{
diff --git a/third_party/prconf/src/ConfigValue.cpp b/third_party/prconf/src/ConfigValue.cpp
index 96bd4b2ead9db0fe957b8cb11cb1c260f4e75fae..632d88f558943474e49afd5d211f7ed013c67ffb 100644
--- a/third_party/prconf/src/ConfigValue.cpp
+++ b/third_party/prconf/src/ConfigValue.cpp
@@ -305,6 +305,19 @@ const
return _value.c_str();
}
+ConfigValue &ConfigValue::Trim(const std::string &white)
+{
+ const auto strBegin = _value.find_first_not_of(white);
+ if (strBegin == string::npos) {
+ _value = "";
+ } else {
+ const auto strEnd = _value.find_last_not_of(white);
+ const auto strRange = strEnd - strBegin + 1;
+ _value = _value.substr(strBegin, strRange);
+ }
+
+ return *this;
+}
//============================================================================//