Switch to unified view

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