Switch to unified view

a/src/conftree.h b/src/conftree.h
...
...
63
#include <ostream>
63
#include <ostream>
64
#endif
64
#endif
65
65
66
#include "pathut.h"
66
#include "pathut.h"
67
67
68
using std::string;
69
using std::vector;
70
using std::map;
71
using std::istream;
72
using std::ostream;
73
74
/** Internal class used for storing presentation information */
68
/** Internal class used for storing presentation information */
75
class ConfLine {
69
class ConfLine {
76
public:
70
public:
77
    enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR, CFL_VARCOMMENT};
71
    enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR, CFL_VARCOMMENT};
78
    Kind m_kind;
72
    Kind m_kind;
79
    string m_data;
73
    std::string m_data;
80
    string m_aux;
74
    std::string m_aux;
81
    ConfLine(Kind k, const string& d, string a = string())
75
    ConfLine(Kind k, const std::string& d, std::string a = std::string())
82
        : m_kind(k), m_data(d), m_aux(a) {
76
        : m_kind(k), m_data(d), m_aux(a) {
83
    }
77
    }
84
    bool operator==(const ConfLine& o) {
78
    bool operator==(const ConfLine& o) {
85
        return o.m_kind == m_kind && o.m_data == m_data;
79
        return o.m_kind == m_kind && o.m_data == m_data;
86
    }
80
    }
...
...
91
 */
85
 */
92
class ConfNull {
86
class ConfNull {
93
public:
87
public:
94
    enum StatusCode {STATUS_ERROR = 0, STATUS_RO = 1, STATUS_RW = 2};
88
    enum StatusCode {STATUS_ERROR = 0, STATUS_RO = 1, STATUS_RW = 2};
95
    virtual ~ConfNull() {};
89
    virtual ~ConfNull() {};
96
    virtual int get(const string& name, string& value,
90
    virtual int get(const std::string& name, std::string& value,
97
                    const string& sk = string()) const = 0;
91
                    const std::string& sk = std::string()) const = 0;
98
    virtual bool hasNameAnywhere(const string& nm) const = 0;
92
    virtual bool hasNameAnywhere(const std::string& nm) const = 0;
99
    virtual int set(const string& nm, const string& val,
93
    virtual int set(const std::string& nm, const std::string& val,
100
                    const string& sk = string()) = 0;
94
                    const std::string& sk = std::string()) = 0;
101
    virtual bool ok() const = 0;
95
    virtual bool ok() const = 0;
102
    virtual vector<string> getNames(const string& sk, const char* = 0)const = 0;
96
    virtual std::vector<std::string> getNames(const std::string& sk,
97
                                              const char* = 0)const = 0;
103
    virtual int erase(const string&, const string&) = 0;
98
    virtual int erase(const std::string&, const std::string&) = 0;
104
    virtual int eraseKey(const string&) = 0;
99
    virtual int eraseKey(const std::string&) = 0;
105
    virtual void showall() const {};
100
    virtual void showall() const {};
106
    virtual vector<string> getSubKeys() const = 0;
101
    virtual std::vector<std::string> getSubKeys() const = 0;
107
    virtual vector<string> getSubKeys(bool) const = 0;
102
    virtual std::vector<std::string> getSubKeys(bool) const = 0;
108
    virtual bool holdWrites(bool) = 0;
103
    virtual bool holdWrites(bool) = 0;
109
    virtual bool sourceChanged() const = 0;
104
    virtual bool sourceChanged() const = 0;
110
};
105
};
111
106
112
/**
107
/**
...
...
128
     * Build the object by reading content from a string
123
     * Build the object by reading content from a string
129
     * @param data points to the data to parse.
124
     * @param data points to the data to parse.
130
     * @param readonly if true open readonly, else rw
125
     * @param readonly if true open readonly, else rw
131
     * @param tildexp  try tilde (home dir) expansion for subsection names
126
     * @param tildexp  try tilde (home dir) expansion for subsection names
132
     */
127
     */
133
    ConfSimple(const string& data, int readonly = 0, bool tildexp = false,
128
    ConfSimple(const std::string& data, int readonly = 0, bool tildexp = false,
134
               bool trimvalues = true);
129
               bool trimvalues = true);
135
130
136
    /**
131
    /**
137
     * Build an empty object. This will be memory only, with no backing store.
132
     * Build an empty object. This will be memory only, with no backing store.
138
     * @param readonly if true open read only, else rw
133
     * @param readonly if true open read only, else rw
...
...
158
            return true;
153
            return true;
159
        }
154
        }
160
    }
155
    }
161
156
162
    /** Clear, then reparse from string */
157
    /** Clear, then reparse from string */
163
    void reparse(const string& in);
158
    void reparse(const std::string& in);
164
159
165
    /** Clear all content */
160
    /** Clear all content */
166
    void clear() {
161
    void clear() {
167
        m_submaps.clear();
162
        m_submaps.clear();
168
        m_order.clear();
163
        m_order.clear();
...
...
171
    /**
166
    /**
172
     * Get string value for named parameter, from specified subsection (looks 
167
     * Get string value for named parameter, from specified subsection (looks 
173
     * in global space if sk is empty).
168
     * in global space if sk is empty).
174
     * @return 0 if name not found, 1 else
169
     * @return 0 if name not found, 1 else
175
     */
170
     */
176
    virtual int get(const string& name, string& value,
171
    virtual int get(const std::string& name, std::string& value,
177
                    const string& sk = string()) const;
172
                    const std::string& sk = std::string()) const;
178
173
179
    /**
174
    /**
180
     * Get integer value for named parameter, from specified subsection (looks 
175
     * Get integer value for named parameter, from specified subsection (looks 
181
     * in global space if sk is empty).
176
     * in global space if sk is empty).
182
     * @return 0 if name not found, 1 else
177
     * @return 0 if name not found, 1 else
183
     */
178
     */
184
    virtual int get(const string& name, int* value,
179
    virtual int get(const std::string& name, int* value,
185
                    const string& sk = string()) const;
180
                    const std::string& sk = std::string()) const;
186
181
187
182
188
    /**
183
    /**
189
     * Set value for named string parameter in specified subsection (or global)
184
     * Set value for named string parameter in specified subsection (or global)
190
     * @return 0 for error, 1 else
185
     * @return 0 for error, 1 else
191
     */
186
     */
192
    virtual int set(const string& nm, const string& val,
187
    virtual int set(const std::string& nm, const std::string& val,
193
                    const string& sk = string());
188
                    const std::string& sk = std::string());
194
    /**
189
    /**
195
     * Set value for named integer parameter in specified subsection (or global)
190
     * Set value for named integer parameter in specified subsection (or global)
196
     * @return 0 for error, 1 else
191
     * @return 0 for error, 1 else
197
     */
192
     */
198
    virtual int set(const string& nm, long long val,
193
    virtual int set(const std::string& nm, long long val,
199
                    const string& sk = string());
194
                    const std::string& sk = std::string());
200
195
201
    /**
196
    /**
202
     * Remove name and value from config
197
     * Remove name and value from config
203
     */
198
     */
204
    virtual int erase(const string& name, const string& sk);
199
    virtual int erase(const std::string& name, const std::string& sk);
205
200
206
    /**
201
    /**
207
     * Erase all names under given subkey (and subkey itself)
202
     * Erase all names under given subkey (and subkey itself)
208
     */
203
     */
209
    virtual int eraseKey(const string& sk);
204
    virtual int eraseKey(const std::string& sk);
210
205
211
    virtual StatusCode getStatus() const;
206
    virtual StatusCode getStatus() const;
212
    virtual bool ok() const {
207
    virtual bool ok() const {
213
        return getStatus() != STATUS_ERROR;
208
        return getStatus() != STATUS_ERROR;
214
    }
209
    }
...
...
220
     * @return WALK_STOP when/if the callback returns WALK_STOP,
215
     * @return WALK_STOP when/if the callback returns WALK_STOP,
221
     *         WALK_CONTINUE else (got to end of config)
216
     *         WALK_CONTINUE else (got to end of config)
222
     */
217
     */
223
    enum WalkerCode {WALK_STOP, WALK_CONTINUE};
218
    enum WalkerCode {WALK_STOP, WALK_CONTINUE};
224
    virtual WalkerCode sortwalk(WalkerCode
219
    virtual WalkerCode sortwalk(WalkerCode
225
                                (*wlkr)(void *cldata, const string& nm,
220
                                (*wlkr)(void *cldata, const std::string& nm,
226
                                        const string& val),
221
                                        const std::string& val),
227
                                void *clidata) const;
222
                                void *clidata) const;
228
223
229
    /** Print all values to stdout */
224
    /** Print all values to stdout */
230
    virtual void showall() const;
225
    virtual void showall() const;
231
226
232
    /** Return all names in given submap. */
227
    /** Return all names in given submap. */
233
    virtual vector<string> getNames(const string& sk, const char *pattern = 0)
228
    virtual std::vector<std::string> getNames(const std::string& sk,
234
    const;
229
                                              const char *pattern = 0) const;
235
230
236
    /** Check if name is present in any submap. This is relatively expensive
231
    /** Check if name is present in any submap. This is relatively expensive
237
     * but useful for saving further processing sometimes */
232
     * but useful for saving further processing sometimes */
238
    virtual bool hasNameAnywhere(const string& nm) const;
233
    virtual bool hasNameAnywhere(const std::string& nm) const;
239
234
240
    /**
235
    /**
241
     * Return all subkeys
236
     * Return all subkeys
242
     */
237
     */
243
    virtual vector<string> getSubKeys(bool) const {
238
    virtual std::vector<std::string> getSubKeys(bool) const {
244
        return getSubKeys();
239
        return getSubKeys();
245
    }
240
    }
246
    virtual vector<string> getSubKeys() const;
241
    virtual std::vector<std::string> getSubKeys() const;
247
    
242
    
248
    /** Return subkeys in file order. BEWARE: only for the original from the 
243
    /** Return subkeys in file order. BEWARE: only for the original from the 
249
     * file: the data is not duplicated to further copies */
244
     * file: the data is not duplicated to further copies */
250
    virtual vector<string> getSubKeys_unsorted(bool = false) const {
245
    virtual std::vector<std::string> getSubKeys_unsorted(bool = false) const {
251
        return m_subkeys_unsorted;
246
        return m_subkeys_unsorted;
252
    }
247
    }
253
248
254
    /** Test for subkey existence */
249
    /** Test for subkey existence */
255
    virtual bool hasSubKey(const string& sk) const {
250
    virtual bool hasSubKey(const std::string& sk) const {
256
        return m_submaps.find(sk) != m_submaps.end();
251
        return m_submaps.find(sk) != m_submaps.end();
257
    }
252
    }
258
253
259
    virtual string getFilename() const {
254
    virtual std::string getFilename() const {
260
        return m_filename;
255
        return m_filename;
261
    }
256
    }
262
257
263
    /** Used with config files with specially formatted, xml-like comments.
258
    /** Used with config files with specially formatted, xml-like comments.
264
     * Extract the comments as text */
259
     * Extract the comments as text */
265
    virtual bool commentsAsXML(ostream& out);
260
    virtual bool commentsAsXML(std::ostream& out);
266
261
267
    /** !! Note that assignment and copy constructor do not copy the
262
    /** !! Note that assignment and copy constructor do not copy the
268
        auxiliary data (m_order and subkeys_unsorted). */
263
        auxiliary data (m_order and subkeys_unsorted). */
269
    
264
    
270
    /**
265
    /**
...
...
293
    }
288
    }
294
289
295
    /**
290
    /**
296
     * Write in file format to out
291
     * Write in file format to out
297
     */
292
     */
298
    bool write(ostream& out) const;
293
    bool write(std::ostream& out) const;
299
294
300
    /** Give access to semi-parsed file contents */
295
    /** Give access to semi-parsed file contents */
301
    const vector<ConfLine>& getlines() const {
296
    const std::vector<ConfLine>& getlines() const {
302
        return m_order;
297
        return m_order;
303
    }
298
    }
304
    
299
    
305
protected:
300
protected:
306
    bool dotildexpand;
301
    bool dotildexpand;
307
    bool trimvalues;
302
    bool trimvalues;
308
    StatusCode status;
303
    StatusCode status;
309
private:
304
private:
310
    // Set if we're working with a file
305
    // Set if we're working with a file
311
    string                            m_filename;
306
    std::string                            m_filename;
312
    time_t                            m_fmtime;
307
    time_t                            m_fmtime;
313
    // Configuration data submaps (one per subkey, the main data has a
308
    // Configuration data submaps (one per subkey, the main data has a
314
    // null subkey)
309
    // null subkey)
315
    map<string, map<string, string> > m_submaps;
310
    std::map<std::string, std::map<std::string, std::string> > m_submaps;
316
    vector<string> m_subkeys_unsorted;
311
    std::vector<std::string> m_subkeys_unsorted;
317
    // Presentation data. We keep the comments, empty lines and
312
    // Presentation data. We keep the comments, empty lines and
318
    // variable and subkey ordering information in there (for
313
    // variable and subkey ordering information in there (for
319
    // rewriting the file while keeping hand-edited information)
314
    // rewriting the file while keeping hand-edited information)
320
    vector<ConfLine>                    m_order;
315
    std::vector<ConfLine>                    m_order;
321
    // Control if we're writing to the backing store
316
    // Control if we're writing to the backing store
322
    bool                              m_holdWrites;
317
    bool                              m_holdWrites;
323
318
324
    void parseinput(istream& input);
319
    void parseinput(std::istream& input);
325
    bool write();
320
    bool write();
326
    // Internal version of set: no RW checking
321
    // Internal version of set: no RW checking
327
    virtual int i_set(const string& nm, const string& val,
322
    virtual int i_set(const std::string& nm, const std::string& val,
328
                      const string& sk, bool init = false);
323
                      const std::string& sk, bool init = false);
329
    bool i_changed(bool upd);
324
    bool i_changed(bool upd);
330
};
325
};
331
326
332
/**
327
/**
333
 * This is a configuration class which attaches tree-like signification to the
328
 * This is a configuration class which attaches tree-like signification to the
...
...
351
public:
346
public:
352
    /* The constructors just call ConfSimple's, asking for key tilde
347
    /* The constructors just call ConfSimple's, asking for key tilde
353
     * expansion */
348
     * expansion */
354
    ConfTree(const char *fname, int readonly = 0, bool trimvalues=true)
349
    ConfTree(const char *fname, int readonly = 0, bool trimvalues=true)
355
        : ConfSimple(fname, readonly, true, trimvalues) {}
350
        : ConfSimple(fname, readonly, true, trimvalues) {}
356
    ConfTree(const string& data, int readonly = 0, bool trimvalues=true)
351
    ConfTree(const std::string& data, int readonly = 0, bool trimvalues=true)
357
        : ConfSimple(data, readonly, true, trimvalues) {}
352
        : ConfSimple(data, readonly, true, trimvalues) {}
358
    ConfTree(int readonly = 0, bool trimvalues=true)
353
    ConfTree(int readonly = 0, bool trimvalues=true)
359
        : ConfSimple(readonly, true, trimvalues) {}
354
        : ConfSimple(readonly, true, trimvalues) {}
360
    virtual ~ConfTree() {};
355
    virtual ~ConfTree() {};
361
    ConfTree(const ConfTree& r) : ConfSimple(r) {};
356
    ConfTree(const ConfTree& r) : ConfSimple(r) {};
...
...
367
    /**
362
    /**
368
     * Get value for named parameter, from specified subsection, or its
363
     * Get value for named parameter, from specified subsection, or its
369
     * parents.
364
     * parents.
370
     * @return 0 if name not found, 1 else
365
     * @return 0 if name not found, 1 else
371
     */
366
     */
372
    virtual int get(const string& name, string& value, const string& sk) const;
367
    virtual int get(const std::string& name, std::string& value,
368
                    const std::string& sk) const;
373
    using ConfSimple::get;
369
    using ConfSimple::get;
374
};
370
};
375
371
376
/**
372
/**
377
 * Use several config files, trying to get values from each in order. Used to
373
 * Use several config files, trying to get values from each in order. Used to
...
...
387
template <class T> class ConfStack : public ConfNull {
383
template <class T> class ConfStack : public ConfNull {
388
public:
384
public:
389
    /// Construct from configuration file names. The earler
385
    /// Construct from configuration file names. The earler
390
    /// files in have priority when fetching values. Only the first
386
    /// files in have priority when fetching values. Only the first
391
    /// file will be updated if ro is false and set() is used.
387
    /// file will be updated if ro is false and set() is used.
392
    ConfStack(const vector<string>& fns, bool ro = true) {
388
    ConfStack(const std::vector<std::string>& fns, bool ro = true) {
393
        construct(fns, ro);
389
        construct(fns, ro);
394
    }
390
    }
395
    /// Construct out of single file name and multiple directories
391
    /// Construct out of single file name and multiple directories
396
    ConfStack(const string& nm, const vector<string>& dirs, bool ro = true) {
392
    ConfStack(const std::string& nm, const std::vector<std::string>& dirs,
393
              bool ro = true) {
397
        vector<string> fns;
394
        std::vector<std::string> fns;
398
        for (vector<string>::const_iterator it = dirs.begin();
395
        for (std::vector<std::string>::const_iterator it = dirs.begin();
399
                it != dirs.end(); it++) {
396
                it != dirs.end(); it++) {
400
            fns.push_back(path_cat(*it, nm));
397
            fns.push_back(path_cat(*it, nm));
401
        }
398
        }
402
        ConfStack::construct(fns, ro);
399
        ConfStack::construct(fns, ro);
403
    }
400
    }
...
...
422
        }
419
        }
423
        return *this;
420
        return *this;
424
    }
421
    }
425
422
426
    virtual bool sourceChanged() const {
423
    virtual bool sourceChanged() const {
427
        typename vector<T*>::const_iterator it;
424
        typename std::vector<T*>::const_iterator it;
428
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
425
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
429
            if ((*it)->sourceChanged()) {
426
            if ((*it)->sourceChanged()) {
430
                return true;
427
                return true;
431
            }
428
            }
432
        }
429
        }
433
        return false;
430
        return false;
434
    }
431
    }
435
432
436
    virtual int get(const string& name, string& value, const string& sk,
433
    virtual int get(const std::string& name, std::string& value,
437
                    bool shallow) const {
434
                    const std::string& sk, bool shallow) const {
438
        typename vector<T*>::const_iterator it;
435
        typename std::vector<T*>::const_iterator it;
439
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
436
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
440
            if ((*it)->get(name, value, sk)) {
437
            if ((*it)->get(name, value, sk)) {
441
                return true;
438
                return true;
442
            }
439
            }
443
            if (shallow) {
440
            if (shallow) {
444
                break;
441
                break;
445
            }
442
            }
446
        }
443
        }
447
        return false;
444
        return false;
448
    }
445
    }
449
    virtual int get(const string& name, string& value, const string& sk) const {
446
    virtual int get(const std::string& name, std::string& value,
447
                    const std::string& sk) const {
450
        return get(name, value, sk, false);
448
        return get(name, value, sk, false);
451
    }
449
    }
452
450
453
    virtual bool hasNameAnywhere(const string& nm) const {
451
    virtual bool hasNameAnywhere(const std::string& nm) const {
454
        typename vector<T*>::const_iterator it;
452
        typename std::vector<T*>::const_iterator it;
455
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
453
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
456
            if ((*it)->hasNameAnywhere(nm)) {
454
            if ((*it)->hasNameAnywhere(nm)) {
457
                return true;
455
                return true;
458
            }
456
            }
459
        }
457
        }
460
        return false;
458
        return false;
461
    }
459
    }
462
460
463
    virtual int set(const string& nm, const string& val,
461
    virtual int set(const std::string& nm, const std::string& val,
464
                    const string& sk = string()) {
462
                    const std::string& sk = std::string()) {
465
        if (!m_ok) {
463
        if (!m_ok) {
466
            return 0;
464
            return 0;
467
        }
465
        }
468
        //LOGDEB2(("ConfStack::set [%s]:[%s] -> [%s]\n", sk.c_str(),
466
        //LOGDEB2(("ConfStack::set [%s]:[%s] -> [%s]\n", sk.c_str(),
469
        //nm.c_str(), val.c_str()));
467
        //nm.c_str(), val.c_str()));
470
        // Avoid adding unneeded entries: if the new value matches the
468
        // Avoid adding unneeded entries: if the new value matches the
471
        // one out from the deeper configs, erase or dont add it
469
        // one out from the deeper configs, erase or dont add it
472
        // from/to the topmost file
470
        // from/to the topmost file
473
        typename vector<T*>::iterator it = m_confs.begin();
471
        typename std::vector<T*>::iterator it = m_confs.begin();
474
        it++;
472
        it++;
475
        while (it != m_confs.end()) {
473
        while (it != m_confs.end()) {
476
            string value;
474
            std::string value;
477
            if ((*it)->get(nm, value, sk)) {
475
            if ((*it)->get(nm, value, sk)) {
478
                // This file has value for nm/sk. If it is the same as the new
476
                // This file has value for nm/sk. If it is the same as the new
479
                // one, no need for an entry in the topmost file. Else, stop
477
                // one, no need for an entry in the topmost file. Else, stop
480
                // looking and add the new entry
478
                // looking and add the new entry
481
                if (value == val) {
479
                if (value == val) {
...
...
489
        }
487
        }
490
488
491
        return m_confs.front()->set(nm, val, sk);
489
        return m_confs.front()->set(nm, val, sk);
492
    }
490
    }
493
491
494
    virtual int erase(const string& nm, const string& sk) {
492
    virtual int erase(const std::string& nm, const std::string& sk) {
495
        return m_confs.front()->erase(nm, sk);
493
        return m_confs.front()->erase(nm, sk);
496
    }
494
    }
497
    virtual int eraseKey(const string& sk) {
495
    virtual int eraseKey(const std::string& sk) {
498
        return m_confs.front()->eraseKey(sk);
496
        return m_confs.front()->eraseKey(sk);
499
    }
497
    }
500
    virtual bool holdWrites(bool on) {
498
    virtual bool holdWrites(bool on) {
501
        return m_confs.front()->holdWrites(on);
499
        return m_confs.front()->holdWrites(on);
502
    }
500
    }
503
501
504
    virtual vector<string> getNames(const string& sk, const char *pattern = 0)
502
    virtual std::vector<std::string> getNames(const std::string& sk,
505
    const {
503
                                              const char *pattern = 0) const {
506
        return getNames1(sk, pattern, false);
504
        return getNames1(sk, pattern, false);
507
    }
505
    }
508
    virtual vector<string> getNamesShallow(const string& sk,
506
    virtual std::vector<std::string> getNamesShallow(const std::string& sk,
509
                                           const char *patt = 0) const {
507
                                           const char *patt = 0) const {
510
        return getNames1(sk, patt, true);
508
        return getNames1(sk, patt, true);
511
    }
509
    }
512
510
513
    virtual vector<string> getNames1(const string& sk, const char *pattern,
511
    virtual std::vector<std::string> getNames1(
514
                                     bool shallow) const {
512
        const std::string& sk, const char *pattern, bool shallow) const {
515
        vector<string> nms;
513
        std::vector<std::string> nms;
516
        typename vector<T*>::const_iterator it;
514
        typename std::vector<T*>::const_iterator it;
517
        bool skfound = false;
515
        bool skfound = false;
518
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
516
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
519
            if ((*it)->hasSubKey(sk)) {
517
            if ((*it)->hasSubKey(sk)) {
520
                skfound = true;
518
                skfound = true;
521
                vector<string> lst = (*it)->getNames(sk, pattern);
519
                std::vector<std::string> lst = (*it)->getNames(sk, pattern);
522
                nms.insert(nms.end(), lst.begin(), lst.end());
520
                nms.insert(nms.end(), lst.begin(), lst.end());
523
            }
521
            }
524
            if (shallow && skfound) {
522
            if (shallow && skfound) {
525
                break;
523
                break;
526
            }
524
            }
527
        }
525
        }
528
        sort(nms.begin(), nms.end());
526
        sort(nms.begin(), nms.end());
529
        vector<string>::iterator uit = unique(nms.begin(), nms.end());
527
        std::vector<std::string>::iterator uit = unique(nms.begin(), nms.end());
530
        nms.resize(uit - nms.begin());
528
        nms.resize(uit - nms.begin());
531
        return nms;
529
        return nms;
532
    }
530
    }
533
531
534
    virtual vector<string> getSubKeys() const {
532
    virtual std::vector<std::string> getSubKeys() const {
535
        return getSubKeys(false);
533
        return getSubKeys(false);
536
    }
534
    }
537
    virtual vector<string> getSubKeys(bool shallow) const {
535
    virtual std::vector<std::string> getSubKeys(bool shallow) const {
538
        vector<string> sks;
536
        std::vector<std::string> sks;
539
        typename vector<T*>::const_iterator it;
537
        typename std::vector<T*>::const_iterator it;
540
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
538
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
541
            vector<string> lst;
539
            std::vector<std::string> lst;
542
            lst = (*it)->getSubKeys();
540
            lst = (*it)->getSubKeys();
543
            sks.insert(sks.end(), lst.begin(), lst.end());
541
            sks.insert(sks.end(), lst.begin(), lst.end());
544
            if (shallow) {
542
            if (shallow) {
545
                break;
543
                break;
546
            }
544
            }
547
        }
545
        }
548
        sort(sks.begin(), sks.end());
546
        sort(sks.begin(), sks.end());
549
        vector<string>::iterator uit = unique(sks.begin(), sks.end());
547
        std::vector<std::string>::iterator uit = unique(sks.begin(), sks.end());
550
        sks.resize(uit - sks.begin());
548
        sks.resize(uit - sks.begin());
551
        return sks;
549
        return sks;
552
    }
550
    }
553
551
554
    virtual bool ok() const {
552
    virtual bool ok() const {
555
        return m_ok;
553
        return m_ok;
556
    }
554
    }
557
555
558
private:
556
private:
559
    bool     m_ok;
557
    bool     m_ok;
560
    vector<T*> m_confs;
558
    std::vector<T*> m_confs;
561
559
562
    /// Reset to pristine
560
    /// Reset to pristine
563
    void clear() {
561
    void clear() {
564
        typename vector<T*>::iterator it;
562
        typename std::vector<T*>::iterator it;
565
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
563
        for (it = m_confs.begin(); it != m_confs.end(); it++) {
566
            delete(*it);
564
            delete(*it);
567
        }
565
        }
568
        m_confs.clear();
566
        m_confs.clear();
569
    }
567
    }
570
568
571
    /// Common code to initialize from existing object
569
    /// Common code to initialize from existing object
572
    void init_from(const ConfStack& rhs) {
570
    void init_from(const ConfStack& rhs) {
573
        if ((m_ok = rhs.m_ok)) {
571
        if ((m_ok = rhs.m_ok)) {
574
            typename vector<T*>::const_iterator it;
572
            typename std::vector<T*>::const_iterator it;
575
            for (it = rhs.m_confs.begin(); it != rhs.m_confs.end(); it++) {
573
            for (it = rhs.m_confs.begin(); it != rhs.m_confs.end(); it++) {
576
                m_confs.push_back(new T(**it));
574
                m_confs.push_back(new T(**it));
577
            }
575
            }
578
        }
576
        }
579
    }
577
    }
580
578
581
    /// Common construct from file names code
579
    /// Common construct from file names code
582
    void construct(const vector<string>& fns, bool ro) {
580
    void construct(const std::vector<std::string>& fns, bool ro) {
583
        vector<string>::const_iterator it;
581
        std::vector<std::string>::const_iterator it;
584
        bool lastok = false;
582
        bool lastok = false;
585
        for (it = fns.begin(); it != fns.end(); it++) {
583
        for (it = fns.begin(); it != fns.end(); it++) {
586
            T* p = new T(it->c_str(), ro);
584
            T* p = new T(it->c_str(), ro);
587
            if (p && p->ok()) {
585
            if (p && p->ok()) {
588
                m_confs.push_back(p);
586
                m_confs.push_back(p);