|
a/src/conftree.cpp |
|
b/src/conftree.cpp |
|
... |
|
... |
40 |
#include <sstream>
|
40 |
#include <sstream>
|
41 |
#include <utility>
|
41 |
#include <utility>
|
42 |
|
42 |
|
43 |
#include "pathut.h"
|
43 |
#include "pathut.h"
|
44 |
#include "smallut.h"
|
44 |
#include "smallut.h"
|
|
|
45 |
#include "log.h"
|
45 |
|
46 |
|
46 |
using namespace std;
|
47 |
using namespace std;
|
47 |
|
48 |
|
48 |
#undef DEBUG
|
49 |
#undef DEBUG_CONFTREE
|
49 |
#ifdef DEBUG
|
50 |
#ifdef DEBUG_CONFTREE
|
50 |
#define LOGDEB(X) fprintf X
|
51 |
#define CONFDEB LOGDEB
|
51 |
#else
|
52 |
#else
|
52 |
#define LOGDEB(X)
|
53 |
#define CONFDEB LOGDEB2
|
53 |
#endif
|
54 |
#endif
|
54 |
|
55 |
|
55 |
static const SimpleRegexp varcomment_rx("[ \t]*#[ \t]*([a-zA-Z0-9]+)[ \t]*=",
|
56 |
static const SimpleRegexp varcomment_rx("[ \t]*#[ \t]*([a-zA-Z0-9]+)[ \t]*=",
|
56 |
0, 1);
|
57 |
0, 1);
|
57 |
|
58 |
|
|
... |
|
... |
64 |
bool eof = false;
|
65 |
bool eof = false;
|
65 |
|
66 |
|
66 |
for (;;) {
|
67 |
for (;;) {
|
67 |
cline.clear();
|
68 |
cline.clear();
|
68 |
std::getline(input, cline);
|
69 |
std::getline(input, cline);
|
69 |
LOGDEB((stderr, "Parse:line: [%s] status %d\n",
|
70 |
CONFDEB("Parse:line: [" << cline << "] status " << status << "\n");
|
70 |
cline.c_str(), int(status)));
|
|
|
71 |
if (!input.good()) {
|
71 |
if (!input.good()) {
|
72 |
if (input.bad()) {
|
72 |
if (input.bad()) {
|
73 |
LOGDEB((stderr, "Parse: input.bad()\n"));
|
73 |
CONFDEB("Parse: input.bad()\n");
|
74 |
status = STATUS_ERROR;
|
74 |
status = STATUS_ERROR;
|
75 |
return;
|
75 |
return;
|
76 |
}
|
76 |
}
|
77 |
LOGDEB((stderr, "Parse: eof\n"));
|
77 |
CONFDEB("Parse: eof\n");
|
78 |
// Must be eof ? But maybe we have a partial line which
|
78 |
// Must be eof ? But maybe we have a partial line which
|
79 |
// must be processed. This happens if the last line before
|
79 |
// must be processed. This happens if the last line before
|
80 |
// eof ends with a backslash, or there is no final \n
|
80 |
// eof ends with a backslash, or there is no final \n
|
81 |
eof = true;
|
81 |
eof = true;
|
82 |
}
|
82 |
}
|
|
... |
|
... |
336 |
const string& sk)
|
336 |
const string& sk)
|
337 |
{
|
337 |
{
|
338 |
if (status != STATUS_RW) {
|
338 |
if (status != STATUS_RW) {
|
339 |
return 0;
|
339 |
return 0;
|
340 |
}
|
340 |
}
|
341 |
LOGDEB((stderr, "ConfSimple::set [%s]:[%s] -> [%s]\n", sk.c_str(),
|
341 |
CONFDEB("ConfSimple::set ["<<sk<< "]:[" << nm << "] -> [" << value << "]\n");
|
342 |
nm.c_str(), value.c_str()));
|
|
|
343 |
if (!i_set(nm, value, sk)) {
|
342 |
if (!i_set(nm, value, sk)) {
|
344 |
return 0;
|
343 |
return 0;
|
345 |
}
|
344 |
}
|
346 |
return write();
|
345 |
return write();
|
347 |
}
|
346 |
}
|
|
... |
|
... |
356 |
// set, we're doing initial parsing, else we are changing a parsed
|
355 |
// set, we're doing initial parsing, else we are changing a parsed
|
357 |
// tree (changes the way we update the order data)
|
356 |
// tree (changes the way we update the order data)
|
358 |
int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
357 |
int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
359 |
const string& sk, bool init)
|
358 |
const string& sk, bool init)
|
360 |
{
|
359 |
{
|
361 |
LOGDEB((stderr, "ConfSimple::i_set: nm[%s] val[%s] key[%s], init %d\n",
|
360 |
CONFDEB("ConfSimple::i_set: nm[" << nm << "] val[" << value <<
|
362 |
nm.c_str(), value.c_str(), sk.c_str(), init));
|
361 |
"] key[" << sk << "], init " << init << "\n");
|
363 |
// Values must not have embedded newlines
|
362 |
// Values must not have embedded newlines
|
364 |
if (value.find_first_of("\n\r") != string::npos) {
|
363 |
if (value.find_first_of("\n\r") != string::npos) {
|
365 |
LOGDEB((stderr, "ConfSimple::i_set: LF in value\n"));
|
364 |
CONFDEB("ConfSimple::i_set: LF in value\n");
|
366 |
return 0;
|
365 |
return 0;
|
367 |
}
|
366 |
}
|
368 |
bool existing = false;
|
367 |
bool existing = false;
|
369 |
map<string, map<string, string> >::iterator ss;
|
368 |
map<string, map<string, string> >::iterator ss;
|
370 |
// Test if submap already exists, else create it, and insert variable:
|
369 |
// Test if submap already exists, else create it, and insert variable:
|
371 |
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
370 |
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
372 |
LOGDEB((stderr, "ConfSimple::i_set: new submap\n"));
|
371 |
CONFDEB("ConfSimple::i_set: new submap\n");
|
373 |
map<string, string> submap;
|
372 |
map<string, string> submap;
|
374 |
submap[nm] = value;
|
373 |
submap[nm] = value;
|
375 |
m_submaps[sk] = submap;
|
374 |
m_submaps[sk] = submap;
|
376 |
|
375 |
|
377 |
// Maybe add sk entry to m_order data, if not already there.
|
376 |
// Maybe add sk entry to m_order data, if not already there.
|
|
... |
|
... |
396 |
}
|
395 |
}
|
397 |
}
|
396 |
}
|
398 |
|
397 |
|
399 |
// If the variable already existed, no need to change the m_order data
|
398 |
// If the variable already existed, no need to change the m_order data
|
400 |
if (existing) {
|
399 |
if (existing) {
|
401 |
LOGDEB((stderr, "ConfSimple::i_set: existing var: no order update\n"));
|
400 |
CONFDEB("ConfSimple::i_set: existing var: no order update\n");
|
402 |
return 1;
|
401 |
return 1;
|
403 |
}
|
402 |
}
|
404 |
|
403 |
|
405 |
// Add the new variable at the end of its submap in the order data.
|
404 |
// Add the new variable at the end of its submap in the order data.
|
406 |
|
405 |
|
407 |
if (init) {
|
406 |
if (init) {
|
408 |
// During the initial construction, just append:
|
407 |
// During the initial construction, just append:
|
409 |
LOGDEB((stderr, "ConfSimple::i_set: init true: append\n"));
|
408 |
CONFDEB("ConfSimple::i_set: init true: append\n");
|
410 |
m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
|
409 |
m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
|
411 |
return 1;
|
410 |
return 1;
|
412 |
}
|
411 |
}
|
413 |
|
412 |
|
414 |
// Look for the start and end of the subkey zone. Start is either
|
413 |
// Look for the start and end of the subkey zone. Start is either
|
|
... |
|
... |
416 |
// entry. End is either the next subkey entry, or the end of
|
415 |
// entry. End is either the next subkey entry, or the end of
|
417 |
// list. We insert the new entry just before end.
|
416 |
// list. We insert the new entry just before end.
|
418 |
vector<ConfLine>::iterator start, fin;
|
417 |
vector<ConfLine>::iterator start, fin;
|
419 |
if (sk.empty()) {
|
418 |
if (sk.empty()) {
|
420 |
start = m_order.begin();
|
419 |
start = m_order.begin();
|
421 |
LOGDEB((stderr, "ConfSimple::i_set: null sk, start at top of order\n"));
|
420 |
CONFDEB("ConfSimple::i_set: null sk, start at top of order\n");
|
422 |
} else {
|
421 |
} else {
|
423 |
start = find(m_order.begin(), m_order.end(),
|
422 |
start = find(m_order.begin(), m_order.end(),
|
424 |
ConfLine(ConfLine::CFL_SK, sk));
|
423 |
ConfLine(ConfLine::CFL_SK, sk));
|
425 |
if (start == m_order.end()) {
|
424 |
if (start == m_order.end()) {
|
426 |
// This is not logically possible. The subkey must
|
425 |
// This is not logically possible. The subkey must
|
|
... |
|
... |
570 |
return false;
|
569 |
return false;
|
571 |
}
|
570 |
}
|
572 |
break;
|
571 |
break;
|
573 |
case ConfLine::CFL_SK:
|
572 |
case ConfLine::CFL_SK:
|
574 |
sk = it->m_data;
|
573 |
sk = it->m_data;
|
575 |
LOGDEB((stderr, "ConfSimple::write: SK [%s]\n", sk.c_str()));
|
574 |
CONFDEB("ConfSimple::write: SK [" << sk << "]\n");
|
576 |
// Check that the submap still exists, and only output it if it
|
575 |
// Check that the submap still exists, and only output it if it
|
577 |
// does
|
576 |
// does
|
578 |
if (m_submaps.find(sk) != m_submaps.end()) {
|
577 |
if (m_submaps.find(sk) != m_submaps.end()) {
|
579 |
out << "[" << it->m_data << "]" << endl;
|
578 |
out << "[" << it->m_data << "]" << endl;
|
580 |
if (!out.good()) {
|
579 |
if (!out.good()) {
|
|
... |
|
... |
582 |
}
|
581 |
}
|
583 |
}
|
582 |
}
|
584 |
break;
|
583 |
break;
|
585 |
case ConfLine::CFL_VAR:
|
584 |
case ConfLine::CFL_VAR:
|
586 |
string nm = it->m_data;
|
585 |
string nm = it->m_data;
|
587 |
LOGDEB((stderr, "ConfSimple::write: VAR [%s], sk [%s]\n",
|
586 |
CONFDEB("ConfSimple::write: VAR [" << nm << "], sk [" <<sk<< "]\n");
|
588 |
nm.c_str(), sk.c_str()));
|
|
|
589 |
// As erase() doesnt update m_order we can find unexisting
|
587 |
// As erase() doesnt update m_order we can find unexisting
|
590 |
// variables, and must not output anything for them. Have
|
588 |
// variables, and must not output anything for them. Have
|
591 |
// to use a ConfSimple::get() to check here, because
|
589 |
// to use a ConfSimple::get() to check here, because
|
592 |
// ConfTree's could retrieve from an ancestor even if the
|
590 |
// ConfTree's could retrieve from an ancestor even if the
|
593 |
// local var is gone.
|
591 |
// local var is gone.
|
|
... |
|
... |
597 |
if (!out.good()) {
|
595 |
if (!out.good()) {
|
598 |
return false;
|
596 |
return false;
|
599 |
}
|
597 |
}
|
600 |
break;
|
598 |
break;
|
601 |
}
|
599 |
}
|
602 |
LOGDEB((stderr, "ConfSimple::write: no value: nm[%s] sk[%s]\n",
|
600 |
CONFDEB("ConfSimple::write: no value: nm["<<nm<<"] sk["<<sk<< "]\n");
|
603 |
nm.c_str(), sk.c_str()));
|
|
|
604 |
break;
|
601 |
break;
|
605 |
}
|
602 |
}
|
606 |
}
|
603 |
}
|
607 |
return true;
|
604 |
return true;
|
608 |
}
|
605 |
}
|
|
... |
|
... |
698 |
|
695 |
|
699 |
int ConfTree::get(const std::string& name, string& value, const string& sk)
|
696 |
int ConfTree::get(const std::string& name, string& value, const string& sk)
|
700 |
const
|
697 |
const
|
701 |
{
|
698 |
{
|
702 |
if (sk.empty() || !path_isabsolute(sk)) {
|
699 |
if (sk.empty() || !path_isabsolute(sk)) {
|
703 |
// LOGDEB((stderr, "ConfTree::get: looking in global space for [%s]\n",
|
700 |
LOGDEB2("ConfTree::get: looking in global space for [" <<
|
704 |
// sk.c_str()));
|
701 |
sk << "]\n");
|
705 |
return ConfSimple::get(name, value, sk);
|
702 |
return ConfSimple::get(name, value, sk);
|
706 |
}
|
703 |
}
|
707 |
|
704 |
|
708 |
// Get writable copy of subkey path
|
705 |
// Get writable copy of subkey path
|
709 |
string msk = sk;
|
706 |
string msk = sk;
|
|
... |
|
... |
712 |
// the input sk
|
709 |
// the input sk
|
713 |
path_catslash(msk);
|
710 |
path_catslash(msk);
|
714 |
|
711 |
|
715 |
// Look in subkey and up its parents until root ('')
|
712 |
// Look in subkey and up its parents until root ('')
|
716 |
for (;;) {
|
713 |
for (;;) {
|
717 |
// LOGDEB((stderr,"ConfTree::get: looking for '%s' in '%s'\n",
|
714 |
LOGDEB2("ConfTree::get: looking for [" << name << "] in [" <<
|
718 |
// name.c_str(), msk.c_str()));
|
715 |
msk << "]\n");
|
719 |
if (ConfSimple::get(name, value, msk)) {
|
716 |
if (ConfSimple::get(name, value, msk)) {
|
720 |
return 1;
|
717 |
return 1;
|
721 |
}
|
718 |
}
|
722 |
string::size_type pos = msk.rfind("/");
|
719 |
string::size_type pos = msk.rfind("/");
|
723 |
if (pos != string::npos) {
|
720 |
if (pos != string::npos) {
|
|
... |
|
... |
731 |
break;
|
728 |
break;
|
732 |
}
|
729 |
}
|
733 |
}
|
730 |
}
|
734 |
return 0;
|
731 |
return 0;
|
735 |
}
|
732 |
}
|
|
|
733 |
|