Switch to unified view

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