|
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);
|