diff --git a/src/utils/conftree.cpp b/src/utils/conftree.cpp index 7457c35c..be2eec73 100644 --- a/src/utils/conftree.cpp +++ b/src/utils/conftree.cpp @@ -52,6 +52,9 @@ using namespace std; #define LOGDEB(X) #endif +static const SimpleRegexp varcomment_rx("[ \t]*#[ \t]*([a-zA-Z0-9]+)[ \t]*=", + 0, 1); + void ConfSimple::parseinput(istream& input) { string submapkey; @@ -100,7 +103,12 @@ void ConfSimple::parseinput(istream& input) if (eof) { break; } - m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line)); + if (varcomment_rx.simpleMatch(line)) { + m_order.push_back(ConfLine(ConfLine::CFL_VARCOMMENT, line, + varcomment_rx.getMatch(line, 1))); + } else { + m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line)); + } continue; } if (line[line.length() - 1] == '\\') { @@ -118,12 +126,7 @@ void ConfSimple::parseinput(istream& input) submapkey = line; } m_subkeys_unsorted.push_back(submapkey); - - // No need for adding sk to order, will be done with first - // variable insert. Also means that empty section are - // expandable (won't be output when rewriting) - // Another option would be to add the subsec to m_order here - // and not do it inside i_set() if init is true + m_order.push_back(ConfLine(ConfLine::CFL_SK, submapkey)); continue; } @@ -371,11 +374,11 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value, submap[nm] = value; m_submaps[sk] = submap; - // Maybe add sk entry to m_order data: + // Maybe add sk entry to m_order data, if not already there. if (!sk.empty()) { ConfLine nl(ConfLine::CFL_SK, sk); // Append SK entry only if it's not already there (erase - // does not remove entries from the order data, adn it may + // does not remove entries from the order data, and it may // be being recreated after deletion) if (find(m_order.begin(), m_order.end(), nl) == m_order.end()) { m_order.push_back(nl); @@ -445,8 +448,23 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value, // It may happen that the order entry already exists because erase doesnt // update m_order if (find(start, fin, ConfLine(ConfLine::CFL_VAR, nm)) == fin) { - m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm)); + // Look for a varcomment line, insert the value right after if + // it's there. + bool inserted(false); + vector::iterator it; + for (it = start; it != fin; it++) { + if (it->m_kind == ConfLine::CFL_VARCOMMENT && it->m_aux == nm) { + it++; + m_order.insert(it, ConfLine(ConfLine::CFL_VAR, nm)); + inserted = true; + break; + } + } + if (!inserted) { + m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm)); + } } + return 1; } @@ -546,6 +564,7 @@ bool ConfSimple::write(ostream& out) const it != m_order.end(); it++) { switch (it->m_kind) { case ConfLine::CFL_COMMENT: + case ConfLine::CFL_VARCOMMENT: out << it->m_data << endl; if (!out.good()) { return false; @@ -644,6 +663,35 @@ bool ConfSimple::hasNameAnywhere(const string& nm) const return false; } +bool ConfSimple::commentsAsXML(ostream& out) +{ + const vector& lines = getlines(); + + out << "\n"; + + string sk; + for (vector::const_iterator it = lines.begin(); + it != lines.end(); it++) { + switch (it->m_kind) { + case ConfLine::CFL_COMMENT: + case ConfLine::CFL_VARCOMMENT: + { + string::size_type pos = it->m_data.find_first_not_of("# "); + if (pos != string::npos) { + out << it->m_data.substr(pos) << endl; + } + break; + } + default: + break; + } + } + out << "\n"; + + return true; +} + + // ////////////////////////////////////////////////////////////////////////// // ConfTree Methods: conftree interpret keys like a hierarchical file tree // ////////////////////////////////////////////////////////////////////////// diff --git a/src/utils/conftree.h b/src/utils/conftree.h index 58d9600d..d6111e84 100644 --- a/src/utils/conftree.h +++ b/src/utils/conftree.h @@ -74,11 +74,12 @@ using std::ostream; /** Internal class used for storing presentation information */ class ConfLine { public: - enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR}; + enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR, CFL_VARCOMMENT}; Kind m_kind; string m_data; - ConfLine(Kind k, const string& d) - : m_kind(k), m_data(d) { + string m_aux; + ConfLine(Kind k, const string& d, string a = string()) + : m_kind(k), m_data(d), m_aux(a) { } bool operator==(const ConfLine& o) { return o.m_kind == m_kind && o.m_data == m_data; @@ -239,10 +240,14 @@ public: virtual vector getSubKeys(bool) const { return getSubKeys(); } + virtual vector getSubKeys() const; + + /** Return subkeys in file order. BEWARE: only for the original from the + * file: the data is not duplicated to further copies */ virtual vector getSubKeys_unsorted(bool = false) const { return m_subkeys_unsorted; } - virtual vector getSubKeys() const; + /** Test for subkey existence */ virtual bool hasSubKey(const string& sk) const { return m_submaps.find(sk) != m_submaps.end(); @@ -252,6 +257,13 @@ public: return m_filename; } + /** Used with config files with specially formatted, xml-like comments. + * Extract the comments as text */ + virtual bool commentsAsXML(ostream& out); + + /** !! Note that assignment and copy constructor do not copy the + auxiliary data (m_order and subkeys_unsorted). */ + /** * Copy constructor. Expensive but less so than a full rebuild */ @@ -352,6 +364,7 @@ public: * @return 0 if name not found, 1 else */ virtual int get(const string& name, string& value, const string& sk) const; + using ConfSimple::get; }; /**