Switch to side-by-side view

--- a/src/utils/conftree.h
+++ b/src/utils/conftree.h
@@ -16,6 +16,7 @@
  */
 #ifndef _CONFTREE_H_
 #define  _CONFTREE_H_
+
 /**
  * A simple configuration file implementation.
  *
@@ -31,6 +32,7 @@
  * Any line without a '=' is discarded when rewriting the file.
  * All 'set' calls currently cause an immediate file rewrite.
  */
+
 #include <string>
 #include <map>
 #include <list>
@@ -77,15 +79,9 @@
      * global space if sk is empty).
      * @return 0 if name not found, 1 else
      */
-    virtual int get(const std::string &name, string &value, const string &sk);
-    virtual int get(const std::string &name, string &value) {
-	return get(name, value, string(""));
-    }
-    /*
-     * See comments for std::string variant
-     * @return 0 if name not found, const C string else
-     */
-    virtual const char *get(const char *name, const char *sk = 0);
+    virtual int get(const std::string &name, string &value, 
+		    const string &sk = string(""));
+    /* Note: the version returning char* was buggy and has been removed */
 
     /** 
      * Set value for named parameter in specified subsection (or global)
@@ -155,8 +151,8 @@
 
  protected:
     bool dotildexpand;
+    StatusCode status;
  private:
-    StatusCode status;
     string filename; // set if we're working with a file
     string *data;    // set if we're working with an in-memory string
     map<string, map<string, string> > submaps;
@@ -179,9 +175,6 @@
  * be searched at all.
  */
 class ConfTree : public ConfSimple {
-
-    /* Dont want this to be accessible: keep only the string-based one */
-    virtual const char *get(const char *, const char *) {return 0;}
 
  public:
     /**
@@ -208,4 +201,111 @@
     }
 };
 
+/** 
+ * Use several config files, trying to get values from each in order. Used to
+ * have a central config, with possible overrides from more specific
+ * (ie personal) ones.
+ *
+ * Notes: it's ok for some of the files in the list to not exist, but the last
+ * one must or we generate an error. We open all trees readonly.
+ */
+template <class T> class ConfStack {
+ public:
+    ConfStack(const std::list<string> &fns, bool ro = true) {
+	construct(fns, ro);
+    }
+
+    ConfStack(const char *nm, bool ro = true) {
+	std::list<string> fns;
+	fns.push_back(string(nm));
+	construct(fns, ro);
+    }
+
+    ~ConfStack() {
+	erase();
+	m_ok = false;
+    }
+
+    ConfStack(const ConfStack &rhs) {
+	init_from(rhs);
+    }
+
+    ConfStack& operator=(const ConfStack &rhs) {
+	if (this != &rhs){
+	    erase();
+	    m_ok = rhs.m_ok;
+	    if (m_ok)
+		init_from(rhs);
+	}
+	return *this;
+    }
+
+    int get(const std::string &name, string &value, const string &sk) {
+	typename std::list<T*>::iterator it;
+	for (it = m_confs.begin();it != m_confs.end();it++) {
+	    if ((*it)->get(name, value, sk))
+		return true;
+	}
+	return false;
+    }
+
+    int get(const char *name, string &value, const char *sk) {
+	return get(string(name), value, sk ? string(sk) : string(""));
+    }
+
+    std::list<string> getNames(const string &sk) {
+	std::list<string> nms;
+	typename std::list<T*>::iterator it;
+	for (it = m_confs.begin();it != m_confs.end();it++) {
+	    std::list<string> lst;
+	    lst = (*it)->getNames(sk);
+	    nms.splice(nms.end(), lst);
+	}
+	return nms;
+    }
+
+    bool ok() {return m_ok;}
+
+ private:
+    bool m_ok;
+    std::list<T*> m_confs;
+    
+    void erase() {
+	typename std::list<T*>::iterator it;
+	for (it = m_confs.begin();it != m_confs.end();it++) {
+	    delete (*it);
+	}
+	m_confs.clear();
+    }
+
+    /// Common code to initialize from existing object
+    void init_from(const ConfStack &rhs) {
+	if ((m_ok = rhs.m_ok)) {
+	    typename std::list<T*>::const_iterator it;
+	    for (it = rhs.m_confs.begin();it != rhs.m_confs.end();it++) {
+		m_confs.push_back(new T(**it));
+	    }
+	}
+    }
+
+    /// Common constructor code
+    void construct(const std::list<string> &fns, bool ro) {
+	if (!ro) {
+	    m_ok = false;
+	    return;
+	}
+	std::list<std::string>::const_iterator it;
+	bool lastok = false;
+	for (it = fns.begin();it != fns.end();it++) {
+	    T* p = new T(it->c_str(), true);
+	    if (p && p->ok()) {
+		m_confs.push_back(p);
+		lastok = true;
+	    } else
+		lastok = false;
+	}
+	m_ok = lastok;
+    }
+};
+
 #endif /*_CONFTREE_H_ */