Switch to unified view

a/src/utils/conftree.cpp b/src/utils/conftree.cpp
1
/* Copyright (C) 2003 J.F.Dockes 
1
/* Copyright (C) 2003 J.F.Dockes
2
 *   This program is free software; you can redistribute it and/or modify
2
 *   This program is free software; you can redistribute it and/or modify
3
 *   it under the terms of the GNU General Public License as published by
3
 *   it under the terms of the GNU General Public License as published by
4
 *   the Free Software Foundation; either version 2 of the License, or
4
 *   the Free Software Foundation; either version 2 of the License, or
5
 *   (at your option) any later version.
5
 *   (at your option) any later version.
6
 *
6
 *
...
...
16
 */
16
 */
17
#include "autoconfig.h"
17
#include "autoconfig.h"
18
18
19
#ifndef TEST_CONFTREE
19
#ifndef TEST_CONFTREE
20
20
21
#include "conftree.h"
22
21
#include <ctype.h>
23
#include <ctype.h>
22
#include <fnmatch.h>
24
#include <fnmatch.h>
23
#include "safesysstat.h"
25
#include "safesysstat.h"
24
26
27
#include <algorithm>
28
#include <cstring>
25
#include <fstream>
29
#include <fstream>
30
#include <iostream>
26
#include <sstream>
31
#include <sstream>
27
#include <algorithm>
32
#include <utility>
28
#include <iostream>
29
#include <cstring>
30
33
31
using namespace std;
32
33
#include "conftree.h"
34
#include "pathut.h"
34
#include "pathut.h"
35
#include "smallut.h"
35
#include "smallut.h"
36
37
using namespace std;
36
38
37
#undef DEBUG
39
#undef DEBUG
38
#ifdef DEBUG
40
#ifdef DEBUG
39
#define LOGDEB(X) fprintf X
41
#define LOGDEB(X) fprintf X
40
#else
42
#else
41
#define LOGDEB(X)
43
#define LOGDEB(X)
42
#endif
44
#endif
43
45
44
void ConfSimple::parseinput(istream &input)
46
void ConfSimple::parseinput(istream& input)
45
{
47
{
46
    string submapkey;
48
    string submapkey;
47
    string cline;
49
    string cline;
48
    bool appending = false;
50
    bool appending = false;
49
    string line;
51
    string line;
50
    bool eof = false;
52
    bool eof = false;
51
53
52
    for (;;) {
54
    for (;;) {
53
        cline.clear();
55
        cline.clear();
54
        std::getline(input, cline);
56
        std::getline(input, cline);
55
  LOGDEB((stderr, "Parse:line: [%s] status %d\n",
57
        LOGDEB((stderr, "Parse:line: [%s] status %d\n",
56
                cline.c_str(), int(status)));
58
                cline.c_str(), int(status)));
57
  if (!input.good()) {
59
        if (!input.good()) {
58
      if (input.bad()) {
60
            if (input.bad()) {
59
                LOGDEB((stderr, "Parse: input.bad()\n"));
61
                LOGDEB((stderr, "Parse: input.bad()\n"));
60
      status = STATUS_ERROR;
62
                status = STATUS_ERROR;
61
      return;
63
                return;
62
      }
64
            }
63
            LOGDEB((stderr, "Parse: eof\n"));
65
            LOGDEB((stderr, "Parse: eof\n"));
64
      // Must be eof ? But maybe we have a partial line which
66
            // Must be eof ? But maybe we have a partial line which
65
      // must be processed. This happens if the last line before
67
            // must be processed. This happens if the last line before
66
      // eof ends with a backslash, or there is no final \n
68
            // eof ends with a backslash, or there is no final \n
67
            eof = true;
69
            eof = true;
68
  }
70
        }
69
71
70
        {
72
        {
71
            string::size_type pos = cline.find_last_not_of("\n\r");
73
            string::size_type pos = cline.find_last_not_of("\n\r");
72
            if (pos == string::npos) {
74
            if (pos == string::npos) {
73
                cline.clear();
75
                cline.clear();
74
            } else if (pos != cline.length()-1) {
76
            } else if (pos != cline.length() - 1) {
75
                cline.erase(pos+1);
77
                cline.erase(pos + 1);
76
            }
77
        }
78
            }
79
        }
78
80
79
  if (appending)
81
        if (appending) {
80
      line += cline;
82
            line += cline;
81
  else
83
        } else {
82
      line = cline;
84
            line = cline;
85
        }
83
86
84
  // Note that we trim whitespace before checking for backslash-eol
87
        // Note that we trim whitespace before checking for backslash-eol
85
  // This avoids invisible whitespace problems.
88
        // This avoids invisible whitespace problems.
86
  trimstring(line);
89
        trimstring(line);
87
  if (line.empty() || line.at(0) == '#') {
90
        if (line.empty() || line.at(0) == '#') {
88
            if (eof)
91
            if (eof) {
89
                break;
92
                break;
93
            }
90
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
94
            m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
91
      continue;
95
            continue;
92
  }
96
        }
93
  if (line[line.length() - 1] == '\\') {
97
        if (line[line.length() - 1] == '\\') {
94
      line.erase(line.length() - 1);
98
            line.erase(line.length() - 1);
95
      appending = true;
99
            appending = true;
96
      continue;
100
            continue;
97
  }
101
        }
98
  appending = false;
102
        appending = false;
99
103
100
  if (line[0] == '[') {
104
        if (line[0] == '[') {
101
      trimstring(line, "[]");
105
            trimstring(line, "[]");
102
      if (dotildexpand)
106
            if (dotildexpand) {
103
      submapkey = path_tildexpand(line);
107
                submapkey = path_tildexpand(line);
104
      else 
108
            } else {
105
      submapkey = line;
109
                submapkey = line;
110
            }
111
            m_subkeys_unsorted.push_back(submapkey);
112
106
      // No need for adding sk to order, will be done with first
113
            // No need for adding sk to order, will be done with first
107
      // variable insert. Also means that empty section are
114
            // variable insert. Also means that empty section are
108
      // expandable (won't be output when rewriting)
115
            // expandable (won't be output when rewriting)
109
      // Another option would be to add the subsec to m_order here
116
            // Another option would be to add the subsec to m_order here
110
      // and not do it inside i_set() if init is true
117
            // and not do it inside i_set() if init is true
111
      continue;
118
            continue;
112
  }
119
        }
113
120
114
  // Look for first equal sign
121
        // Look for first equal sign
115
  string::size_type eqpos = line.find("=");
122
        string::size_type eqpos = line.find("=");
116
  if (eqpos == string::npos) {
123
        if (eqpos == string::npos) {
117
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
124
            m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
118
      continue;
125
            continue;
119
  }
126
        }
120
127
121
  // Compute name and value, trim white space
128
        // Compute name and value, trim white space
122
  string nm, val;
129
        string nm, val;
123
  nm = line.substr(0, eqpos);
130
        nm = line.substr(0, eqpos);
124
  trimstring(nm);
131
        trimstring(nm);
125
  val = line.substr(eqpos+1, string::npos);
132
        val = line.substr(eqpos + 1, string::npos);
126
  trimstring(val);
133
        trimstring(val);
127
  
134
128
  if (nm.length() == 0) {
135
        if (nm.length() == 0) {
129
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
136
            m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
130
      continue;
137
            continue;
131
  }
138
        }
132
  i_set(nm, val, submapkey, true);
139
        i_set(nm, val, submapkey, true);
133
        if (eof)
140
        if (eof) {
134
            break;
141
            break;
142
        }
135
    }
143
    }
136
}
144
}
137
145
138
146
139
ConfSimple::ConfSimple(int readonly, bool tildexp)
147
ConfSimple::ConfSimple(int readonly, bool tildexp)
...
...
163
{
171
{
164
    status = readonly ? STATUS_RO : STATUS_RW;
172
    status = readonly ? STATUS_RO : STATUS_RW;
165
173
166
    ifstream input;
174
    ifstream input;
167
    if (readonly) {
175
    if (readonly) {
168
  input.open(fname, ios::in);
176
        input.open(fname, ios::in);
169
    } else {
177
    } else {
170
  ios::openmode mode = ios::in|ios::out;
178
        ios::openmode mode = ios::in | ios::out;
171
  // It seems that there is no separate 'create if not exists' 
179
        // It seems that there is no separate 'create if not exists'
172
  // open flag. Have to truncate to create, but dont want to do 
180
        // open flag. Have to truncate to create, but dont want to do
173
  // this to an existing file !
181
        // this to an existing file !
174
  if (!path_exists(fname)) {
182
        if (!path_exists(fname)) {
175
      mode |= ios::trunc;
183
            mode |= ios::trunc;
176
  }
184
        }
177
  input.open(fname, mode);
185
        input.open(fname, mode);
178
  if (input.is_open()) {
179
      status = STATUS_RW;
180
  } else {
181
      input.clear();
182
      input.open(fname, ios::in);
183
      if (input.is_open()) {
186
        if (input.is_open()) {
184
      status = STATUS_RO;
187
            status = STATUS_RW;
185
      }
188
        } else {
186
  }
189
            input.clear();
190
            input.open(fname, ios::in);
191
            if (input.is_open()) {
192
                status = STATUS_RO;
193
            }
194
        }
187
    }
195
    }
188
196
189
    if (!input.is_open()) {
197
    if (!input.is_open()) {
190
  status = STATUS_ERROR;
198
        status = STATUS_ERROR;
191
  return;
199
        return;
192
    }     
200
    }
193
201
194
    parseinput(input);
202
    parseinput(input);
195
    i_changed(true);
203
    i_changed(true);
196
}
204
}
197
205
198
ConfSimple::StatusCode ConfSimple::getStatus() const
206
ConfSimple::StatusCode ConfSimple::getStatus() const
199
{
207
{
200
    switch (status) {
208
    switch (status) {
201
    case STATUS_RO: return STATUS_RO;
209
    case STATUS_RO:
202
    case STATUS_RW: return STATUS_RW;
210
        return STATUS_RO;
211
    case STATUS_RW:
212
        return STATUS_RW;
213
    default:
203
    default: return STATUS_ERROR;
214
        return STATUS_ERROR;
204
    }
215
    }
205
}
216
}
206
217
207
bool ConfSimple::sourceChanged() const
218
bool ConfSimple::sourceChanged() const
208
{
219
{
209
    if (!m_filename.empty()) {
220
    if (!m_filename.empty()) {
210
  struct stat st;
221
        struct stat st;
211
  if (stat(m_filename.c_str(), &st) == 0) {
222
        if (stat(m_filename.c_str(), &st) == 0) {
212
      if (m_fmtime != st.st_mtime) {
223
            if (m_fmtime != st.st_mtime) {
213
      return true;
224
                return true;
214
      }
225
            }
215
  }
226
        }
216
    }
227
    }
217
    return false;
228
    return false;
218
}
229
}
219
230
220
bool ConfSimple::i_changed(bool upd)
231
bool ConfSimple::i_changed(bool upd)
221
{
232
{
222
    if (!m_filename.empty()) {
233
    if (!m_filename.empty()) {
223
  struct stat st;
234
        struct stat st;
224
  if (stat(m_filename.c_str(), &st) == 0) {
235
        if (stat(m_filename.c_str(), &st) == 0) {
225
      if (m_fmtime != st.st_mtime) {
236
            if (m_fmtime != st.st_mtime) {
226
      if (upd)
237
                if (upd) {
227
          m_fmtime = st.st_mtime;
238
                    m_fmtime = st.st_mtime;
228
      return true;
239
                }
229
      }
240
                return true;
230
  }
241
            }
242
        }
231
    }
243
    }
232
    return false;
244
    return false;
233
}
245
}
234
246
235
int ConfSimple::get(const string &nm, string &value, const string &sk) const
247
int ConfSimple::get(const string& nm, string& value, const string& sk) const
236
{
248
{
237
    if (!ok())
249
    if (!ok()) {
238
  return 0;
250
        return 0;
251
    }
239
252
240
    // Find submap
253
    // Find submap
241
    map<string, map<string, string> >::const_iterator ss;
254
    map<string, map<string, string> >::const_iterator ss;
242
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) 
255
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
243
  return 0;
256
        return 0;
257
    }
244
258
245
    // Find named value
259
    // Find named value
246
    map<string, string>::const_iterator s;
260
    map<string, string>::const_iterator s;
247
    if ((s = ss->second.find(nm)) == ss->second.end()) 
261
    if ((s = ss->second.find(nm)) == ss->second.end()) {
248
  return 0;
262
        return 0;
263
    }
249
    value = s->second;
264
    value = s->second;
250
    return 1;
265
    return 1;
251
}
266
}
252
267
253
// Appropriately output a subkey (nm=="") or variable line.
268
// Appropriately output a subkey (nm=="") or variable line.
...
...
262
// break some other encoding with, e.g. escape sequences? So break at
277
// break some other encoding with, e.g. escape sequences? So break at
263
// whitespace (is this safe with all encodings?).
278
// whitespace (is this safe with all encodings?).
264
// Note that the choice of break point does not affect the validity of
279
// Note that the choice of break point does not affect the validity of
265
// the file data (when read back by conftree), only its ease of
280
// the file data (when read back by conftree), only its ease of
266
// editing with a normal editor.
281
// editing with a normal editor.
267
static ConfSimple::WalkerCode varprinter(void *f, const string &nm, 
282
static ConfSimple::WalkerCode varprinter(void *f, const string& nm,
268
                   const string &value)
283
        const string& value)
269
{
284
{
270
    ostream& output = *((ostream *)f);
285
    ostream& output = *((ostream *)f);
271
    if (nm.empty()) {
286
    if (nm.empty()) {
272
  output << "\n[" << value << "]\n";
287
        output << "\n[" << value << "]\n";
273
    } else {
288
    } else {
274
        output << nm << " = ";
289
        output << nm << " = ";
275
  if (nm.length() + value.length() < 75) {
290
        if (nm.length() + value.length() < 75) {
276
      output << value;
291
            output << value;
277
  } else {
292
        } else {
278
            string::size_type ll = 0;
293
            string::size_type ll = 0;
279
      for (string::size_type pos = 0; pos < value.length(); pos++) {
294
            for (string::size_type pos = 0; pos < value.length(); pos++) {
280
                string::value_type c = value[pos];
295
                string::value_type c = value[pos];
281
                output << c;
296
                output << c;
282
                ll++;
297
                ll++;
283
                // Break at whitespace if line too long and "a lot" of
298
                // Break at whitespace if line too long and "a lot" of
284
                // remaining data
299
                // remaining data
285
                if (ll > 50 && (value.length() - pos) > 10 &&
300
                if (ll > 50 && (value.length() - pos) > 10 &&
286
                    (c == ' ' || c == '\t')) {
301
                        (c == ' ' || c == '\t')) {
287
                    ll = 0;
302
                    ll = 0;
288
                    output << "\\\n";
303
                    output << "\\\n";
289
                }
304
                }
290
      }
305
            }
291
  }
306
        }
292
        output << "\n";
307
        output << "\n";
293
    }
308
    }
294
    return ConfSimple::WALK_CONTINUE;
309
    return ConfSimple::WALK_CONTINUE;
295
}
310
}
296
311
297
// Set variable and rewrite data
312
// Set variable and rewrite data
298
int ConfSimple::set(const std::string &nm, const std::string &value, 
313
int ConfSimple::set(const std::string& nm, const std::string& value,
299
          const string &sk)
314
                    const string& sk)
300
{
315
{
301
    if (status  != STATUS_RW)
316
    if (status  != STATUS_RW) {
302
  return 0;
317
        return 0;
318
    }
303
    LOGDEB((stderr, "ConfSimple::set [%s]:[%s] -> [%s]\n", sk.c_str(),
319
    LOGDEB((stderr, "ConfSimple::set [%s]:[%s] -> [%s]\n", sk.c_str(),
304
       nm.c_str(), value.c_str()));
320
            nm.c_str(), value.c_str()));
305
    if (!i_set(nm, value, sk))
321
    if (!i_set(nm, value, sk)) {
306
  return 0;
322
        return 0;
323
    }
307
    return write();
324
    return write();
308
}
325
}
309
326
310
// Internal set variable: no rw checking or file rewriting. If init is
327
// Internal set variable: no rw checking or file rewriting. If init is
311
// set, we're doing initial parsing, else we are changing a parsed
328
// set, we're doing initial parsing, else we are changing a parsed
312
// tree (changes the way we update the order data)
329
// tree (changes the way we update the order data)
313
int ConfSimple::i_set(const std::string &nm, const std::string &value, 
330
int ConfSimple::i_set(const std::string& nm, const std::string& value,
314
            const string &sk, bool init)
331
                      const string& sk, bool init)
315
{
332
{
316
    LOGDEB((stderr, "ConfSimple::i_set: nm[%s] val[%s] key[%s], init %d\n",
333
    LOGDEB((stderr, "ConfSimple::i_set: nm[%s] val[%s] key[%s], init %d\n",
317
      nm.c_str(), value.c_str(), sk.c_str(), init));
334
            nm.c_str(), value.c_str(), sk.c_str(), init));
318
    // Values must not have embedded newlines
335
    // Values must not have embedded newlines
319
    if (value.find_first_of("\n\r") != string::npos) {
336
    if (value.find_first_of("\n\r") != string::npos) {
320
  LOGDEB((stderr, "ConfSimple::i_set: LF in value\n"));
337
        LOGDEB((stderr, "ConfSimple::i_set: LF in value\n"));
321
  return 0;
338
        return 0;
322
    }
339
    }
323
    bool existing = false;
340
    bool existing = false;
324
    map<string, map<string, string> >::iterator ss;
341
    map<string, map<string, string> >::iterator ss;
325
    // Test if submap already exists, else create it, and insert variable:
342
    // Test if submap already exists, else create it, and insert variable:
326
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
343
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
327
  LOGDEB((stderr, "ConfSimple::i_set: new submap\n"));
344
        LOGDEB((stderr, "ConfSimple::i_set: new submap\n"));
328
  map<string, string> submap;
345
        map<string, string> submap;
329
  submap[nm] = value;
346
        submap[nm] = value;
330
  m_submaps[sk] = submap;
347
        m_submaps[sk] = submap;
331
348
332
  // Maybe add sk entry to m_order data:
349
        // Maybe add sk entry to m_order data:
333
  if (!sk.empty()) {
350
        if (!sk.empty()) {
334
      ConfLine nl(ConfLine::CFL_SK, sk);
351
            ConfLine nl(ConfLine::CFL_SK, sk);
335
      // Append SK entry only if it's not already there (erase
352
            // Append SK entry only if it's not already there (erase
336
      // does not remove entries from the order data, adn it may
353
            // does not remove entries from the order data, adn it may
337
      // be being recreated after deletion)
354
            // be being recreated after deletion)
338
      if (find(m_order.begin(), m_order.end(), nl) == m_order.end()) {
355
            if (find(m_order.begin(), m_order.end(), nl) == m_order.end()) {
339
      m_order.push_back(nl);
356
                m_order.push_back(nl);
340
      }
357
            }
341
  }
358
        }
342
    } else {
359
    } else {
343
  // Insert or update variable in existing map.
360
        // Insert or update variable in existing map.
344
  map<string, string>::iterator it;
361
        map<string, string>::iterator it;
345
  it = ss->second.find(nm);
362
        it = ss->second.find(nm);
346
  if (it == ss->second.end()) {
363
        if (it == ss->second.end()) {
347
      ss->second.insert(pair<string,string>(nm, value));
364
            ss->second.insert(pair<string, string>(nm, value));
348
  } else {
365
        } else {
349
      it->second = value;
366
            it->second = value;
350
      existing = true;
367
            existing = true;
351
  }
368
        }
352
    }
369
    }
353
370
354
    // If the variable already existed, no need to change the m_order data
371
    // If the variable already existed, no need to change the m_order data
355
    if (existing) {
372
    if (existing) {
356
  LOGDEB((stderr, "ConfSimple::i_set: existing var: no order update\n"));
373
        LOGDEB((stderr, "ConfSimple::i_set: existing var: no order update\n"));
357
  return 1;
374
        return 1;
358
    }
375
    }
359
376
360
    // Add the new variable at the end of its submap in the order data.
377
    // Add the new variable at the end of its submap in the order data.
361
378
362
    if (init) {
379
    if (init) {
363
  // During the initial construction, just append:
380
        // During the initial construction, just append:
364
  LOGDEB((stderr, "ConfSimple::i_set: init true: append\n"));
381
        LOGDEB((stderr, "ConfSimple::i_set: init true: append\n"));
365
  m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
382
        m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
366
  return 1;
383
        return 1;
367
    } 
384
    }
368
385
369
    // Look for the start and end of the subkey zone. Start is either
386
    // Look for the start and end of the subkey zone. Start is either
370
    // at begin() for a null subkey, or just behind the subkey
387
    // at begin() for a null subkey, or just behind the subkey
371
    // entry. End is either the next subkey entry, or the end of
388
    // entry. End is either the next subkey entry, or the end of
372
    // list. We insert the new entry just before end.
389
    // list. We insert the new entry just before end.
373
    vector<ConfLine>::iterator start, fin;
390
    vector<ConfLine>::iterator start, fin;
374
    if (sk.empty()) {
391
    if (sk.empty()) {
375
  start = m_order.begin();
392
        start = m_order.begin();
376
  LOGDEB((stderr,"ConfSimple::i_set: null sk, start at top of order\n"));
393
        LOGDEB((stderr, "ConfSimple::i_set: null sk, start at top of order\n"));
377
    } else {
394
    } else {
378
  start = find(m_order.begin(), m_order.end(), 
395
        start = find(m_order.begin(), m_order.end(),
379
           ConfLine(ConfLine::CFL_SK, sk));
396
                     ConfLine(ConfLine::CFL_SK, sk));
380
  if (start == m_order.end()) {
397
        if (start == m_order.end()) {
381
      // This is not logically possible. The subkey must
398
            // This is not logically possible. The subkey must
382
      // exist. We're doomed
399
            // exist. We're doomed
383
      std::cerr << "Logical failure during configuration variable " 
400
            std::cerr << "Logical failure during configuration variable "
384
      "insertion" << endl;
401
                      "insertion" << endl;
385
      abort();
402
            abort();
386
  }
403
        }
387
    }
404
    }
388
405
389
    fin = m_order.end();
406
    fin = m_order.end();
390
    if (start != m_order.end()) {
407
    if (start != m_order.end()) {
391
  // The null subkey has no entry (maybe it should)
408
        // The null subkey has no entry (maybe it should)
392
  if (!sk.empty())
409
        if (!sk.empty()) {
393
      start++;
410
            start++;
411
        }
394
  for (vector<ConfLine>::iterator it = start; it != m_order.end(); it++) {
412
        for (vector<ConfLine>::iterator it = start; it != m_order.end(); it++) {
395
      if (it->m_kind == ConfLine::CFL_SK) {
413
            if (it->m_kind == ConfLine::CFL_SK) {
396
      fin = it;
414
                fin = it;
397
      break;
415
                break;
398
      }
416
            }
399
  }
417
        }
400
    }
418
    }
401
419
402
    // It may happen that the order entry already exists because erase doesnt
420
    // It may happen that the order entry already exists because erase doesnt
403
    // update m_order
421
    // update m_order
404
    if (find(start, fin, ConfLine(ConfLine::CFL_VAR, nm)) == fin) {
422
    if (find(start, fin, ConfLine(ConfLine::CFL_VAR, nm)) == fin) {
405
  m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm));
423
        m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm));
406
    }
424
    }
407
    return 1;
425
    return 1;
408
}
426
}
409
427
410
int ConfSimple::erase(const string &nm, const string &sk)
428
int ConfSimple::erase(const string& nm, const string& sk)
411
{
429
{
412
    if (status  != STATUS_RW)
430
    if (status  != STATUS_RW) {
413
  return 0;
431
        return 0;
432
    }
414
433
415
    map<string, map<string, string> >::iterator ss;
434
    map<string, map<string, string> >::iterator ss;
416
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
435
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
417
  return 0;
436
        return 0;
418
    }
419
    
437
    }
438
420
    ss->second.erase(nm);
439
    ss->second.erase(nm);
421
    if (ss->second.empty()) {
440
    if (ss->second.empty()) {
422
  m_submaps.erase(ss);
441
        m_submaps.erase(ss);
423
    }
442
    }
424
    return write();
443
    return write();
425
}
444
}
426
445
427
int ConfSimple::eraseKey(const string &sk)
446
int ConfSimple::eraseKey(const string& sk)
428
{
447
{
429
    vector<string> nms = getNames(sk);
448
    vector<string> nms = getNames(sk);
430
    for (vector<string>::iterator it = nms.begin(); it != nms.end(); it++) {
449
    for (vector<string>::iterator it = nms.begin(); it != nms.end(); it++) {
431
  erase(*it, sk);
450
        erase(*it, sk);
432
    }
451
    }
433
    return write();
452
    return write();
434
}
453
}
435
454
436
// Walk the tree, calling user function at each node
455
// Walk the tree, calling user function at each node
437
ConfSimple::WalkerCode 
456
ConfSimple::WalkerCode
438
ConfSimple::sortwalk(WalkerCode (*walker)(void *,const string&,const string&),
457
ConfSimple::sortwalk(WalkerCode(*walker)(void *, const string&, const string&),
439
           void *clidata) const
458
                     void *clidata) const
440
{
459
{
441
    if (!ok())
460
    if (!ok()) {
442
  return WALK_STOP;
461
        return WALK_STOP;
462
    }
443
    // For all submaps:
463
    // For all submaps:
444
    for (map<string, map<string, string> >::const_iterator sit = 
464
    for (map<string, map<string, string> >::const_iterator sit =
445
       m_submaps.begin();
465
                m_submaps.begin();
446
   sit != m_submaps.end(); sit++) {
466
            sit != m_submaps.end(); sit++) {
447
467
448
  // Possibly emit submap name:
468
        // Possibly emit submap name:
449
  if (!sit->first.empty() && walker(clidata, string(), sit->first.c_str())
469
        if (!sit->first.empty() && walker(clidata, string(), sit->first.c_str())
450
      == WALK_STOP)
470
                == WALK_STOP) {
451
      return WALK_STOP;
471
            return WALK_STOP;
472
        }
452
473
453
  // Walk submap
474
        // Walk submap
454
  const map<string, string> &sm = sit->second;
475
        const map<string, string>& sm = sit->second;
455
  for (map<string, string>::const_iterator it = sm.begin();it != sm.end();
476
        for (map<string, string>::const_iterator it = sm.begin(); it != sm.end();
456
       it++) {
477
                it++) {
457
      if (walker(clidata, it->first, it->second) == WALK_STOP)
478
            if (walker(clidata, it->first, it->second) == WALK_STOP) {
458
      return WALK_STOP;
479
                return WALK_STOP;
459
  }
480
            }
481
        }
460
    }
482
    }
461
    return WALK_CONTINUE;
483
    return WALK_CONTINUE;
462
}
484
}
463
485
464
// Write to default output. This currently only does something if output is
486
// Write to default output. This currently only does something if output is
465
// a file
487
// a file
466
bool ConfSimple::write()
488
bool ConfSimple::write()
467
{
489
{
468
    if (!ok())
490
    if (!ok()) {
469
  return false;
491
        return false;
492
    }
470
    if (m_holdWrites)
493
    if (m_holdWrites) {
471
  return true;
494
        return true;
495
    }
472
    if (m_filename.length()) {
496
    if (m_filename.length()) {
473
  ofstream output(m_filename.c_str(), ios::out|ios::trunc);
497
        ofstream output(m_filename.c_str(), ios::out | ios::trunc);
474
  if (!output.is_open())
498
        if (!output.is_open()) {
475
      return 0;
499
            return 0;
500
        }
476
  return write(output);
501
        return write(output);
477
    } else {
502
    } else {
478
  // No backing store, no writing. Maybe one day we'll need it with
503
        // No backing store, no writing. Maybe one day we'll need it with
479
        // some kind of output string. This can't be the original string which
504
        // some kind of output string. This can't be the original string which
480
        // is currently readonly.
505
        // is currently readonly.
481
  //ostringstream output(m_ostring, ios::out | ios::trunc);
506
        //ostringstream output(m_ostring, ios::out | ios::trunc);
482
  return 1;
507
        return 1;
483
    }
508
    }
484
}
509
}
485
510
486
// Write out the tree in configuration file format:
511
// Write out the tree in configuration file format:
487
// This does not check holdWrites, this is done by write(void), which
512
// This does not check holdWrites, this is done by write(void), which
488
// lets ie: showall work even when holdWrites is set
513
// lets ie: showall work even when holdWrites is set
489
bool ConfSimple::write(ostream& out) const
514
bool ConfSimple::write(ostream& out) const
490
{
515
{
491
    if (!ok())
516
    if (!ok()) {
492
  return false;
517
        return false;
518
    }
493
    string sk;
519
    string sk;
494
    for (vector<ConfLine>::const_iterator it = m_order.begin(); 
520
    for (vector<ConfLine>::const_iterator it = m_order.begin();
495
   it != m_order.end(); it++) {
521
            it != m_order.end(); it++) {
496
  switch(it->m_kind) {
522
        switch (it->m_kind) {
497
  case ConfLine::CFL_COMMENT: 
523
        case ConfLine::CFL_COMMENT:
498
      out << it->m_data << endl; 
524
            out << it->m_data << endl;
499
      if (!out.good()) 
525
            if (!out.good()) {
500
      return false;
526
                return false;
501
      break;
527
            }
528
            break;
502
  case ConfLine::CFL_SK:      
529
        case ConfLine::CFL_SK:
503
      sk = it->m_data;
530
            sk = it->m_data;
504
      LOGDEB((stderr, "ConfSimple::write: SK [%s]\n", sk.c_str()));
531
            LOGDEB((stderr, "ConfSimple::write: SK [%s]\n", sk.c_str()));
505
      // Check that the submap still exists, and only output it if it
532
            // Check that the submap still exists, and only output it if it
506
      // does
533
            // does
507
      if (m_submaps.find(sk) != m_submaps.end()) {
534
            if (m_submaps.find(sk) != m_submaps.end()) {
508
      out << "[" << it->m_data << "]" << endl;
535
                out << "[" << it->m_data << "]" << endl;
509
      if (!out.good()) 
536
                if (!out.good()) {
510
          return false;
537
                    return false;
511
      }
538
                }
512
      break;
539
            }
540
            break;
513
  case ConfLine::CFL_VAR:
541
        case ConfLine::CFL_VAR:
514
      string nm = it->m_data;
542
            string nm = it->m_data;
515
      LOGDEB((stderr, "ConfSimple::write: VAR [%s], sk [%s]\n",
543
            LOGDEB((stderr, "ConfSimple::write: VAR [%s], sk [%s]\n",
516
          nm.c_str(), sk.c_str()));
544
                    nm.c_str(), sk.c_str()));
517
      // As erase() doesnt update m_order we can find unexisting
545
            // As erase() doesnt update m_order we can find unexisting
518
      // variables, and must not output anything for them. Have
546
            // variables, and must not output anything for them. Have
519
      // to use a ConfSimple::get() to check here, because
547
            // to use a ConfSimple::get() to check here, because
520
      // ConfTree's could retrieve from an ancestor even if the
548
            // ConfTree's could retrieve from an ancestor even if the
521
      // local var is gone.
549
            // local var is gone.
522
      string value;
550
            string value;
523
      if (ConfSimple::get(nm, value, sk)) {
551
            if (ConfSimple::get(nm, value, sk)) {
524
          varprinter(&out, nm, value);
552
                varprinter(&out, nm, value);
525
          if (!out.good()) 
553
                if (!out.good()) {
526
          return false;
554
                    return false;
527
          break;
555
                }
528
      }
556
                break;
557
            }
529
      LOGDEB((stderr, "ConfSimple::write: no value: nm[%s] sk[%s]\n",
558
            LOGDEB((stderr, "ConfSimple::write: no value: nm[%s] sk[%s]\n",
530
          nm.c_str(), sk.c_str()));
559
                    nm.c_str(), sk.c_str()));
531
      break;
560
            break;
532
  }
561
        }
533
    }
562
    }
534
    return true;
563
    return true;
535
}
564
}
536
565
537
void ConfSimple::showall() const
566
void ConfSimple::showall() const
538
{
567
{
539
    if (!ok())
568
    if (!ok()) {
540
  return;
569
        return;
570
    }
541
    write(std::cout);
571
    write(std::cout);
542
}
572
}
543
573
544
vector<string> ConfSimple::getNames(const string &sk, const char *pattern) const
574
vector<string> ConfSimple::getNames(const string& sk, const char *pattern) const
545
{
575
{
546
    vector<string> mylist;
576
    vector<string> mylist;
547
    if (!ok())
577
    if (!ok()) {
548
  return mylist;
578
        return mylist;
579
    }
549
    map<string, map<string, string> >::const_iterator ss;
580
    map<string, map<string, string> >::const_iterator ss;
550
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
581
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
551
  return mylist;
582
        return mylist;
552
    }
583
    }
553
    mylist.reserve(ss->second.size());
584
    mylist.reserve(ss->second.size());
554
    map<string, string>::const_iterator it;
585
    map<string, string>::const_iterator it;
555
    for (it = ss->second.begin(); it != ss->second.end(); it++) {
586
    for (it = ss->second.begin(); it != ss->second.end(); it++) {
556
        if (pattern && 0 != fnmatch(pattern, it->first.c_str(), 0))
587
        if (pattern && 0 != fnmatch(pattern, it->first.c_str(), 0)) {
557
            continue;
588
            continue;
589
        }
558
  mylist.push_back(it->first);
590
        mylist.push_back(it->first);
559
    }
591
    }
560
    return mylist;
592
    return mylist;
561
}
593
}
562
594
563
vector<string> ConfSimple::getSubKeys() const
595
vector<string> ConfSimple::getSubKeys() const
564
{
596
{
565
    vector<string> mylist;
597
    vector<string> mylist;
566
    if (!ok())
598
    if (!ok()) {
567
  return mylist;
599
        return mylist;
600
    }
568
    mylist.reserve(m_submaps.size());
601
    mylist.reserve(m_submaps.size());
569
    map<string, map<string, string> >::const_iterator ss;
602
    map<string, map<string, string> >::const_iterator ss;
570
    for (ss = m_submaps.begin(); ss != m_submaps.end(); ss++) {
603
    for (ss = m_submaps.begin(); ss != m_submaps.end(); ss++) {
571
  mylist.push_back(ss->first);
604
        mylist.push_back(ss->first);
572
    }
605
    }
573
    return mylist;
606
    return mylist;
574
}
607
}
575
608
576
bool ConfSimple::hasNameAnywhere(const string& nm) const
609
bool ConfSimple::hasNameAnywhere(const string& nm) const
577
{
610
{
578
    vector<string>keys = getSubKeys();
611
    vector<string>keys = getSubKeys();
579
    for (vector<string>::const_iterator it = keys.begin(); 
612
    for (vector<string>::const_iterator it = keys.begin();
580
         it != keys.end(); it++) {
613
            it != keys.end(); it++) {
581
        string val;
614
        string val;
582
        if (get(nm, val, *it))
615
        if (get(nm, val, *it)) {
583
            return true;
616
            return true;
617
        }
584
    }
618
    }
585
    return false;
619
    return false;
586
}
620
}
587
621
588
// //////////////////////////////////////////////////////////////////////////
622
// //////////////////////////////////////////////////////////////////////////
589
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
623
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
590
// //////////////////////////////////////////////////////////////////////////
624
// //////////////////////////////////////////////////////////////////////////
591
625
592
int ConfTree::get(const std::string &name, string &value, const string &sk)
626
int ConfTree::get(const std::string& name, string& value, const string& sk)
593
    const
627
const
594
{
628
{
595
    if (sk.empty() || !path_isabsolute(sk) ) {
629
    if (sk.empty() || !path_isabsolute(sk)) {
596
        // LOGDEB((stderr, "ConfTree::get: looking in global space for sk [%s]\n", sk.c_str()));
630
        // LOGDEB((stderr, "ConfTree::get: looking in global space for [%s]\n",
631
        // sk.c_str()));
597
  return ConfSimple::get(name, value, sk);
632
        return ConfSimple::get(name, value, sk);
598
    }
633
    }
599
634
600
    // Get writable copy of subkey path
635
    // Get writable copy of subkey path
601
    string msk = sk;
636
    string msk = sk;
602
637
...
...
604
    // the input sk
639
    // the input sk
605
    path_catslash(msk);
640
    path_catslash(msk);
606
641
607
    // Look in subkey and up its parents until root ('')
642
    // Look in subkey and up its parents until root ('')
608
    for (;;) {
643
    for (;;) {
609
  // LOGDEB((stderr,"ConfTree::get: looking for '%s' in '%s'\n",
644
        // LOGDEB((stderr,"ConfTree::get: looking for '%s' in '%s'\n",
610
        // name.c_str(), msk.c_str()));
645
        // name.c_str(), msk.c_str()));
611
  if (ConfSimple::get(name, value, msk))
646
        if (ConfSimple::get(name, value, msk)) {
612
      return 1;
647
            return 1;
648
        }
613
  string::size_type pos = msk.rfind("/");
649
        string::size_type pos = msk.rfind("/");
614
  if (pos != string::npos) {
650
        if (pos != string::npos) {
615
      msk.replace(pos, string::npos, string());
651
            msk.replace(pos, string::npos, string());
616
  } else {
652
        } else {
617
#ifdef _WIN32
653
#ifdef _WIN32
618
            if (msk.size() == 2 && isalpha(msk[0]) && msk[1] == ':')
654
            if (msk.size() == 2 && isalpha(msk[0]) && msk[1] == ':') {
619
                msk.clear();
655
                msk.clear();
620
            else
656
            } else
621
#endif
657
#endif
622
      break;
658
                break;
623
        }
659
        }
624
    }
660
    }
625
    return 0;
661
    return 0;
626
}
662
}
627
663
...
...
645
static char *thisprog;
681
static char *thisprog;
646
682
647
bool complex_updates(const string& fn)
683
bool complex_updates(const string& fn)
648
{
684
{
649
    int fd;
685
    int fd;
650
    if ((fd = open(fn.c_str(), O_RDWR|O_TRUNC|O_CREAT, 0666)) < 0) {
686
    if ((fd = open(fn.c_str(), O_RDWR | O_TRUNC | O_CREAT, 0666)) < 0) {
651
  perror("open/create");
687
        perror("open/create");
652
  return false;
688
        return false;
653
    }
689
    }
654
    close(fd);
690
    close(fd);
655
691
656
    ConfTree conf(fn.c_str());
692
    ConfTree conf(fn.c_str());
657
    if (!conf.ok()) {
693
    if (!conf.ok()) {
658
  cerr << "Config init failed" << endl;
694
        cerr << "Config init failed" << endl;
659
  return false;
695
        return false;
660
    }
696
    }
661
697
662
    conf.set("nm-1", "val-1", "");
698
    conf.set("nm-1", "val-1", "");
663
    conf.set("nm-2", "val-2", "");
699
    conf.set("nm-2", "val-2", "");
664
700
...
...
697
    conf.erase("nm-2", "/dir1/dir1");
733
    conf.erase("nm-2", "/dir1/dir1");
698
734
699
    string data;
735
    string data;
700
    file_to_string(fn, data, 0);
736
    file_to_string(fn, data, 0);
701
    const string ref =
737
    const string ref =
702
  "nm-1 = val-1\n"
738
        "nm-1 = val-1\n"
703
  "[/dir1]\n"
739
        "[/dir1]\n"
704
  "nm-1 = val1-1\n"
740
        "nm-1 = val1-1\n"
705
  "nm-2 = val1-2\n"
741
        "nm-2 = val1-2\n"
706
  ;
742
        ;
707
    if (data.compare(ref)) {
743
    if (data.compare(ref)) {
708
  cerr << "Final file:" << endl << data << endl << "Differs from ref:" <<
744
        cerr << "Final file:" << endl << data << endl << "Differs from ref:" <<
709
      endl << ref << endl;
745
             endl << ref << endl;
710
  return false;
746
        return false;
711
    } else {
747
    } else {
712
  cout << "Updates test Ok" << endl;
748
        cout << "Updates test Ok" << endl;
713
    }
749
    }
714
    return true;
750
    return true;
715
}
751
}
716
752
717
ConfSimple::WalkerCode mywalker(void *, const string &nm, const string &value)
753
ConfSimple::WalkerCode mywalker(void *, const string& nm, const string& value)
718
{
754
{
719
    if (nm.empty())
755
    if (nm.empty()) {
720
  printf("\n[%s]\n", value.c_str());
756
        printf("\n[%s]\n", value.c_str());
721
    else 
757
    } else {
722
  printf("'%s' -> '%s'\n", nm.c_str(), value.c_str());
758
        printf("'%s' -> '%s'\n", nm.c_str(), value.c_str());
759
    }
723
    return ConfSimple::WALK_CONTINUE;
760
    return ConfSimple::WALK_CONTINUE;
724
}
761
}
725
762
726
const char *longvalue = 
763
const char *longvalue =
727
"Donnees012345678901234567890123456789012345678901234567890123456789AA"
764
    "Donnees012345678901234567890123456789012345678901234567890123456789AA"
728
"0123456789012345678901234567890123456789012345678901234567890123456789FIN"
765
    "0123456789012345678901234567890123456789012345678901234567890123456789FIN"
729
    ;
766
    ;
730
767
731
void memtest(ConfSimple &c) 
768
void memtest(ConfSimple& c)
732
{
769
{
733
    cout << "Initial:" << endl;
770
    cout << "Initial:" << endl;
734
    c.showall();
771
    c.showall();
735
    if (c.set("nom", "avec nl \n 2eme ligne", "")) {
772
    if (c.set("nom", "avec nl \n 2eme ligne", "")) {
736
  fprintf(stderr, "set with embedded nl succeeded !\n");
773
        fprintf(stderr, "set with embedded nl succeeded !\n");
737
  exit(1);
774
        exit(1);
738
    }
775
    }
739
    if (!c.set(string("parm1"), string("1"), string("subkey1"))) {
776
    if (!c.set(string("parm1"), string("1"), string("subkey1"))) {
740
  fprintf(stderr, "Set error");
777
        fprintf(stderr, "Set error");
741
  exit(1);
778
        exit(1);
742
    }
779
    }
743
    if (!c.set("sparm", "Parametre \"string\" bla", "s2")) {
780
    if (!c.set("sparm", "Parametre \"string\" bla", "s2")) {
744
  fprintf(stderr, "Set error");
781
        fprintf(stderr, "Set error");
745
  exit(1);
782
        exit(1);
746
    }
783
    }
747
    if (!c.set("long", longvalue, "")) {
784
    if (!c.set("long", longvalue, "")) {
748
  fprintf(stderr, "Set error");
785
        fprintf(stderr, "Set error");
749
  exit(1);
786
        exit(1);
750
    }
787
    }
751
788
752
    cout << "Final:" << endl;
789
    cout << "Final:" << endl;
753
    c.showall();
790
    c.showall();
754
}
791
}
755
792
756
bool readwrite(ConfNull *conf)
793
bool readwrite(ConfNull *conf)
757
{
794
{
758
    if (conf->ok()) {
795
    if (conf->ok()) {
759
  // It's ok for the file to not exist here
796
        // It's ok for the file to not exist here
760
  string value;
797
        string value;
761
      
798
762
  if (conf->get("mypid", value)) {
799
        if (conf->get("mypid", value)) {
763
      cout << "Value for mypid is [" << value << "]" << endl;
800
            cout << "Value for mypid is [" << value << "]" << endl;
764
  } else {
801
        } else {
765
      cout << "mypid not set" << endl;
802
            cout << "mypid not set" << endl;
766
  }
803
        }
767
      
804
768
  if (conf->get("unstring", value)) {
805
        if (conf->get("unstring", value)) {
769
      cout << "Value for unstring is ["<< value << "]" << endl;
806
            cout << "Value for unstring is [" << value << "]" << endl;
770
  } else {
807
        } else {
771
      cout << "unstring not set" << endl;
808
            cout << "unstring not set" << endl;
772
  }
809
        }
773
    }
810
    }
774
    char spid[100];
811
    char spid[100];
775
    sprintf(spid, "%d", getpid());
812
    sprintf(spid, "%d", getpid());
776
    if (!conf->set("mypid", spid)) {
813
    if (!conf->set("mypid", spid)) {
777
  cerr << "Set mypid failed" << endl;
814
        cerr << "Set mypid failed" << endl;
778
    }
815
    }
779
816
780
    ostringstream ost;
817
    ostringstream ost;
781
    ost << "mypid" << getpid();
818
    ost << "mypid" << getpid();
782
    if (!conf->set(ost.str(), spid, "")) {
819
    if (!conf->set(ost.str(), spid, "")) {
783
  cerr << "Set mypid failed (2)" << endl;
820
        cerr << "Set mypid failed (2)" << endl;
784
    }
821
    }
785
    if (!conf->set("unstring", "Une jolie phrase pour essayer")) {
822
    if (!conf->set("unstring", "Une jolie phrase pour essayer")) {
786
  cerr << "Set unstring failed" << endl;
823
        cerr << "Set unstring failed" << endl;
787
    }
824
    }
788
    return true;
825
    return true;
789
}
826
}
790
827
791
bool query(ConfNull *conf, const string& nm, const string& sub)
828
bool query(ConfNull *conf, const string& nm, const string& sub)
792
{
829
{
793
    if (!conf->ok()) {
830
    if (!conf->ok()) {
794
  cerr <<  "Error opening or parsing file\n" << endl;
831
        cerr <<  "Error opening or parsing file\n" << endl;
795
  return false;
832
        return false;
796
    }
833
    }
797
    string value;
834
    string value;
798
    if (!conf->get(nm, value, sub)) {
835
    if (!conf->get(nm, value, sub)) {
799
  cerr << "name [" << nm << "] not found in [" << sub << "]" << endl;
836
        cerr << "name [" << nm << "] not found in [" << sub << "]" << endl;
800
  return false;
837
        return false;
801
    }
838
    }
802
    cout << "[" << sub << "] " << nm << " " << value << endl;
839
    cout << "[" << sub << "] " << nm << " " << value << endl;
803
    return true;
840
    return true;
804
}
841
}
805
842
806
bool erase(ConfNull *conf, const string& nm, const string& sub)
843
bool erase(ConfNull *conf, const string& nm, const string& sub)
807
{
844
{
808
    if (!conf->ok()) {
845
    if (!conf->ok()) {
809
  cerr <<  "Error opening or parsing file\n" << endl;
846
        cerr <<  "Error opening or parsing file\n" << endl;
810
  return false;
847
        return false;
811
    }
848
    }
812
849
813
    if (!conf->erase(nm, sub)) {
850
    if (!conf->erase(nm, sub)) {
814
  cerr <<  "delete name [" << nm <<  "] in ["<< sub << "] failed" << endl;
851
        cerr <<  "delete name [" << nm <<  "] in [" << sub << "] failed" << endl;
815
  return false;
852
        return false;
816
    }
853
    }
817
    return true;
854
    return true;
818
}
855
}
819
856
820
bool eraseKey(ConfNull *conf, const string& sub)
857
bool eraseKey(ConfNull *conf, const string& sub)
821
{
858
{
822
    if (!conf->ok()) {
859
    if (!conf->ok()) {
823
  cerr <<  "Error opening or parsing file\n" << endl;
860
        cerr <<  "Error opening or parsing file\n" << endl;
824
  return false;
861
        return false;
825
    }
862
    }
826
863
827
    if (!conf->eraseKey(sub)) {
864
    if (!conf->eraseKey(sub)) {
828
  cerr <<  "delete key [" << sub <<  "] failed" << endl;
865
        cerr <<  "delete key [" << sub <<  "] failed" << endl;
829
  return false;
866
        return false;
830
    }
867
    }
831
    return true;
868
    return true;
832
}
869
}
833
870
834
bool setvar(ConfNull *conf, const string& nm, const string& value, 
871
bool setvar(ConfNull *conf, const string& nm, const string& value,
835
      const string& sub)
872
            const string& sub)
836
{
873
{
837
    if (!conf->ok()) {
874
    if (!conf->ok()) {
838
  cerr <<  "Error opening or parsing file\n" << endl;
875
        cerr <<  "Error opening or parsing file\n" << endl;
839
  return false;
876
        return false;
840
    }
877
    }
841
    if (!conf->set(nm, value, sub)) {
878
    if (!conf->set(nm, value, sub)) {
842
  cerr <<  "Set error\n" << endl;
879
        cerr <<  "Set error\n" << endl;
843
  return false;
880
        return false;
844
    }
881
    }
845
    return true;
882
    return true;
846
}
883
}
847
884
848
static char usage [] =
885
static char usage [] =
...
...
853
    "-q nm sect : subsection test: look for nm in 'sect' which can be ''\n"
890
    "-q nm sect : subsection test: look for nm in 'sect' which can be ''\n"
854
    "-d nm sect : delete nm in 'sect' which can be ''\n"
891
    "-d nm sect : delete nm in 'sect' which can be ''\n"
855
    "-E sect : erase key (and all its names)\n"
892
    "-E sect : erase key (and all its names)\n"
856
    "-S : string io test. No filename in this case\n"
893
    "-S : string io test. No filename in this case\n"
857
    "-V : volatile config test. No filename in this case\n"
894
    "-V : volatile config test. No filename in this case\n"
858
    "-U : complex update test. Will erase the named file parameter\n"  
895
    "-U : complex update test. Will erase the named file parameter\n"
859
    ;
896
    ;
860
897
861
void Usage() {
898
void Usage()
899
{
862
    fprintf(stderr, "%s:%s\n", thisprog, usage);
900
    fprintf(stderr, "%s:%s\n", thisprog, usage);
863
    exit(1);
901
    exit(1);
864
}
902
}
865
static int     op_flags;
903
static int     op_flags;
866
#define OPT_MOINS 0x1
904
#define OPT_MOINS 0x1
867
#define OPT_w   0x2 
905
#define OPT_w     0x2
868
#define OPT_q     0x4
906
#define OPT_q     0x4
869
#define OPT_s     0x8
907
#define OPT_s     0x8
870
#define OPT_S     0x10
908
#define OPT_S     0x10
871
#define OPT_d     0x20
909
#define OPT_d     0x20
872
#define OPT_V     0x40
910
#define OPT_V     0x40
...
...
880
    const char *nm = 0;
918
    const char *nm = 0;
881
    const char *sub = 0;
919
    const char *sub = 0;
882
    const char *value = 0;
920
    const char *value = 0;
883
921
884
    thisprog = argv[0];
922
    thisprog = argv[0];
885
    argc--; argv++;
923
    argc--;
924
    argv++;
886
925
887
    while (argc > 0 && **argv == '-') {
926
    while (argc > 0 && **argv == '-') {
888
  (*argv)++;
927
        (*argv)++;
889
  if (!(**argv))
928
        if (!(**argv))
890
      /* Cas du "adb - core" */
929
            /* Cas du "adb - core" */
891
      Usage();
930
        {
931
            Usage();
932
        }
892
  while (**argv)
933
        while (**argv)
893
      switch (*(*argv)++) {
934
            switch (*(*argv)++) {
894
      case 'a':
935
            case 'a':
895
      op_flags |= OPT_a;
936
                op_flags |= OPT_a;
896
      if (argc < 4)  
937
                if (argc < 4) {
897
          Usage();
938
                    Usage();
898
      nm = *(++argv);argc--;
939
                }
899
      value = *(++argv);argc--;
940
                nm = *(++argv);
900
      sub = *(++argv);argc--;       
941
                argc--;
901
      goto b1;
942
                value = *(++argv);
943
                argc--;
944
                sub = *(++argv);
945
                argc--;
946
                goto b1;
902
      case 'd':
947
            case 'd':
903
      op_flags |= OPT_d;
948
                op_flags |= OPT_d;
904
      if (argc < 3)  
949
                if (argc < 3) {
905
          Usage();
950
                    Usage();
906
      nm = *(++argv);argc--;
951
                }
907
      sub = *(++argv);argc--;       
952
                nm = *(++argv);
908
      goto b1;
953
                argc--;
909
      case 'E':   
954
                sub = *(++argv);
910
      op_flags |= OPT_E; 
955
                argc--;
911
      if (argc < 2)
956
                goto b1;
912
          Usage();
957
            case 'E':
913
      sub = *(++argv);argc--;       
958
                op_flags |= OPT_E;
914
      goto b1;
959
                if (argc < 2) {
915
      case 'k':   op_flags |= OPT_k; break;
960
                    Usage();
961
                }
962
                sub = *(++argv);
963
                argc--;
964
                goto b1;
965
            case 'k':
966
                op_flags |= OPT_k;
967
                break;
916
      case 'q':
968
            case 'q':
917
      op_flags |= OPT_q;
969
                op_flags |= OPT_q;
918
      if (argc < 3)  
970
                if (argc < 3) {
919
          Usage();
971
                    Usage();
920
      nm = *(++argv);argc--;
972
                }
921
      sub = *(++argv);argc--;       
973
                nm = *(++argv);
922
      goto b1;
974
                argc--;
923
      case 's':   op_flags |= OPT_s; break;
975
                sub = *(++argv);
924
      case 'S':   op_flags |= OPT_S; break;
976
                argc--;
925
      case 'V':   op_flags |= OPT_V; break;
977
                goto b1;
926
      case 'U':   op_flags |= OPT_U; break;
978
            case 's':
927
      case 'w':   op_flags |= OPT_w; break;
979
                op_flags |= OPT_s;
980
                break;
981
            case 'S':
982
                op_flags |= OPT_S;
983
                break;
984
            case 'V':
985
                op_flags |= OPT_V;
986
                break;
987
            case 'U':
988
                op_flags |= OPT_U;
989
                break;
990
            case 'w':
991
                op_flags |= OPT_w;
992
                break;
928
993
929
      default: Usage();   break;
994
            default:
930
      }
995
                Usage();
931
    b1: argc--; argv++;
996
                break;
997
            }
998
b1:
999
        argc--;
1000
        argv++;
932
    }
1001
    }
933
1002
934
    if ((op_flags & OPT_S)) {
1003
    if ((op_flags & OPT_S)) {
935
  // String storage test
1004
        // String storage test
936
  if (argc != 0)
1005
        if (argc != 0) {
937
      Usage();
1006
            Usage();
938
  string s;
1007
        }
1008
        string s;
939
  ConfSimple c(s);
1009
        ConfSimple c(s);
940
  memtest(c);
1010
        memtest(c);
941
  exit(0);
1011
        exit(0);
942
    } else if  ((op_flags & OPT_V)) {
1012
    } else if ((op_flags & OPT_V)) {
943
  // No storage test
1013
        // No storage test
944
  if (argc != 0)
1014
        if (argc != 0) {
945
      Usage();
1015
            Usage();
1016
        }
946
  ConfSimple c;
1017
        ConfSimple c;
947
  memtest(c);
1018
        memtest(c);
948
  exit(0);
1019
        exit(0);
949
    } 
1020
    }
950
1021
951
    // Other tests use file(s) as backing store
1022
    // Other tests use file(s) as backing store
952
    if (argc < 1)
1023
    if (argc < 1) {
953
  Usage();
1024
        Usage();
1025
    }
954
1026
955
    if (op_flags & OPT_U) {
1027
    if (op_flags & OPT_U) {
956
  exit(!complex_updates(argv[0]));
1028
        exit(!complex_updates(argv[0]));
957
    }
1029
    }
958
    vector<string> flist;
1030
    vector<string> flist;
959
    while (argc--) {
1031
    while (argc--) {
960
  flist.push_back(*argv++);
1032
        flist.push_back(*argv++);
961
    }
1033
    }
962
    bool ro = !(op_flags & (OPT_w|OPT_a|OPT_d|OPT_E));
1034
    bool ro = !(op_flags & (OPT_w | OPT_a | OPT_d | OPT_E));
963
    ConfNull *conf = 0;
1035
    ConfNull *conf = 0;
964
    switch (flist.size()) {
1036
    switch (flist.size()) {
965
    case 0:
1037
    case 0:
966
  Usage();
1038
        Usage();
967
  break;
1039
        break;
968
    case 1:
1040
    case 1:
969
  conf = new ConfTree(flist.front().c_str(), ro);
1041
        conf = new ConfTree(flist.front().c_str(), ro);
970
  break;
1042
        break;
971
    default:
1043
    default:
972
  conf = new ConfStack<ConfTree>(flist, ro);
1044
        conf = new ConfStack<ConfTree>(flist, ro);
973
  break;
1045
        break;
974
    }
1046
    }
975
1047
976
    if (op_flags & OPT_w) {
1048
    if (op_flags & OPT_w) {
977
  exit(!readwrite(conf));
1049
        exit(!readwrite(conf));
978
    } else if (op_flags & OPT_q) {
1050
    } else if (op_flags & OPT_q) {
979
  exit(!query(conf, nm, sub));
1051
        exit(!query(conf, nm, sub));
980
    } else if (op_flags & OPT_k) {
1052
    } else if (op_flags & OPT_k) {
981
  if (!conf->ok()) {
1053
        if (!conf->ok()) {
982
      cerr << "conf init error" << endl;
1054
            cerr << "conf init error" << endl;
983
      exit(1);
1055
            exit(1);
984
  }
1056
        }
985
  vector<string>lst = conf->getSubKeys();
1057
        vector<string>lst = conf->getSubKeys();
986
  for (vector<string>::const_iterator it = lst.begin(); 
1058
        for (vector<string>::const_iterator it = lst.begin();
987
       it != lst.end(); it++) {
1059
                it != lst.end(); it++) {
988
      cout << *it << endl;
1060
            cout << *it << endl;
989
  }
1061
        }
990
  exit(0);
1062
        exit(0);
991
    } else if (op_flags & OPT_a) {
1063
    } else if (op_flags & OPT_a) {
992
  exit(!setvar(conf, nm, value, sub));
1064
        exit(!setvar(conf, nm, value, sub));
993
    } else if (op_flags & OPT_d) {
1065
    } else if (op_flags & OPT_d) {
994
  exit(!erase(conf, nm, sub));
1066
        exit(!erase(conf, nm, sub));
995
    } else if (op_flags & OPT_E) {
1067
    } else if (op_flags & OPT_E) {
996
  exit(!eraseKey(conf, sub));
1068
        exit(!eraseKey(conf, sub));
997
    } else if (op_flags & OPT_s) {
1069
    } else if (op_flags & OPT_s) {
998
  if (!conf->ok()) {
1070
        if (!conf->ok()) {
999
      cerr << "Cant open /parse conf file " << endl;
1071
            cerr << "Cant open /parse conf file " << endl;
1000
      exit(1);
1072
            exit(1);
1001
  }
1073
        }
1002
      
1074
1003
  string source;
1075
        string source;
1004
  if (!conf->get(string("strings"), source, "")) {
1076
        if (!conf->get(string("strings"), source, "")) {
1005
      cerr << "Cant get param 'strings'" << endl;
1077
            cerr << "Cant get param 'strings'" << endl;
1006
      exit(1);
1078
            exit(1);
1007
  }
1079
        }
1008
  cout << "source: [" << source << "]" << endl;
1080
        cout << "source: [" << source << "]" << endl;
1009
  vector<string> strings;
1081
        vector<string> strings;
1010
  if (!stringToStrings(source, strings)) {
1082
        if (!stringToStrings(source, strings)) {
1011
      cerr << "parse failed" << endl;
1083
            cerr << "parse failed" << endl;
1012
      exit(1);
1084
            exit(1);
1013
  }
1085
        }
1014
      
1086
1015
  for (vector<string>::iterator it = strings.begin(); 
1087
        for (vector<string>::iterator it = strings.begin();
1016
       it != strings.end(); it++) {
1088
                it != strings.end(); it++) {
1017
      cout << "[" << *it << "]" << endl;
1089
            cout << "[" << *it << "]" << endl;
1018
  }
1090
        }
1019
       
1091
1020
    } else {
1092
    } else {
1021
  if (!conf->ok()) {
1093
        if (!conf->ok()) {
1022
      fprintf(stderr, "Open failed\n");
1094
            fprintf(stderr, "Open failed\n");
1023
      exit(1);
1095
            exit(1);
1024
  }
1096
        }
1025
  printf("LIST\n");
1097
        printf("LIST\n");
1026
  conf->showall();
1098
        conf->showall();
1027
  //printf("WALK\n");conf->sortwalk(mywalker, 0);
1099
        //printf("WALK\n");conf->sortwalk(mywalker, 0);
1028
  printf("\nNAMES in global space:\n");
1100
        printf("\nNAMES in global space:\n");
1029
  vector<string> names = conf->getNames("");
1101
        vector<string> names = conf->getNames("");
1030
  for (vector<string>::iterator it = names.begin();
1102
        for (vector<string>::iterator it = names.begin();
1031
             it!=names.end(); it++) 
1103
                it != names.end(); it++) {
1032
      cout << *it << " ";
1104
            cout << *it << " ";
1105
        }
1033
        cout << endl;
1106
        cout << endl;
1034
  printf("\nNAMES in global space matching t* \n");
1107
        printf("\nNAMES in global space matching t* \n");
1035
  names = conf->getNames("", "t*");
1108
        names = conf->getNames("", "t*");
1036
  for (vector<string>::iterator it = names.begin();
1109
        for (vector<string>::iterator it = names.begin();
1037
             it!=names.end(); it++) 
1110
                it != names.end(); it++) {
1038
      cout << *it << " ";
1111
            cout << *it << " ";
1112
        }
1039
        cout << endl;
1113
        cout << endl;
1040
    }
1114
    }
1041
}
1115
}
1042
1116
1043
#endif
1117
#endif