Allow fields local to a subtree to be set in the configuration
This commit is contained in:
+34
-22
@@ -46,7 +46,7 @@ using std::list;
|
||||
#define MIN(A,B) ((A)<(B) ? (A) : (B))
|
||||
#endif
|
||||
|
||||
//#define DEBUG
|
||||
#undef DEBUG
|
||||
#ifdef DEBUG
|
||||
#define LOGDEB(X) fprintf X
|
||||
#else
|
||||
@@ -63,22 +63,20 @@ void ConfSimple::parseinput(istream &input)
|
||||
bool eof = false;
|
||||
|
||||
for (;;) {
|
||||
cline[0] = 0;
|
||||
input.getline(cline, LL-1);
|
||||
LOGDEB((stderr, "Parse:line: [%s] status %d\n", cline, int(status)));
|
||||
if (!input.good()) {
|
||||
if (input.bad()) {
|
||||
LOGDEB((stderr, "Parse: input.bad()\n"));
|
||||
status = STATUS_ERROR;
|
||||
return;
|
||||
}
|
||||
LOGDEB((stderr, "Parse: eof\n"));
|
||||
// Must be eof ? But maybe we have a partial line which
|
||||
// must be processed. This happens if the last line before
|
||||
// eof ends with a backslash
|
||||
if (appending) {
|
||||
eof = true;
|
||||
goto processline;
|
||||
}
|
||||
|
||||
break;
|
||||
// eof ends with a backslash, or there is no final \n
|
||||
eof = true;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -94,11 +92,12 @@ void ConfSimple::parseinput(istream &input)
|
||||
else
|
||||
line = cline;
|
||||
|
||||
processline:
|
||||
// Note that we trim whitespace before checking for backslash-eol
|
||||
// This avoids invisible problems.
|
||||
// This avoids invisible whitespace problems.
|
||||
trimstring(line);
|
||||
if (line.empty() || line.at(0) == '#') {
|
||||
if (eof)
|
||||
break;
|
||||
m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
|
||||
continue;
|
||||
}
|
||||
@@ -142,29 +141,29 @@ void ConfSimple::parseinput(istream &input)
|
||||
continue;
|
||||
}
|
||||
i_set(nm, val, submapkey, true);
|
||||
if (eof == true)
|
||||
if (eof)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ConfSimple::ConfSimple(int readonly, bool tildexp)
|
||||
: dotildexpand(tildexp), m_data(0), m_holdWrites(false)
|
||||
: dotildexpand(tildexp), m_holdWrites(false)
|
||||
{
|
||||
status = readonly ? STATUS_RO : STATUS_RW;
|
||||
}
|
||||
|
||||
ConfSimple::ConfSimple(string *d, int readonly, bool tildexp)
|
||||
: dotildexpand(tildexp), m_data(d), m_holdWrites(false)
|
||||
ConfSimple::ConfSimple(const string& d, int readonly, bool tildexp)
|
||||
: dotildexpand(tildexp), m_holdWrites(false)
|
||||
{
|
||||
status = readonly ? STATUS_RO : STATUS_RW;
|
||||
|
||||
stringstream input(*d, ios::in);
|
||||
stringstream input(d, ios::in);
|
||||
parseinput(input);
|
||||
}
|
||||
|
||||
ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
|
||||
: dotildexpand(tildexp), m_filename(fname), m_data(0), m_holdWrites(false)
|
||||
: dotildexpand(tildexp), m_filename(fname), m_holdWrites(false)
|
||||
{
|
||||
status = readonly ? STATUS_RO : STATUS_RW;
|
||||
|
||||
@@ -418,7 +417,8 @@ ConfSimple::sortwalk(WalkerCode (*walker)(void *,const string&,const string&),
|
||||
return WALK_CONTINUE;
|
||||
}
|
||||
|
||||
// Write to default output:
|
||||
// Write to default output. This currently only does something if output is
|
||||
// a file
|
||||
bool ConfSimple::write()
|
||||
{
|
||||
if (!ok())
|
||||
@@ -430,11 +430,11 @@ bool ConfSimple::write()
|
||||
if (!output.is_open())
|
||||
return 0;
|
||||
return write(output);
|
||||
} else if (m_data) {
|
||||
ostringstream output(*m_data, ios::out | ios::trunc);
|
||||
return write(output);
|
||||
} else {
|
||||
// No backing store, no writing
|
||||
// No backing store, no writing. Maybe one day we'll need it with
|
||||
// some kind of output string. This can't be the original string which
|
||||
// is currently readonly.
|
||||
//ostringstream output(m_ostring, ios::out | ios::trunc);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -529,6 +529,18 @@ list<string> ConfSimple::getSubKeys()
|
||||
return mylist;
|
||||
}
|
||||
|
||||
bool ConfSimple::hasNameAnywhere(const string& nm)
|
||||
{
|
||||
list<string>keys = getSubKeys();
|
||||
for (list<string>::const_iterator it = keys.begin();
|
||||
it != keys.end(); it++) {
|
||||
string val;
|
||||
if (get(nm, val, *it))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
|
||||
// //////////////////////////////////////////////////////////////////////////
|
||||
@@ -917,7 +929,7 @@ int main(int argc, char **argv)
|
||||
if (argc != 0)
|
||||
Usage();
|
||||
string s;
|
||||
ConfSimple c(&s);
|
||||
ConfSimple c(s);
|
||||
memtest(c);
|
||||
exit(0);
|
||||
} else if ((op_flags & OPT_V)) {
|
||||
|
||||
+18
-9
@@ -96,6 +96,7 @@ public:
|
||||
virtual ~ConfNull() {};
|
||||
virtual int get(const string &name, string &value,
|
||||
const string &sk = string()) = 0;
|
||||
virtual bool hasNameAnywhere(const string& nm) = 0;
|
||||
virtual int set(const string &nm, const string &val,
|
||||
const string &sk = string()) = 0;
|
||||
virtual bool ok() = 0;
|
||||
@@ -127,7 +128,7 @@ public:
|
||||
* @param readonly if true open readonly, else rw
|
||||
* @param tildexp try tilde (home dir) expansion for subsection names
|
||||
*/
|
||||
ConfSimple(string *data, int readonly = 0, bool tildexp = false);
|
||||
ConfSimple(const string& data, int readonly = 0, bool tildexp = false);
|
||||
|
||||
/**
|
||||
* Build an empty object. This will be memory only, with no backing store.
|
||||
@@ -196,6 +197,10 @@ public:
|
||||
/** Return all names in given submap. */
|
||||
virtual list<string> getNames(const string &sk, const char *pattern = 0);
|
||||
|
||||
/** Check if name is present in any submap. This is relatively expensive
|
||||
* but useful for saving further processing sometimes */
|
||||
virtual bool hasNameAnywhere(const string& nm);
|
||||
|
||||
/**
|
||||
* Return all subkeys
|
||||
*/
|
||||
@@ -207,13 +212,11 @@ public:
|
||||
* Copy constructor. Expensive but less so than a full rebuild
|
||||
*/
|
||||
ConfSimple(const ConfSimple &rhs)
|
||||
: ConfNull(), m_data(0)
|
||||
: ConfNull()
|
||||
{
|
||||
if ((status = rhs.status) == STATUS_ERROR)
|
||||
return;
|
||||
m_filename = rhs.m_filename;
|
||||
// Note: we just share the pointer, this doesnt belong to us
|
||||
m_data = rhs.m_data;
|
||||
m_submaps = rhs.m_submaps;
|
||||
}
|
||||
|
||||
@@ -224,8 +227,6 @@ public:
|
||||
{
|
||||
if (this != &rhs && (status = rhs.status) != STATUS_ERROR) {
|
||||
m_filename = rhs.m_filename;
|
||||
// Note: we don't own data. Just share the pointer
|
||||
m_data = rhs.m_data;
|
||||
m_submaps = rhs.m_submaps;
|
||||
}
|
||||
return *this;
|
||||
@@ -237,8 +238,6 @@ protected:
|
||||
private:
|
||||
// Set if we're working with a file
|
||||
string m_filename;
|
||||
// Set if we're working with an in-memory string
|
||||
string *m_data;
|
||||
// Configuration data submaps (one per subkey, the main data has a
|
||||
// null subkey)
|
||||
map<string, map<string, string> > m_submaps;
|
||||
@@ -281,7 +280,7 @@ public:
|
||||
* expansion */
|
||||
ConfTree(const char *fname, int readonly = 0)
|
||||
: ConfSimple(fname, readonly, true) {}
|
||||
ConfTree(string *data, int readonly = 0)
|
||||
ConfTree(const string &data, int readonly = 0)
|
||||
: ConfSimple(data, readonly, true) {}
|
||||
ConfTree(int readonly = 0)
|
||||
: ConfSimple(readonly, true) {}
|
||||
@@ -364,6 +363,16 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool hasNameAnywhere(const string& nm)
|
||||
{
|
||||
typename list<T*>::iterator it;
|
||||
for (it = m_confs.begin();it != m_confs.end();it++) {
|
||||
if ((*it)->hasNameAnywhere(nm))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int set(const string &nm, const string &val, const string &sk = string())
|
||||
{
|
||||
if (!m_ok)
|
||||
|
||||
Reference in New Issue
Block a user