Switch to unified view

a/src/utils/conftree.cpp b/src/utils/conftree.cpp
1
#ifndef lint
1
#ifndef lint
2
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.8 2006-12-14 13:53:43 dockes Exp $  (C) 2003 J.F.Dockes";
2
static char rcsid [] = "@(#$Id: conftree.cpp,v 1.9 2007-08-03 07:50:49 dockes Exp $  (C) 2003 J.F.Dockes";
3
#endif
3
#endif
4
/*
4
/*
5
 *   This program is free software; you can redistribute it and/or modify
5
 *   This program is free software; you can redistribute it and/or modify
6
 *   it under the terms of the GNU General Public License as published by
6
 *   it under the terms of the GNU General Public License as published by
7
 *   the Free Software Foundation; either version 2 of the License, or
7
 *   the Free Software Foundation; either version 2 of the License, or
...
...
27
#include <ctype.h>
27
#include <ctype.h>
28
28
29
#include <fstream>
29
#include <fstream>
30
#include <sstream>
30
#include <sstream>
31
#include <algorithm>
31
#include <algorithm>
32
#include <iostream>
32
33
33
#include "conftree.h"
34
#include "conftree.h"
34
#include "pathut.h"
35
#include "pathut.h"
35
#include "smallut.h"
36
#include "smallut.h"
36
37
...
...
40
#endif // NO_NAMESPACES
41
#endif // NO_NAMESPACES
41
42
42
#ifndef MIN
43
#ifndef MIN
43
#define MIN(A,B) ((A)<(B) ? (A) : (B))
44
#define MIN(A,B) ((A)<(B) ? (A) : (B))
44
#endif
45
#endif
45
46
46
47
#define LL 1024
47
#define LL 1024
48
void ConfSimple::parseinput(istream &input)
48
void ConfSimple::parseinput(istream &input)
49
{
49
{
50
    string submapkey;
50
    string submapkey;
...
...
76
        line = cline;
76
        line = cline;
77
77
78
    // Note that we trim whitespace before checking for backslash-eol
78
    // Note that we trim whitespace before checking for backslash-eol
79
    // This avoids invisible problems.
79
    // This avoids invisible problems.
80
    trimstring(line);
80
    trimstring(line);
81
    if (line.empty())
81
    if (line.empty()) {
82
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
82
        continue;
83
        continue;
84
  }
83
    if (line[line.length() - 1] == '\\') {
85
    if (line[line.length() - 1] == '\\') {
84
        line.erase(line.length() - 1);
86
        line.erase(line.length() - 1);
85
        appending = true;
87
        appending = true;
86
        continue;
88
        continue;
87
    }
89
    }
...
...
91
        trimstring(line, "[]");
93
        trimstring(line, "[]");
92
        if (dotildexpand)
94
        if (dotildexpand)
93
        submapkey = path_tildexpand(line);
95
        submapkey = path_tildexpand(line);
94
        else 
96
        else 
95
        submapkey = line;
97
        submapkey = line;
98
      // No need for adding sk to order, will be done with first
99
      // variable insert. Also means that empty section are
100
      // expandable (won't be output when rewriting)
101
      // Another option would be to add the subsec to m_order here
102
      // and not do it inside i_set() if init is true
96
        continue;
103
        continue;
97
    }
104
    }
98
105
99
    // Look for first equal sign
106
    // Look for first equal sign
100
    string::size_type eqpos = line.find("=");
107
    string::size_type eqpos = line.find("=");
101
    if (eqpos == string::npos)
108
    if (eqpos == string::npos) {
109
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
102
        continue;
110
        continue;
111
  }
103
112
104
    // Compute name and value, trim white space
113
    // Compute name and value, trim white space
105
    string nm, val;
114
    string nm, val;
106
    nm = line.substr(0, eqpos);
115
    nm = line.substr(0, eqpos);
107
    trimstring(nm);
116
    trimstring(nm);
108
    val = line.substr(eqpos+1, string::npos);
117
    val = line.substr(eqpos+1, string::npos);
109
    trimstring(val);
118
    trimstring(val);
110
    
119
    
111
    if (nm.length() == 0)
120
    if (nm.length() == 0) {
121
      m_order.push_back(ConfLine(ConfLine::CFL_COMMENT, line));
112
        continue;
122
        continue;
113
114
  map<string, map<string, string> >::iterator s;
115
  s = submaps.find(submapkey);
116
  if (s != submaps.end()) {
117
      // submap already exists
118
      map<string, string> &sm = s->second;
119
      sm[nm] = val;
120
  } else {
121
      map<string, string> newmap;
122
      newmap[nm] = val;
123
      submaps[submapkey] = newmap;
124
    }
123
    }
125
124
  i_set(nm, val, submapkey, true);
126
    }
125
    }
127
}
126
}
128
127
129
128
130
ConfSimple::ConfSimple(int readonly, bool tildexp)
129
ConfSimple::ConfSimple(int readonly, bool tildexp)
130
    : dotildexpand(tildexp), m_data(0)
131
{
131
{
132
    data = 0;
133
    dotildexpand = tildexp;
134
    status = readonly ? STATUS_RO : STATUS_RW;
132
    status = readonly ? STATUS_RO : STATUS_RW;
135
}
133
}
136
134
137
ConfSimple::ConfSimple(string *d, int readonly, bool tildexp)
135
ConfSimple::ConfSimple(string *d, int readonly, bool tildexp)
136
    : dotildexpand(tildexp), m_data(d)
138
{
137
{
139
    data = d;
140
    dotildexpand = tildexp;
141
    status = readonly ? STATUS_RO : STATUS_RW;
138
    status = readonly ? STATUS_RO : STATUS_RW;
142
139
143
    stringstream input(*d, ios::in);
140
    stringstream input(*d, ios::in);
144
    parseinput(input);
141
    parseinput(input);
145
}
142
}
146
143
147
148
ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
144
ConfSimple::ConfSimple(const char *fname, int readonly, bool tildexp)
145
    : dotildexpand(tildexp), m_filename(fname), m_data(0)
149
{
146
{
150
    data = 0;
151
    filename = string(fname);
152
    dotildexpand = tildexp;
153
    status = readonly ? STATUS_RO : STATUS_RW;
147
    status = readonly ? STATUS_RO : STATUS_RW;
154
148
155
    ifstream input;
149
    ifstream input;
156
    if (readonly) {
150
    if (readonly) {
157
    input.open(fname, ios::in);
151
    input.open(fname, ios::in);
...
...
178
    if (!input.is_open()) {
172
    if (!input.is_open()) {
179
    status = STATUS_ERROR;
173
    status = STATUS_ERROR;
180
    return;
174
    return;
181
    }       
175
    }       
182
176
183
    // Parse
184
    parseinput(input);
177
    parseinput(input);
185
}
178
}
186
179
187
ConfSimple::StatusCode ConfSimple::getStatus()
180
ConfSimple::StatusCode ConfSimple::getStatus()
188
{
181
{
...
...
198
    if (!ok())
191
    if (!ok())
199
    return 0;
192
    return 0;
200
193
201
    // Find submap
194
    // Find submap
202
    map<string, map<string, string> >::iterator ss;
195
    map<string, map<string, string> >::iterator ss;
203
    if ((ss = submaps.find(sk)) == submaps.end()) 
196
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) 
204
    return 0;
197
    return 0;
205
198
206
    // Find named value
199
    // Find named value
207
    map<string, string>::iterator s;
200
    map<string, string>::iterator s;
208
    if ((s = ss->second.find(nm)) == ss->second.end()) 
201
    if ((s = ss->second.find(nm)) == ss->second.end()) 
209
    return 0;
202
    return 0;
210
    value = s->second;
203
    value = s->second;
211
    return 1;
204
    return 1;
212
}
205
}
213
206
207
// Code to appropriately output a subkey (nm=="") or variable line
208
// Splits long lines
214
static ConfSimple::WalkerCode swalker(void *f, const string &nm, 
209
static ConfSimple::WalkerCode varprinter(void *f, const string &nm, 
215
                      const string &value)
210
                      const string &value)
216
{
211
{
217
    ostream *output = (ostream *)f;
212
    ostream *output = (ostream *)f;
218
    if (nm.empty())
213
    if (nm.empty()) {
219
    *output << "\n[" << value << "]\n";
214
    *output << "\n[" << value << "]\n";
220
    else {
215
    } else {
221
    string value1;
216
    string value1;
222
    if (value.length() < 60) {
217
    if (value.length() < 60) {
223
        value1 = value;
218
        value1 = value;
224
    } else {
219
    } else {
225
        string::size_type pos = 0;
220
        string::size_type pos = 0;
...
...
234
    *output << nm << " = " << value1 << "\n";
229
    *output << nm << " = " << value1 << "\n";
235
    }
230
    }
236
    return ConfSimple::WALK_CONTINUE;
231
    return ConfSimple::WALK_CONTINUE;
237
}
232
}
238
233
234
// Set variable and rewrite data
239
int ConfSimple::set(const std::string &nm, const std::string &value, 
235
int ConfSimple::set(const std::string &nm, const std::string &value, 
240
          const string &sk)
236
            const string &sk)
241
{
237
{
242
    if (status  != STATUS_RW)
238
    if (status  != STATUS_RW)
243
    return 0;
239
    return 0;
244
240
245
    // Preprocess value: we don't want nl's in there, and we want to keep
241
    if (!i_set(nm, value, sk))
246
    // lines to a reasonable length
242
  return 0;
243
    return write();
244
}
245
246
// Internal set variable: no rw checking or file rewriting. If init is
247
// set, we're doing initial parsing, else we are changing a parsed
248
// tree (changes the way we update the order data)
249
int ConfSimple::i_set(const std::string &nm, const std::string &value, 
250
            const string &sk, bool init)
251
{
252
    // Values must not have embedded newlines
247
    if (value.find_first_of("\n\r") != string::npos) {
253
    if (value.find_first_of("\n\r") != string::npos) {
248
    return 0;
254
    return 0;
249
    }
255
    }
250
256
    bool existing = false;
251
    map<string, map<string, string> >::iterator ss;
257
    map<string, map<string, string> >::iterator ss;
252
    if ((ss = submaps.find(sk)) == submaps.end()) {
258
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
253
    map<string, string> submap;
259
    map<string, string> submap;
254
    submap[nm] = value;
260
    submap[nm] = value;
255
    submaps[sk] = submap;
261
    m_submaps[sk] = submap;
256
262
  if (!sk.empty())
263
      m_order.push_back(ConfLine(ConfLine::CFL_SK, sk));
264
  // The var insert will be at the end, need not search for the
265
  // right place
266
  init = true;
257
    } else {
267
    } else {
268
  map<string, string>::iterator it;
269
  it = ss->second.find(nm);
270
  if (it == ss->second.end()) {
271
      ss->second.insert(pair<string,string>(nm, value));
272
  } else {
258
    ss->second[nm] = value;
273
        it->second = value;
259
    }
274
      existing = true;
260
  
261
    if (filename.length()) {
262
  ofstream output(filename.c_str(), ios::out|ios::trunc);
263
  if (!output.is_open())
264
      return 0;
265
  if (sortwalk(swalker, &output) != WALK_CONTINUE) {
266
      return 0;
267
    }
275
    }
276
    }
277
278
    // If the variable already existed, no need to change the order data
279
    if (existing)
268
    return 1;
280
    return 1;
269
    } else if (data) {
281
270
  ostringstream output(*data, ios::out | ios::trunc);
282
    // Add the new variable at the end of its submap in the order data.
271
  if (sortwalk(swalker, &output) != WALK_CONTINUE) {
283
272
      return 0;
284
    if (init) {
273
  }
285
  // During the initial construction, insert at end
286
  m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
274
    return 1;
287
    return 1;
288
    } 
289
290
    list<ConfLine>::iterator start, fin;
291
    if (sk.empty()) {
292
  start = m_order.begin();
275
    } else {
293
    } else {
276
  // No backing store, no writing
294
  start = find(m_order.begin(), m_order.end(), 
277
  return 1;
295
           ConfLine(ConfLine::CFL_SK, sk));
296
  if (start == m_order.end()) {
297
      // This is not logically possible. The subkey must
298
      // exist. We're doomed
299
      std::cerr << "Logical failure during configuration variable " 
300
      "insertion" << endl;
301
      abort();
302
  }
303
    }
304
305
    fin = m_order.end();
306
    if (start != m_order.end()) {
307
  start++;
308
  for (list<ConfLine>::iterator it = start; it != m_order.end(); it++) {
309
      if (it->m_kind == ConfLine::CFL_SK) {
310
      fin = it;
311
      break;
278
    }
312
      }
313
  }
314
    }
315
    m_order.insert(fin, ConfLine(ConfLine::CFL_VAR, nm));
316
317
    return 1;
279
}
318
}
280
319
281
int ConfSimple::erase(const string &nm, const string &sk)
320
int ConfSimple::erase(const string &nm, const string &sk)
282
{
321
{
283
    if (status  != STATUS_RW)
322
    if (status  != STATUS_RW)
284
    return 0;
323
    return 0;
285
324
286
    map<string, map<string, string> >::iterator ss;
325
    map<string, map<string, string> >::iterator ss;
287
    if ((ss = submaps.find(sk)) == submaps.end()) {
326
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
288
    return 0;
327
    return 0;
289
290
    }
328
    }
291
    
329
    
292
    ss->second.erase(nm);
330
    ss->second.erase(nm);
293
  
331
  
294
    if (filename.length()) {
332
    return write();
295
  ofstream output(filename.c_str(), ios::out|ios::trunc);
296
  if (!output.is_open())
297
      return 0;
298
  if (sortwalk(swalker, &output) != WALK_CONTINUE) {
299
      return 0;
300
  }
301
  return 1;
302
    } else if (data) {
303
  ostringstream output(*data, ios::out | ios::trunc);
304
  if (sortwalk(swalker, &output) != WALK_CONTINUE) {
305
      return 0;
306
  }
307
  return 1;
308
    } else {
309
  return 1;
310
    }
311
}
333
}
312
334
313
int ConfSimple::set(const char *nm, const char *value, const char *sk)
335
int ConfSimple::set(const char *nm, const char *value, const char *sk)
314
{
336
{
315
    string ssk = (sk == 0) ? string("") : string(sk);
337
    string ssk = (sk == 0) ? string("") : string(sk);
...
...
321
             void *clidata)
343
             void *clidata)
322
{
344
{
323
    if (!ok())
345
    if (!ok())
324
    return WALK_STOP;
346
    return WALK_STOP;
325
    // For all submaps:
347
    // For all submaps:
326
    for (map<string, map<string, string> >::iterator sit = submaps.begin();
348
    for (map<string, map<string, string> >::iterator sit = m_submaps.begin();
327
     sit != submaps.end(); sit++) {
349
     sit != m_submaps.end(); sit++) {
328
350
329
    // Possibly emit submap name:
351
    // Possibly emit submap name:
330
    if (!sit->first.empty() && walker(clidata, "", sit->first.c_str())
352
    if (!sit->first.empty() && walker(clidata, "", sit->first.c_str())
331
        == WALK_STOP)
353
        == WALK_STOP)
332
        return WALK_STOP;
354
        return WALK_STOP;
...
...
340
    }
362
    }
341
    }
363
    }
342
    return WALK_CONTINUE;
364
    return WALK_CONTINUE;
343
}
365
}
344
366
345
#include <iostream>
367
bool ConfSimple::write()
368
{
369
    if (m_filename.length()) {
370
  ofstream output(m_filename.c_str(), ios::out|ios::trunc);
371
  if (!output.is_open())
372
      return 0;
373
  return write(output);
374
    } else if (m_data) {
375
  ostringstream output(*m_data, ios::out | ios::trunc);
376
  return write(output);
377
    } else {
378
  // No backing store, no writing
379
  return 1;
380
    }
381
}
382
383
bool ConfSimple::write(ostream& out)
384
{
385
    if (!ok())
386
  return false;
387
    string sk;
388
    for (list<ConfLine>::const_iterator it = m_order.begin(); 
389
   it != m_order.end(); it++) {
390
  switch(it->m_kind) {
391
  case ConfLine::CFL_COMMENT: 
392
      out << it->m_data << endl; 
393
      if (!out.good()) 
394
      return false;
395
      break;
396
  case ConfLine::CFL_SK:      
397
      sk = it->m_data;
398
      out << "[" << it->m_data << "]" << endl;
399
      if (!out.good()) 
400
      return false;
401
      break;
402
  case ConfLine::CFL_VAR:
403
      string value;
404
      // As erase() doesnt update m_order we can find unexisting
405
      // variables, and must not output anything for them
406
      if (get(it->m_data, value, sk)) {
407
      varprinter(&out, it->m_data, value);
408
      if (!out.good()) 
409
          return false;
410
      }
411
  }
412
    }
413
    return true;
414
}
415
346
void ConfSimple::listall()
416
void ConfSimple::listall()
347
{
417
{
348
    if (!ok())
418
    if (!ok())
349
    return;
419
    return;
350
    sortwalk(swalker, &std::cout);
420
    write(std::cout);
351
}
421
}
352
422
353
list<string> ConfSimple::getNames(const string &sk)
423
list<string> ConfSimple::getNames(const string &sk)
354
{
424
{
355
    std::list<string> mylist;
425
    std::list<string> mylist;
356
    if (!ok())
426
    if (!ok())
357
    return mylist;
427
    return mylist;
358
    map<string, map<string, string> >::iterator ss;
428
    map<string, map<string, string> >::iterator ss;
359
    if ((ss = submaps.find(sk)) == submaps.end()) {
429
    if ((ss = m_submaps.find(sk)) == m_submaps.end()) {
360
    return mylist;
430
    return mylist;
361
    }
431
    }
362
    map<string, string>::const_iterator it;
432
    map<string, string>::const_iterator it;
363
    for (it = ss->second.begin();it != ss->second.end();it++) {
433
    for (it = ss->second.begin();it != ss->second.end();it++) {
364
    mylist.push_back(it->first);
434
    mylist.push_back(it->first);
365
    }
435
    }
366
    mylist.sort();
436
    mylist.sort();
367
    mylist.unique();
437
    mylist.unique();
438
    return mylist;
439
}
440
441
list<string> ConfSimple::getSubKeys()
442
{
443
    std::list<string> mylist;
444
    if (!ok())
445
  return mylist;
446
    map<string, map<string, string> >::iterator ss;
447
    for (ss = m_submaps.begin(); ss != m_submaps.end(); ss++) {
448
  mylist.push_back(ss->first);
449
    }
368
    return mylist;
450
    return mylist;
369
}
451
}
370
452
371
// //////////////////////////////////////////////////////////////////////////
453
// //////////////////////////////////////////////////////////////////////////
372
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
454
// ConfTree Methods: conftree interpret keys like a hierarchical file tree
...
...
458
540
459
static char usage [] =
541
static char usage [] =
460
    "testconftree [opts] filename\n"
542
    "testconftree [opts] filename\n"
461
    "[-w]  : read/write test.\n"
543
    "[-w]  : read/write test.\n"
462
    "[-s]  : string parsing test. Filename must hold parm 'strings'\n"
544
    "[-s]  : string parsing test. Filename must hold parm 'strings'\n"
545
    "[-a] nm value sect : add nm,value in 'sect' which can be ''\n"
463
    "[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
546
    "[-q] nm sect : subsection test: look for nm in 'sect' which can be ''\n"
464
    "[-d] nm sect : delete nm in 'sect' which can be ''\n"
547
    "[-d] nm sect : delete nm in 'sect' which can be ''\n"
465
    "[-S] : string io test. No filename in this case\n"
548
    "[-S] : string io test. No filename in this case\n"
466
    "[-V] : volatile config test. No filename in this case\n"
549
    "[-V] : volatile config test. No filename in this case\n"
467
    ;
550
    ;
...
...
476
#define OPT_q     0x4
559
#define OPT_q     0x4
477
#define OPT_s     0x8
560
#define OPT_s     0x8
478
#define OPT_S     0x10
561
#define OPT_S     0x10
479
#define OPT_d     0x20
562
#define OPT_d     0x20
480
#define OPT_V     0x40
563
#define OPT_V     0x40
564
#define OPT_a     0x80
481
565
482
int main(int argc, char **argv)
566
int main(int argc, char **argv)
483
{
567
{
484
    const char *nm = 0;
568
    const char *nm = 0;
485
    const char *sub = 0;
569
    const char *sub = 0;
570
    const char *value = 0;
486
571
487
    thisprog = argv[0];
572
    thisprog = argv[0];
488
    argc--; argv++;
573
    argc--; argv++;
489
574
490
    while (argc > 0 && **argv == '-') {
575
    while (argc > 0 && **argv == '-') {
...
...
492
    if (!(**argv))
577
    if (!(**argv))
493
        /* Cas du "adb - core" */
578
        /* Cas du "adb - core" */
494
        Usage();
579
        Usage();
495
    while (**argv)
580
    while (**argv)
496
        switch (*(*argv)++) {
581
        switch (*(*argv)++) {
497
        case 'd':   
582
        case 'd':
498
        op_flags |= OPT_d;
583
        op_flags |= OPT_d;
499
        if (argc < 3)  
584
        if (argc < 3)  
500
            Usage();
585
            Usage();
501
        nm = *(++argv);argc--;
586
        nm = *(++argv);argc--;
587
      sub = *(++argv);argc--;       
588
      goto b1;
589
      case 'a':
590
      op_flags |= OPT_a;
591
      if (argc < 4)  
592
          Usage();
593
      nm = *(++argv);argc--;
594
      value = *(++argv);argc--;
502
        sub = *(++argv);argc--;       
595
        sub = *(++argv);argc--;       
503
        goto b1;
596
        goto b1;
504
        case 'q':
597
        case 'q':
505
        op_flags |= OPT_q;
598
        op_flags |= OPT_q;
506
        if (argc < 3)  
599
        if (argc < 3)  
...
...
554
            printf("unstring not set\n");
647
            printf("unstring not set\n");
555
        }
648
        }
556
        }
649
        }
557
        char spid[100];
650
        char spid[100];
558
        sprintf(spid, "%d", getpid());
651
        sprintf(spid, "%d", getpid());
559
        parms.set("mypid", spid);
652
        if (!parms.set("mypid", spid)) {
653
      cerr << "Set mypid failed" << endl;
654
      }
560
655
561
        ostringstream ost;;
656
        ostringstream ost;;
562
        ost << "mypid" << getpid();
657
        ost << "mypid" << getpid();
563
        parms.set(ost.str(), spid, "");
658
        if (!parms.set(ost.str(), spid, "")) {
564
659
      cerr << "Set mypid failed (2)" << endl;
660
      }
565
        parms.set("unstring", "Une jolie phrase pour essayer");
661
        if (!parms.set("unstring", "Une jolie phrase pour essayer")) {
662
      cerr << "Set unstring failed" << endl;
663
      }
566
    } else if (op_flags & OPT_q) {
664
    } else if (op_flags & OPT_q) {
567
        ConfTree parms(filename, 0);
665
        ConfTree parms(filename, 0);
568
        if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
666
        if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
569
        fprintf(stderr, "Error opening or parsing file\n");
667
        fprintf(stderr, "Error opening or parsing file\n");
570
        exit(1);
668
        exit(1);
...
...
573
        if (!parms.get(nm, value, sub)) {
671
        if (!parms.get(nm, value, sub)) {
574
        fprintf(stderr, "name '%s' not found in '%s'\n", nm, sub);
672
        fprintf(stderr, "name '%s' not found in '%s'\n", nm, sub);
575
        exit(1);
673
        exit(1);
576
        }
674
        }
577
        printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
675
        printf("%s : '%s' = '%s'\n", sub, nm, value.c_str());
676
      exit(0);
677
  } else if (op_flags & OPT_a) {
678
      ConfTree parms(filename, 0);
679
      if (parms.getStatus() == ConfSimple::STATUS_ERROR) {
680
      fprintf(stderr, "Error opening or parsing file\n");
681
      exit(1);
682
      }
683
      if (!parms.set(nm, value, sub)) {
684
      fprintf(stderr, "Set error\n");
685
      exit(1);
686
      }
578
        exit(0);
687
        exit(0);
579
    } else if (op_flags & OPT_d) {
688
    } else if (op_flags & OPT_d) {
580
        ConfTree parms(filename, 0);
689
        ConfTree parms(filename, 0);
581
        if (parms.getStatus() != ConfSimple::STATUS_RW) {
690
        if (parms.getStatus() != ConfSimple::STATUS_RW) {
582
        fprintf(stderr, "Error opening or parsing file\n");
691
        fprintf(stderr, "Error opening or parsing file\n");