|
a/src/conftree.cxx |
|
b/src/conftree.cxx |
|
... |
|
... |
16 |
*/
|
16 |
*/
|
17 |
#ifndef TEST_CONFTREE
|
17 |
#ifndef TEST_CONFTREE
|
18 |
|
18 |
|
19 |
#include "conftree.hxx"
|
19 |
#include "conftree.hxx"
|
20 |
|
20 |
|
21 |
#include <fnmatch.h> // for fnmatch
|
21 |
#include <fnmatch.h>
|
22 |
#include <stdlib.h> // for abort
|
22 |
#include <stdlib.h>
|
23 |
#include <sys/stat.h> // for stat, st_mtime
|
23 |
#include <sys/stat.h>
|
24 |
#include <unistd.h> // for access
|
24 |
#include <unistd.h>
|
25 |
|
25 |
|
26 |
#include <algorithm> // for find
|
26 |
#include <algorithm>
|
27 |
#include <cstring> // for strlen
|
27 |
#include <cstring>
|
28 |
#include <fstream> // for ifstream, ofstream
|
28 |
#include <fstream>
|
29 |
#include <iostream> // for cerr, cout
|
29 |
#include <iostream>
|
30 |
#include <sstream> // for stringstream
|
30 |
#include <sstream>
|
31 |
#include <utility> // for pair
|
31 |
#include <utility>
|
32 |
|
32 |
|
33 |
#include "upmpdutils.hxx" // for trimstring, path_catslash, etc
|
33 |
#include "upmpdutils.hxx"
|
34 |
|
34 |
|
35 |
using namespace std;
|
35 |
using namespace std;
|
36 |
|
36 |
|
37 |
#undef DEBUG
|
37 |
#undef DEBUG
|
38 |
#ifdef DEBUG
|
38 |
#ifdef DEBUG
|
39 |
#define LOGDEB(X) fprintf X
|
39 |
#define LOGDEB(X) fprintf X
|
40 |
#else
|
40 |
#else
|
41 |
#define LOGDEB(X)
|
41 |
#define LOGDEB(X)
|
42 |
#endif
|
42 |
#endif
|
43 |
|
43 |
|
44 |
#ifndef MIN
|
|
|
45 |
#define MIN(A,B) ((A) < (B) ? (A) : (B))
|
|
|
46 |
#endif
|
|
|
47 |
|
|
|
48 |
#define LL 2048
|
|
|
49 |
|
|
|
50 |
void ConfSimple::parseinput(istream& input)
|
44 |
void ConfSimple::parseinput(istream& input)
|
51 |
{
|
45 |
{
|
52 |
string submapkey;
|
46 |
string submapkey;
|
53 |
char cline[LL];
|
47 |
string cline;
|
54 |
bool appending = false;
|
48 |
bool appending = false;
|
55 |
string line;
|
49 |
string line;
|
56 |
bool eof = false;
|
50 |
bool eof = false;
|
57 |
|
51 |
|
58 |
for (;;) {
|
52 |
for (;;) {
|
59 |
cline[0] = 0;
|
53 |
cline.clear();
|
60 |
input.getline(cline, LL - 1);
|
54 |
std::getline(input, cline);
|
61 |
LOGDEB((stderr, "Parse:line: [%s] status %d\n", cline, int(status)));
|
55 |
LOGDEB((stderr, "Parse:line: [%s] status %d\n",
|
|
|
56 |
cline.c_str(), int(status)));
|
62 |
if (!input.good()) {
|
57 |
if (!input.good()) {
|
63 |
if (input.bad()) {
|
58 |
if (input.bad()) {
|
64 |
LOGDEB((stderr, "Parse: input.bad()\n"));
|
59 |
LOGDEB((stderr, "Parse: input.bad()\n"));
|
65 |
status = STATUS_ERROR;
|
60 |
status = STATUS_ERROR;
|
66 |
return;
|
61 |
return;
|
|
... |
|
... |
71 |
// eof ends with a backslash, or there is no final \n
|
66 |
// eof ends with a backslash, or there is no final \n
|
72 |
eof = true;
|
67 |
eof = true;
|
73 |
}
|
68 |
}
|
74 |
|
69 |
|
75 |
{
|
70 |
{
|
76 |
int ll = strlen(cline);
|
71 |
string::size_type pos = cline.find_last_not_of("\n\r");
|
77 |
while (ll > 0 && (cline[ll - 1] == '\n' || cline[ll - 1] == '\r')) {
|
72 |
if (pos == string::npos) {
|
78 |
cline[ll - 1] = 0;
|
|
|
79 |
ll--;
|
73 |
cline.clear();
|
|
|
74 |
} else if (pos != cline.length() - 1) {
|
|
|
75 |
cline.erase(pos + 1);
|
80 |
}
|
76 |
}
|
81 |
}
|
77 |
}
|
82 |
|
78 |
|
83 |
if (appending) {
|
79 |
if (appending) {
|
84 |
line += cline;
|
80 |
line += cline;
|
|
... |
|
... |
179 |
} else {
|
175 |
} else {
|
180 |
ios::openmode mode = ios::in | ios::out;
|
176 |
ios::openmode mode = ios::in | ios::out;
|
181 |
// It seems that there is no separate 'create if not exists'
|
177 |
// It seems that there is no separate 'create if not exists'
|
182 |
// open flag. Have to truncate to create, but dont want to do
|
178 |
// open flag. Have to truncate to create, but dont want to do
|
183 |
// this to an existing file !
|
179 |
// this to an existing file !
|
184 |
if (access(fname, 0) < 0) {
|
180 |
if (!path_exists(fname)) {
|
185 |
mode |= ios::trunc;
|
181 |
mode |= ios::trunc;
|
186 |
}
|
182 |
}
|
187 |
input.open(fname, mode);
|
183 |
input.open(fname, mode);
|
188 |
if (input.is_open()) {
|
184 |
if (input.is_open()) {
|
189 |
status = STATUS_RW;
|
185 |
status = STATUS_RW;
|
|
... |
|
... |
266 |
value = s->second;
|
262 |
value = s->second;
|
267 |
return 1;
|
263 |
return 1;
|
268 |
}
|
264 |
}
|
269 |
|
265 |
|
270 |
// Appropriately output a subkey (nm=="") or variable line.
|
266 |
// Appropriately output a subkey (nm=="") or variable line.
|
271 |
// Splits long lines
|
267 |
// We can't make any assumption about the data except that it does not
|
|
|
268 |
// contain line breaks.
|
|
|
269 |
// Avoid long lines if possible (for hand-editing)
|
|
|
270 |
// We used to break at arbitrary places, but this was ennoying for
|
|
|
271 |
// files with pure UTF-8 encoding (some files can be binary anyway),
|
|
|
272 |
// because it made later editing difficult, as the file would no
|
|
|
273 |
// longer have a valid encoding.
|
|
|
274 |
// Any ASCII byte would be a safe break point for utf-8, but could
|
|
|
275 |
// break some other encoding with, e.g. escape sequences? So break at
|
|
|
276 |
// whitespace (is this safe with all encodings?).
|
|
|
277 |
// Note that the choice of break point does not affect the validity of
|
|
|
278 |
// the file data (when read back by conftree), only its ease of
|
|
|
279 |
// editing with a normal editor.
|
272 |
static ConfSimple::WalkerCode varprinter(void *f, const string& nm,
|
280 |
static ConfSimple::WalkerCode varprinter(void *f, const string& nm,
|
273 |
const string& value)
|
281 |
const string& value)
|
274 |
{
|
282 |
{
|
275 |
ostream *output = (ostream *)f;
|
283 |
ostream& output = *((ostream *)f);
|
276 |
if (nm.empty()) {
|
284 |
if (nm.empty()) {
|
277 |
*output << "\n[" << value << "]\n";
|
285 |
output << "\n[" << value << "]\n";
|
278 |
} else {
|
286 |
} else {
|
279 |
string value1;
|
287 |
output << nm << " = ";
|
280 |
if (value.length() < 60) {
|
288 |
if (nm.length() + value.length() < 75) {
|
281 |
value1 = value;
|
289 |
output << value;
|
282 |
} else {
|
290 |
} else {
|
283 |
string::size_type pos = 0;
|
291 |
string::size_type ll = 0;
|
284 |
while (pos < value.length()) {
|
|
|
285 |
string::size_type len = MIN(60, value.length() - pos);
|
292 |
for (string::size_type pos = 0; pos < value.length(); pos++) {
|
286 |
value1 += value.substr(pos, len);
|
293 |
string::value_type c = value[pos];
|
|
|
294 |
output << c;
|
287 |
pos += len;
|
295 |
ll++;
|
288 |
if (pos < value.length()) {
|
296 |
// Break at whitespace if line too long and "a lot" of
|
|
|
297 |
// remaining data
|
|
|
298 |
if (ll > 50 && (value.length() - pos) > 10 &&
|
|
|
299 |
(c == ' ' || c == '\t')) {
|
|
|
300 |
ll = 0;
|
289 |
value1 += "\\\n";
|
301 |
output << "\\\n";
|
290 |
}
|
302 |
}
|
291 |
}
|
303 |
}
|
292 |
}
|
304 |
}
|
293 |
*output << nm << " = " << value1 << "\n";
|
305 |
output << "\n";
|
294 |
}
|
306 |
}
|
295 |
return ConfSimple::WALK_CONTINUE;
|
307 |
return ConfSimple::WALK_CONTINUE;
|
296 |
}
|
308 |
}
|
297 |
|
309 |
|
298 |
// Set variable and rewrite data
|
310 |
// Set variable and rewrite data
|
|
... |
|
... |
610 |
// //////////////////////////////////////////////////////////////////////////
|
622 |
// //////////////////////////////////////////////////////////////////////////
|
611 |
|
623 |
|
612 |
int ConfTree::get(const std::string& name, string& value, const string& sk)
|
624 |
int ConfTree::get(const std::string& name, string& value, const string& sk)
|
613 |
const
|
625 |
const
|
614 |
{
|
626 |
{
|
615 |
if (sk.empty() || sk[0] != '/') {
|
627 |
if (sk.empty() || !path_isabsolute(sk)) {
|
616 |
// LOGDEB((stderr, "ConfTree::get: looking in global space\n"));
|
628 |
// LOGDEB((stderr, "ConfTree::get: looking in global space for [%s]\n",
|
|
|
629 |
// sk.c_str()));
|
617 |
return ConfSimple::get(name, value, sk);
|
630 |
return ConfSimple::get(name, value, sk);
|
618 |
}
|
631 |
}
|
619 |
|
632 |
|
620 |
// Get writable copy of subkey path
|
633 |
// Get writable copy of subkey path
|
621 |
string msk = sk;
|
634 |
string msk = sk;
|
|
... |
|
... |
633 |
}
|
646 |
}
|
634 |
string::size_type pos = msk.rfind("/");
|
647 |
string::size_type pos = msk.rfind("/");
|
635 |
if (pos != string::npos) {
|
648 |
if (pos != string::npos) {
|
636 |
msk.replace(pos, string::npos, string());
|
649 |
msk.replace(pos, string::npos, string());
|
637 |
} else {
|
650 |
} else {
|
|
|
651 |
#ifdef _WIN32
|
|
|
652 |
if (msk.size() == 2 && isalpha(msk[0]) && msk[1] == ':') {
|
|
|
653 |
msk.clear();
|
|
|
654 |
} else
|
|
|
655 |
#endif
|
638 |
break;
|
656 |
break;
|
639 |
}
|
657 |
}
|
640 |
}
|
658 |
}
|
641 |
return 0;
|
659 |
return 0;
|
642 |
}
|
660 |
}
|
643 |
|
661 |
|