have conftree preserve comments and ordering
This commit is contained in:
parent
767e4c01c8
commit
3ef569c5db
@ -74,7 +74,7 @@ trutf8iter.o : utf8iter.cpp utf8iter.h
|
|||||||
|
|
||||||
|
|
||||||
CONFTREE_OBJS= trconftree.o ../lib/pathut.o ../lib/smallut.o ../lib/conftree.o
|
CONFTREE_OBJS= trconftree.o ../lib/pathut.o ../lib/smallut.o ../lib/conftree.o
|
||||||
trconftree : $(CONFTREE_OBJS)
|
trconftree : $(CONFTREE_OBJS) $(BIGLIB)
|
||||||
$(CXX) $(ALL_CXXFLAGS) -o trconftree $(CONFTREE_OBJS)
|
$(CXX) $(ALL_CXXFLAGS) -o trconftree $(CONFTREE_OBJS)
|
||||||
trconftree.o : conftree.cpp
|
trconftree.o : conftree.cpp
|
||||||
$(CXX) $(ALL_CXXFLAGS) -DTEST_CONFTREE -c -o trconftree.o \
|
$(CXX) $(ALL_CXXFLAGS) -DTEST_CONFTREE -c -o trconftree.o \
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#ifndef lint
|
#ifndef lint
|
||||||
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.8 2006-12-14 13:53:43 dockes Exp $ (C) 2003 J.F.Dockes";
|
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.9 2007-08-03 07:50:49 dockes Exp $ (C) 2003 J.F.Dockes";
|
||||||
#endif
|
#endif
|
||||||
/*
|
/*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@ -29,6 +29,7 @@ static char rcsid [] = "@(#$Id: conftree.cpp,v 1.8 2006-12-14 13:53:43 dockes Ex
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "conftree.h"
|
#include "conftree.h"
|
||||||
#include "pathut.h"
|
#include "pathut.h"
|
||||||
@ -43,7 +44,6 @@ using std::list;
|
|||||||
#define MIN(A,B) ((A)<(B) ? (A) : (B))
|
#define MIN(A,B) ((A)<(B) ? (A) : (B))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define LL 1024
|
#define LL 1024
|
||||||
void ConfSimple::parseinput(istream &input)
|
void ConfSimple::parseinput(istream &input)
|
||||||
{
|
{
|
||||||
@ -78,8 +78,10 @@ void ConfSimple::parseinput(istream &input)
|
|||||||
// Note that we trim whitespace before checking for backslash-eol
|
// Note that we trim whitespace before checking for backslash-eol
|
||||||
// This avoids invisible problems.
|
// This avoids invisible problems.
|
||||||
trimstring(line);
|
trimstring(line);
|
||||||
if (line.empty())
|
if (line.empty()) {
|
||||||
|
m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
if (line[line.length() - 1] == '\\') {
|
if (line[line.length() - 1] == '\\') {
|
||||||
line.erase(line.length() - 1);
|
line.erase(line.length() - 1);
|
||||||
appending = true;
|
appending = true;
|
||||||
@ -93,13 +95,20 @@ void ConfSimple::parseinput(istream &input)
|
|||||||
submapkey = path_tildexpand(line);
|
submapkey = path_tildexpand(line);
|
||||||
else
|
else
|
||||||
submapkey = line;
|
submapkey = line;
|
||||||
|
// 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
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for first equal sign
|
// Look for first equal sign
|
||||||
string::size_type eqpos = line.find("=");
|
string::size_type eqpos = line.find("=");
|
||||||
if (eqpos == string::npos)
|
if (eqpos == string::npos) {
|
||||||
|
m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Compute name and value, trim white space
|
// Compute name and value, trim white space
|
||||||
string nm, val;
|
string nm, val;
|
||||||
@ -108,48 +117,33 @@ void ConfSimple::parseinput(istream &input)
|
|||||||
val = line.substr(eqpos+1, string::npos);
|
val = line.substr(eqpos+1, string::npos);
|
||||||
trimstring(val);
|
trimstring(val);
|
||||||
|
|
||||||
if (nm.length() == 0)
|
if (nm.length() == 0) {
|
||||||
|
m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
map<string, map<string, string> >::iterator s;
|
|
||||||
s = submaps.find(submapkey);
|
|
||||||
if (s != submaps.end()) {
|
|
||||||
// submap already exists
|
|
||||||
map<string, string> &sm = s->second;
|
|
||||||
sm[nm] = val;
|
|
||||||
} else {
|
|
||||||
map<string, string> newmap;
|
|
||||||
newmap[nm] = val;
|
|
||||||
submaps[submapkey] = newmap;
|
|
||||||
}
|
}
|
||||||
|
i_set(nm, val, submapkey, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ConfSimple::ConfSimple(int readonly, bool tildexp)
|
ConfSimple::ConfSimple(int readonly, bool tildexp)
|
||||||
|
: dotildexpand(tildexp), m_data(0)
|
||||||
{
|
{
|
||||||
data = 0;
|
|
||||||
dotildexpand = tildexp;
|
|
||||||
status = readonly ? STATUS_RO : STATUS_RW;
|
status = readonly ? STATUS_RO : STATUS_RW;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfSimple::ConfSimple(string *d, int readonly, bool tildexp)
|
ConfSimple::ConfSimple(string *d, int readonly, bool tildexp)
|
||||||
|
: dotildexpand(tildexp), m_data(d)
|
||||||
{
|
{
|
||||||
data = d;
|
|
||||||
dotildexpand = tildexp;
|
|
||||||
status = readonly ? STATUS_RO : STATUS_RW;
|
status = readonly ? STATUS_RO : STATUS_RW;
|
||||||
|
|
||||||
stringstream input(*d, ios::in);
|
stringstream input(*d, ios::in);
|
||||||
parseinput(input);
|
parseinput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
|
ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
|
||||||
|
: dotildexpand(tildexp), m_filename(fname), m_data(0)
|
||||||
{
|
{
|
||||||
data = 0;
|
|
||||||
filename = string(fname);
|
|
||||||
dotildexpand = tildexp;
|
|
||||||
status = readonly ? STATUS_RO : STATUS_RW;
|
status = readonly ? STATUS_RO : STATUS_RW;
|
||||||
|
|
||||||
ifstream input;
|
ifstream input;
|
||||||
@ -180,7 +174,6 @@ ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse
|
|
||||||
parseinput(input);
|
parseinput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +193,7 @@ int ConfSimple::get(const string &nm, string &value, const string &sk)
|
|||||||
|
|
||||||
// Find submap
|
// Find submap
|
||||||
map<string, map<string, string> >::iterator ss;
|
map<string, map<string, string> >::iterator ss;
|
||||||
if ((ss = submaps.find(sk)) == submaps.end())
|
if ((ss = m_submaps.find(sk)) == m_submaps.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Find named value
|
// Find named value
|
||||||
@ -211,13 +204,15 @@ int ConfSimple::get(const string &nm, string &value, const string &sk)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ConfSimple::WalkerCode swalker(void *f, const string &nm,
|
// Code to appropriately output a subkey (nm=="") or variable line
|
||||||
|
// Splits long lines
|
||||||
|
static ConfSimple::WalkerCode varprinter(void *f, const string &nm,
|
||||||
const string &value)
|
const string &value)
|
||||||
{
|
{
|
||||||
ostream *output = (ostream *)f;
|
ostream *output = (ostream *)f;
|
||||||
if (nm.empty())
|
if (nm.empty()) {
|
||||||
*output << "\n[" << value << "]\n";
|
*output << "\n[" << value << "]\n";
|
||||||
else {
|
} else {
|
||||||
string value1;
|
string value1;
|
||||||
if (value.length() < 60) {
|
if (value.length() < 60) {
|
||||||
value1 = value;
|
value1 = value;
|
||||||
@ -236,46 +231,90 @@ static ConfSimple::WalkerCode swalker(void *f, const string &nm,
|
|||||||
return ConfSimple::WALK_CONTINUE;
|
return ConfSimple::WALK_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set variable and rewrite data
|
||||||
int ConfSimple::set(const std::string &nm, const std::string &value,
|
int ConfSimple::set(const std::string &nm, const std::string &value,
|
||||||
const string &sk)
|
const string &sk)
|
||||||
{
|
{
|
||||||
if (status != STATUS_RW)
|
if (status != STATUS_RW)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Preprocess value: we don't want nl's in there, and we want to keep
|
if (!i_set(nm, value, sk))
|
||||||
// lines to a reasonable length
|
return 0;
|
||||||
|
return write();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal set variable: no rw checking or file rewriting. If init is
|
||||||
|
// set, we're doing initial parsing, else we are changing a parsed
|
||||||
|
// tree (changes the way we update the order data)
|
||||||
|
int ConfSimple::i_set(const std::string &nm, const std::string &value,
|
||||||
|
const string &sk, bool init)
|
||||||
|
{
|
||||||
|
// Values must not have embedded newlines
|
||||||
if (value.find_first_of("\n\r") != string::npos) {
|
if (value.find_first_of("\n\r") != string::npos) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
bool existing = false;
|
||||||
map<string, map<string, string> >::iterator ss;
|
map<string, map<string, string> >::iterator ss;
|
||||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||||
map<string, string> submap;
|
map<string, string> submap;
|
||||||
submap[nm] = value;
|
submap[nm] = value;
|
||||||
submaps[sk] = submap;
|
m_submaps[sk] = submap;
|
||||||
|
if (!sk.empty())
|
||||||
|
m_order.push_back(ConfLine(ConfLine::CFL_SK, sk));
|
||||||
|
// The var insert will be at the end, need not search for the
|
||||||
|
// right place
|
||||||
|
init = true;
|
||||||
|
} else {
|
||||||
|
map<string, string>::iterator it;
|
||||||
|
it = ss->second.find(nm);
|
||||||
|
if (it == ss->second.end()) {
|
||||||
|
ss->second.insert(pair<string,string>(nm, value));
|
||||||
|
} else {
|
||||||
|
it->second = value;
|
||||||
|
existing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the variable already existed, no need to change the order data
|
||||||
|
if (existing)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// Add the new variable at the end of its submap in the order data.
|
||||||
|
|
||||||
|
if (init) {
|
||||||
|
// During the initial construction, insert at end
|
||||||
|
m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list<ConfLine>::iterator start, fin;
|
||||||
|
if (sk.empty()) {
|
||||||
|
start = m_order.begin();
|
||||||
} else {
|
} else {
|
||||||
ss->second[nm] = value;
|
start = find(m_order.begin(), m_order.end(),
|
||||||
}
|
ConfLine(ConfLine::CFL_SK, sk));
|
||||||
|
if (start == m_order.end()) {
|
||||||
if (filename.length()) {
|
// This is not logically possible. The subkey must
|
||||||
ofstream output(filename.c_str(), ios::out|ios::trunc);
|
// exist. We're doomed
|
||||||
if (!output.is_open())
|
std::cerr << "Logical failure during configuration variable "
|
||||||
return 0;
|
"insertion" << endl;
|
||||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
abort();
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
} else if (data) {
|
|
||||||
ostringstream output(*data, ios::out | ios::trunc);
|
|
||||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
// No backing store, no writing
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fin = m_order.end();
|
||||||
|
if (start != m_order.end()) {
|
||||||
|
start++;
|
||||||
|
for (list<ConfLine>::iterator it = start; it != m_order.end(); it++) {
|
||||||
|
if (it->m_kind == ConfLine::CFL_SK) {
|
||||||
|
fin = it;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm));
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfSimple::erase(const string &nm, const string &sk)
|
int ConfSimple::erase(const string &nm, const string &sk)
|
||||||
@ -284,30 +323,13 @@ int ConfSimple::erase(const string &nm, const string &sk)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
map<string, map<string, string> >::iterator ss;
|
map<string, map<string, string> >::iterator ss;
|
||||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ss->second.erase(nm);
|
ss->second.erase(nm);
|
||||||
|
|
||||||
if (filename.length()) {
|
return write();
|
||||||
ofstream output(filename.c_str(), ios::out|ios::trunc);
|
|
||||||
if (!output.is_open())
|
|
||||||
return 0;
|
|
||||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
} else if (data) {
|
|
||||||
ostringstream output(*data, ios::out | ios::trunc);
|
|
||||||
if (sortwalk(swalker, &output) != WALK_CONTINUE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfSimple::set(const char *nm, const char *value, const char *sk)
|
int ConfSimple::set(const char *nm, const char *value, const char *sk)
|
||||||
@ -323,8 +345,8 @@ ConfSimple::sortwalk(WalkerCode (*walker)(void *,const string&,const string&),
|
|||||||
if (!ok())
|
if (!ok())
|
||||||
return WALK_STOP;
|
return WALK_STOP;
|
||||||
// For all submaps:
|
// For all submaps:
|
||||||
for (map<string, map<string, string> >::iterator sit = submaps.begin();
|
for (map<string, map<string, string> >::iterator sit = m_submaps.begin();
|
||||||
sit != submaps.end(); sit++) {
|
sit != m_submaps.end(); sit++) {
|
||||||
|
|
||||||
// Possibly emit submap name:
|
// Possibly emit submap name:
|
||||||
if (!sit->first.empty() && walker(clidata, "", sit->first.c_str())
|
if (!sit->first.empty() && walker(clidata, "", sit->first.c_str())
|
||||||
@ -342,12 +364,60 @@ ConfSimple::sortwalk(WalkerCode (*walker)(void *,const string&,const string&),
|
|||||||
return WALK_CONTINUE;
|
return WALK_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <iostream>
|
bool ConfSimple::write()
|
||||||
|
{
|
||||||
|
if (m_filename.length()) {
|
||||||
|
ofstream output(m_filename.c_str(), ios::out|ios::trunc);
|
||||||
|
if (!output.is_open())
|
||||||
|
return 0;
|
||||||
|
return write(output);
|
||||||
|
} else if (m_data) {
|
||||||
|
ostringstream output(*m_data, ios::out | ios::trunc);
|
||||||
|
return write(output);
|
||||||
|
} else {
|
||||||
|
// No backing store, no writing
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfSimple::write(ostream& out)
|
||||||
|
{
|
||||||
|
if (!ok())
|
||||||
|
return false;
|
||||||
|
string sk;
|
||||||
|
for (list<ConfLine>::const_iterator it = m_order.begin();
|
||||||
|
it != m_order.end(); it++) {
|
||||||
|
switch(it->m_kind) {
|
||||||
|
case ConfLine::CFL_COMMENT:
|
||||||
|
out << it->m_data << endl;
|
||||||
|
if (!out.good())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case ConfLine::CFL_SK:
|
||||||
|
sk = it->m_data;
|
||||||
|
out << "[" << it->m_data << "]" << endl;
|
||||||
|
if (!out.good())
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case ConfLine::CFL_VAR:
|
||||||
|
string value;
|
||||||
|
// As erase() doesnt update m_order we can find unexisting
|
||||||
|
// variables, and must not output anything for them
|
||||||
|
if (get(it->m_data, value, sk)) {
|
||||||
|
varprinter(&out, it->m_data, value);
|
||||||
|
if (!out.good())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfSimple::listall()
|
void ConfSimple::listall()
|
||||||
{
|
{
|
||||||
if (!ok())
|
if (!ok())
|
||||||
return;
|
return;
|
||||||
sortwalk(swalker, &std::cout);
|
write(std::cout);
|
||||||
}
|
}
|
||||||
|
|
||||||
list<string> ConfSimple::getNames(const string &sk)
|
list<string> ConfSimple::getNames(const string &sk)
|
||||||
@ -356,7 +426,7 @@ list<string> ConfSimple::getNames(const string &sk)
|
|||||||
if (!ok())
|
if (!ok())
|
||||||
return mylist;
|
return mylist;
|
||||||
map<string, map<string, string> >::iterator ss;
|
map<string, map<string, string> >::iterator ss;
|
||||||
if ((ss = submaps.find(sk)) == submaps.end()) {
|
if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
|
||||||
return mylist;
|
return mylist;
|
||||||
}
|
}
|
||||||
map<string, string>::const_iterator it;
|
map<string, string>::const_iterator it;
|
||||||
@ -368,6 +438,18 @@ list<string> ConfSimple::getNames(const string &sk)
|
|||||||
return mylist;
|
return mylist;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
list<string> ConfSimple::getSubKeys()
|
||||||
|
{
|
||||||
|
std::list<string> mylist;
|
||||||
|
if (!ok())
|
||||||
|
return mylist;
|
||||||
|
map<string, map<string, string> >::iterator ss;
|
||||||
|
for (ss = m_submaps.begin(); ss != m_submaps.end(); ss++) {
|
||||||
|
mylist.push_back(ss->first);
|
||||||
|
}
|
||||||
|
return mylist;
|
||||||
|
}
|
||||||
|
|
||||||
// //////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////
|
||||||
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
|
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
|
||||||
// //////////////////////////////////////////////////////////////////////////
|
// //////////////////////////////////////////////////////////////////////////
|
||||||
@ -460,6 +542,7 @@ static char usage [] =
|
|||||||
"testconftree [opts] filename\n"
|
"testconftree [opts] filename\n"
|
||||||
"[-w] : read/write test.\n"
|
"[-w] : read/write test.\n"
|
||||||
"[-s] : string parsing test. Filename must hold parm 'strings'\n"
|
"[-s] : string parsing test. Filename must hold parm 'strings'\n"
|
||||||
|
"[-a] nm value sect : add nm,value in 'sect' which can be ''\n"
|
||||||
"[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
|
"[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
|
||||||
"[-d] nm sect : delete nm in 'sect' which can be ''\n"
|
"[-d] nm sect : delete nm in 'sect' which can be ''\n"
|
||||||
"[-S] : string io test. No filename in this case\n"
|
"[-S] : string io test. No filename in this case\n"
|
||||||
@ -478,11 +561,13 @@ static int op_flags;
|
|||||||
#define OPT_S 0x10
|
#define OPT_S 0x10
|
||||||
#define OPT_d 0x20
|
#define OPT_d 0x20
|
||||||
#define OPT_V 0x40
|
#define OPT_V 0x40
|
||||||
|
#define OPT_a 0x80
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *nm = 0;
|
const char *nm = 0;
|
||||||
const char *sub = 0;
|
const char *sub = 0;
|
||||||
|
const char *value = 0;
|
||||||
|
|
||||||
thisprog = argv[0];
|
thisprog = argv[0];
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
@ -494,13 +579,21 @@ int main(int argc, char **argv)
|
|||||||
Usage();
|
Usage();
|
||||||
while (**argv)
|
while (**argv)
|
||||||
switch (*(*argv)++) {
|
switch (*(*argv)++) {
|
||||||
case 'd':
|
case 'd':
|
||||||
op_flags |= OPT_d;
|
op_flags |= OPT_d;
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
Usage();
|
Usage();
|
||||||
nm = *(++argv);argc--;
|
nm = *(++argv);argc--;
|
||||||
sub = *(++argv);argc--;
|
sub = *(++argv);argc--;
|
||||||
goto b1;
|
goto b1;
|
||||||
|
case 'a':
|
||||||
|
op_flags |= OPT_a;
|
||||||
|
if (argc < 4)
|
||||||
|
Usage();
|
||||||
|
nm = *(++argv);argc--;
|
||||||
|
value = *(++argv);argc--;
|
||||||
|
sub = *(++argv);argc--;
|
||||||
|
goto b1;
|
||||||
case 'q':
|
case 'q':
|
||||||
op_flags |= OPT_q;
|
op_flags |= OPT_q;
|
||||||
if (argc < 3)
|
if (argc < 3)
|
||||||
@ -556,13 +649,18 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
char spid[100];
|
char spid[100];
|
||||||
sprintf(spid, "%d", getpid());
|
sprintf(spid, "%d", getpid());
|
||||||
parms.set("mypid", spid);
|
if (!parms.set("mypid", spid)) {
|
||||||
|
cerr << "Set mypid failed" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
ostringstream ost;;
|
ostringstream ost;;
|
||||||
ost << "mypid" << getpid();
|
ost << "mypid" << getpid();
|
||||||
parms.set(ost.str(), spid, "");
|
if (!parms.set(ost.str(), spid, "")) {
|
||||||
|
cerr << "Set mypid failed (2)" << endl;
|
||||||
parms.set("unstring", "Une jolie phrase pour essayer");
|
}
|
||||||
|
if (!parms.set("unstring", "Une jolie phrase pour essayer")) {
|
||||||
|
cerr << "Set unstring failed" << endl;
|
||||||
|
}
|
||||||
} else if (op_flags & OPT_q) {
|
} else if (op_flags & OPT_q) {
|
||||||
ConfTree parms(filename, 0);
|
ConfTree parms(filename, 0);
|
||||||
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||||
@ -576,6 +674,17 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
|
printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
|
||||||
exit(0);
|
exit(0);
|
||||||
|
} else if (op_flags & OPT_a) {
|
||||||
|
ConfTree parms(filename, 0);
|
||||||
|
if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
|
||||||
|
fprintf(stderr, "Error opening or parsing file\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (!parms.set(nm, value, sub)) {
|
||||||
|
fprintf(stderr, "Set error\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
} else if (op_flags & OPT_d) {
|
} else if (op_flags & OPT_d) {
|
||||||
ConfTree parms(filename, 0);
|
ConfTree parms(filename, 0);
|
||||||
if (parms.getStatus() != ConfSimple::STATUS_RW) {
|
if (parms.getStatus() != ConfSimple::STATUS_RW) {
|
||||||
|
|||||||
@ -23,7 +23,9 @@
|
|||||||
* Configuration files have lines like 'name = value', and/or like '[subkey]'
|
* Configuration files have lines like 'name = value', and/or like '[subkey]'
|
||||||
*
|
*
|
||||||
* Lines like '[subkeyname]' in the file define subsections, with independant
|
* Lines like '[subkeyname]' in the file define subsections, with independant
|
||||||
* configuration namespaces.
|
* configuration namespaces. Only subsections holding at least one variable are
|
||||||
|
* significant (empty subsections may be deleted during an update, but
|
||||||
|
not always).
|
||||||
*
|
*
|
||||||
* Whitespace around name and value is insignificant.
|
* Whitespace around name and value is insignificant.
|
||||||
*
|
*
|
||||||
@ -48,6 +50,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#else
|
#else
|
||||||
#include <istream>
|
#include <istream>
|
||||||
|
#include <ostream>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef NO_NAMESPACES
|
#ifndef NO_NAMESPACES
|
||||||
@ -55,10 +58,28 @@ using std::string;
|
|||||||
using std::list;
|
using std::list;
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::istream;
|
using std::istream;
|
||||||
|
using std::ostream;
|
||||||
#endif // NO_NAMESPACES
|
#endif // NO_NAMESPACES
|
||||||
|
|
||||||
#include "pathut.h"
|
#include "pathut.h"
|
||||||
|
|
||||||
|
/** Internal class used for storing presentation information */
|
||||||
|
class ConfLine {
|
||||||
|
public:
|
||||||
|
enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR};
|
||||||
|
Kind m_kind;
|
||||||
|
string m_data;
|
||||||
|
ConfLine(Kind k, const string& d)
|
||||||
|
: m_kind(k), m_data(d)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool operator==(const ConfLine& o)
|
||||||
|
{
|
||||||
|
return o.m_kind == m_kind && o.m_data == m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a simple configuration file with subsections.
|
* Manages a simple configuration file with subsections.
|
||||||
*/
|
*/
|
||||||
@ -135,29 +156,37 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual list<string> getNames(const string &sk);
|
virtual list<string> getNames(const string &sk);
|
||||||
|
|
||||||
virtual string getFilename() {return filename;}
|
/**
|
||||||
|
* Return all subkeys
|
||||||
|
*/
|
||||||
|
virtual list<string> getSubKeys();
|
||||||
|
|
||||||
|
virtual string getFilename() {return m_filename;}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor. Expensive but less so than a full rebuild
|
* Copy constructor. Expensive but less so than a full rebuild
|
||||||
*/
|
*/
|
||||||
ConfSimple(const ConfSimple &rhs) : data(0) {
|
ConfSimple(const ConfSimple &rhs)
|
||||||
|
: m_data(0)
|
||||||
|
{
|
||||||
if ((status = rhs.status) == STATUS_ERROR)
|
if ((status = rhs.status) == STATUS_ERROR)
|
||||||
return;
|
return;
|
||||||
filename = rhs.filename;
|
m_filename = rhs.m_filename;
|
||||||
// Note: we just share the pointer, this doesnt belong to us
|
// Note: we just share the pointer, this doesnt belong to us
|
||||||
data = rhs.data;
|
m_data = rhs.m_data;
|
||||||
submaps = rhs.submaps;
|
m_submaps = rhs.m_submaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assignement. This is expensive
|
* Assignement. This is expensive
|
||||||
*/
|
*/
|
||||||
ConfSimple& operator=(const ConfSimple &rhs) {
|
ConfSimple& operator=(const ConfSimple &rhs)
|
||||||
|
{
|
||||||
if (this != &rhs && (status = rhs.status) != STATUS_ERROR) {
|
if (this != &rhs && (status = rhs.status) != STATUS_ERROR) {
|
||||||
filename = rhs.filename;
|
m_filename = rhs.m_filename;
|
||||||
// Note: we don't own data. Just share the pointer
|
// Note: we don't own data. Just share the pointer
|
||||||
data = rhs.data;
|
m_data = rhs.m_data;
|
||||||
submaps = rhs.submaps;
|
m_submaps = rhs.m_submaps;
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -166,11 +195,24 @@ protected:
|
|||||||
bool dotildexpand;
|
bool dotildexpand;
|
||||||
StatusCode status;
|
StatusCode status;
|
||||||
private:
|
private:
|
||||||
string filename; // set if we're working with a file
|
// Set if we're working with a file
|
||||||
string *data; // set if we're working with an in-memory string
|
string m_filename;
|
||||||
map<string, map<string, string> > submaps;
|
// Set if we're working with an in-memory string
|
||||||
|
string *m_data;
|
||||||
|
// Configuration data submaps (one per subkey, the main data has a
|
||||||
|
// null subkey)
|
||||||
|
map<string, map<string, string> > m_submaps;
|
||||||
|
// Presentation data. We keep the comments, empty lines and
|
||||||
|
// variable and subkey ordering information in there (for
|
||||||
|
// rewriting the file while keeping hand-edited information)
|
||||||
|
list<ConfLine> m_order;
|
||||||
|
|
||||||
void parseinput(istream &input);
|
void parseinput(istream& input);
|
||||||
|
bool write();
|
||||||
|
bool write(ostream& out);
|
||||||
|
// Internal version of set: no RW checking
|
||||||
|
virtual int i_set(const string &nm, const string &val,
|
||||||
|
const string &sk, bool init = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user