librnr  1.14.5
RoadNarrows Robotics Common Library 1
example_config.c
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Common Library 1
4 //
5 // File: example_config.c
6 //
7 /*! \file
8  *
9  * $LastChangedDate: 2011-11-18 13:30:34 -0700 (Fri, 18 Nov 2011) $
10  * $Rev: 1577 $
11  *
12  * \brief Example of using the librnr config module.
13  *
14  * \author Robin Knight (robin.knight@roadnarrows.com)
15  *
16  * \pkgcopyright{2007-2018,RoadNarrows LLC.,http://www.roadnarrows.com}
17  */
18 // Permission is hereby granted, without written agreement and without
19 // license or royalty fees, to use, copy, modify, and distribute this
20 // software and its documentation for any purpose, provided that
21 // (1) The above copyright notice and the following two paragraphs
22 // appear in all copies of the source code and (2) redistributions
23 // including binaries reproduces these notices in the supporting
24 // documentation. Substantial modifications to this software may be
25 // copyrighted by their authors and need not follow the licensing terms
26 // described here, provided that the new terms are clearly indicated in
27 // all files where they apply.
28 //
29 // IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
30 // OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
31 // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
32 // DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
33 // EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
34 // THE POSSIBILITY OF SUCH DAMAGE.
35 //
36 // THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
37 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
38 // FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
39 // "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
40 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
41 //
42 ////////////////////////////////////////////////////////////////////////////////
43 
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 
49 #include "rnr/rnrconfig.h"
50 #include "rnr/log.h"
51 #include "rnr/config.h"
52 
53 /*!
54  * \brief command execution function type
55  */
56 typedef void (*CmdExec_T)(int, char *[]);
57 
58 /*!
59  * \brief command structure type
60  */
61 typedef struct
62 {
63  const char *m_sCmdName; ///< command name
64  CmdExec_T m_fnCmdExec; ///< command execution function
65  const char *m_sCmdHelpArgs; ///< command help arguments
66  const char *m_sCmdHelpDesc; ///< command help description
67 } Cmd_T;
68 
69 static Config_T *TheConfig = NULL; ///< the configuration db
70 
71 /*!
72  * \brief Check argument count against minimum required.
73  *
74  * \param argc Argument count.
75  * \param min Required minimum count.
76  */
77 #define CHKARGS(argc, min) \
78  { if((argc-1) < min) \
79  { \
80  fprintf(stderr, "Error: %d arguments required\n", min); \
81  return; \
82  } \
83  }
84 
85 /*!
86  * \brief Check that the configuration db exists.
87  */
88 #define CHKCFG() \
89  { \
90  if(TheConfig == NULL) \
91  { \
92  fprintf(stderr, "Error: configuration db does not exist\n"); \
93  return; \
94  } \
95  }
96 
97 /*!
98  * \brief Check that the configuration db does not exist.
99  */
100 #define CHKNOCFG() \
101  { \
102  if(TheConfig != NULL) \
103  { \
104  fprintf(stderr, "Error: configuration %s exists - delete first\n", \
105  ConfigDbGetName(TheConfig)); \
106  return; \
107  } \
108  }
109 
110 // forward declaration
111 static void CmdHelp(int, char *[]);
112 
113 /*!
114  * \brief Quit this example program.
115  *
116  * \param argc Command argument count.
117  * \param argv Array of arguments.
118  */
119 static void CmdQuit(int argc, char *argv[])
120 {
121  exit(0);
122 }
123 
124 /*!
125  * \brief Set diagnotics logging level.
126  *
127  * \param argc Command argument count.
128  * \param argv Array of arguments.
129  */
130 static void CmdLog(int argc, char *argv[])
131 {
132  int n;
133 
134  CHKARGS(argc, 1);
135 
136  n = atoi(argv[1]);
137 
139 }
140 
141 /*!
142  * \brief Delete configuration db.
143  *
144  * \param argc Command argument count.
145  * \param argv Array of arguments.
146  */
147 static void CmdDbDelete(int argc, char *argv[])
148 {
149  CHKCFG();
150 
151  ConfigDbDelete(TheConfig);
152  TheConfig = NULL;
153 }
154 
155 /*!
156  * \brief Create new, empty configuration db.
157  *
158  * \param argc Command argument count.
159  * \param argv Array of arguments.
160  */
161 static void CmdDbNew(int argc, char *argv[])
162 {
163  CHKNOCFG();
164 
165  TheConfig = ConfigDbNew(NULL);
166 }
167 
168 /*!
169  * \brief Print out entire configuration db.
170  *
171  * \param argc Command argument count.
172  * \param argv Array of arguments.
173  */
174 static void CmdDbPrint(int argc, char *argv[])
175 {
176  CHKCFG();
177 
178  ConfigDbPrint(TheConfig, stdout);
179 }
180 
181 /*!
182  * \brief Create new configuration db from file.
183  *
184  * \param argc Command argument count.
185  * \param argv Array of arguments.
186  */
187 static void CmdDbRead(int argc, char *argv[])
188 {
189  CHKARGS(argc, 1);
190  CHKNOCFG();
191 
192  TheConfig = ConfigDbRead(argv[1]);
193 }
194 
195 /*!
196  * \brief Delete configuration key.
197  *
198  * \param argc Command argument count.
199  * \param argv Array of arguments.
200  */
201 static void CmdDelete(int argc, char *argv[])
202 {
203  CHKARGS(argc, 2);
204  CHKCFG();
205 
206  if( ConfigDelete(TheConfig, argv[1], argv[2]) != OK )
207  {
208  printf("Error: failed to delete\n");
209  }
210  else
211  {
212  printf("%s: [%s]: %s: deleted\n", ConfigDbGetName(TheConfig),
213  argv[1], argv[2]);
214  }
215 }
216 
217 /*!
218  * \brief Find configuration key=values matching substring.
219  *
220  * \param argc Command argument count.
221  * \param argv Array of arguments.
222  */
223 static void CmdFind(int argc, char *argv[])
224 {
225  char *sPat;
226  size_t lenPat;
227  ConfigIter_T *pIterSects;
228  ConfigIter_T *pIterKeys;
229  const char *sSectionName;
230  const char *sKey;
231  const char *sVal;
232 
233  CHKARGS(argc, 1);
234  CHKCFG();
235 
236  sPat = argv[1];
237  lenPat = strlen(sPat);
238 
239  pIterSects = ConfigDbIterNew(TheConfig);
240 
241  while( (sSectionName = ConfigIterNext(pIterSects)) != NULL )
242  {
243  pIterKeys = ConfigSectionIterNew(TheConfig, sSectionName);
244 
245  while( (sKey = ConfigIterNext(pIterKeys)) != NULL )
246  {
247  if( !strncmp(sPat, sKey, lenPat) )
248  {
249  sVal = ConfigGetStr(TheConfig, sSectionName, sKey);
250  printf("%s: [%s]: %s=%s\n",
251  ConfigDbGetName(TheConfig), sSectionName, sKey, sVal);
252  }
253  }
254 
255  ConfigIterDelete(pIterKeys);
256  }
257 
258  ConfigIterDelete(pIterSects);
259 }
260 
261 /*!
262  * \brief Get configuration value string converting to double.
263  *
264  * \param argc Command argument count.
265  * \param argv Array of arguments.
266  */
267 static void CmdGetd(int argc, char *argv[])
268 {
269  double fVal;
270 
271  CHKARGS(argc, 2);
272  CHKCFG();
273 
274  if( ConfigGetDouble(TheConfig, argv[1], argv[2], &fVal) != OK )
275  {
276  printf("Error: failed to get/convert\n");
277  }
278  else
279  {
280  printf("%s: [%s]: %s=%f\n", ConfigDbGetName(TheConfig),
281  argv[1], argv[2], fVal);
282  }
283 }
284 
285 /*!
286  * \brief Get configuration value string converting to int.
287  *
288  * \param argc Command argument count.
289  * \param argv Array of arguments.
290  */
291 static void CmdGeti(int argc, char *argv[])
292 {
293  int iVal;
294 
295  CHKARGS(argc, 2);
296  CHKCFG();
297 
298  if( ConfigGetInt(TheConfig, argv[1], argv[2], &iVal) != OK )
299  {
300  printf("Error: failed to get/convert\n");
301  }
302  else
303  {
304  printf("%s: [%s]: %s=%d\n", ConfigDbGetName(TheConfig),
305  argv[1], argv[2], iVal);
306  }
307 }
308 
309 /*!
310  * \brief Get configuration value string.
311  *
312  * \param argc Command argument count.
313  * \param argv Array of arguments.
314  */
315 static void CmdGets(int argc, char *argv[])
316 {
317  const char *sVal;
318 
319  CHKARGS(argc, 2);
320  CHKCFG();
321 
322  if( (sVal = ConfigGetStr(TheConfig, argv[1], argv[2])) == NULL )
323  {
324  printf("Error: failed to get\n");
325  }
326  else
327  {
328  printf("%s: [%s]: %s=%s\n", ConfigDbGetName(TheConfig),
329  argv[1], argv[2], sVal);
330  }
331 }
332 
333 /*!
334  * \brief Delete entier configuration db section.
335  *
336  * \param argc Command argument count.
337  * \param argv Array of arguments.
338  */
339 static void CmdSectDelete(int argc, char *argv[])
340 {
341  ConfigSection_T *pSect;
342 
343  CHKARGS(argc, 1);
344  CHKCFG();
345 
346  if( (pSect = ConfigSectionGet(TheConfig, argv[1])) == NULL )
347  {
348  printf("Error: failed to delete section\n");
349  }
350  else
351  {
352  ConfigSectionDelete(TheConfig, pSect);
353  printf("%s: [%s] deleted\n", ConfigDbGetName(TheConfig), argv[1]);
354  }
355 }
356 
357 /*!
358  * \brief Create new, empty configuration db section.
359  *
360  * \param argc Command argument count.
361  * \param argv Array of arguments.
362  */
363 static void CmdSectNew(int argc, char *argv[])
364 {
365  CHKARGS(argc, 1);
366  CHKCFG();
367 
368  if( ConfigSectionNew(TheConfig, argv[1]) == NULL )
369  {
370  printf("Error: failed to add section\n");
371  }
372  else
373  {
374  printf("%s: [%s] added\n", ConfigDbGetName(TheConfig), argv[1]);
375  }
376 }
377 
378 /*!
379  * \brief Set or create key=<double> entry in section.
380  *
381  * \param argc Command argument count.
382  * \param argv Array of arguments.
383  */
384 static void CmdSetd(int argc, char *argv[])
385 {
386  double fVal;
387 
388  CHKARGS(argc, 3);
389  CHKCFG();
390 
391  fVal = atof(argv[3]);
392 
393  if( ConfigSetDouble(TheConfig, argv[1], argv[2], fVal) != OK )
394  {
395  printf("Error: failed to set\n");
396  }
397  else
398  {
399  printf("%s: [%s]: %s=%f\n", ConfigDbGetName(TheConfig),
400  argv[1], argv[2], fVal);
401  }
402 }
403 
404 /*!
405  * \brief Set or create key=<int> entry in section.
406  *
407  * \param argc Command argument count.
408  * \param argv Array of arguments.
409  */
410 static void CmdSeti(int argc, char *argv[])
411 {
412  int iVal;
413 
414  CHKARGS(argc, 3);
415  CHKCFG();
416 
417  iVal = atoi(argv[3]);
418 
419  if( ConfigSetInt(TheConfig, argv[1], argv[2], iVal) != OK )
420  {
421  printf("Error: failed to set\n");
422  }
423  else
424  {
425  printf("%s: [%s]: %s=%d\n", ConfigDbGetName(TheConfig),
426  argv[1], argv[2], iVal);
427  }
428 }
429 
430 /*!
431  * \brief Set or create key=<string> entry in section.
432  *
433  * \param argc Command argument count.
434  * \param argv Array of arguments.
435  */
436 static void CmdSets(int argc, char *argv[])
437 {
438  CHKARGS(argc, 3);
439  CHKCFG();
440 
441  if( ConfigSetStr(TheConfig, argv[1], argv[2], argv[3]) != OK )
442  {
443  printf("Error: failed to set\n");
444  }
445  else
446  {
447  printf("%s: [%s]: %s=%s\n", ConfigDbGetName(TheConfig),
448  argv[1], argv[2], argv[3]);
449  }
450 }
451 
452 /*!
453  * \brief The command set.
454  */
455 static Cmd_T CmdTbl[] =
456 {
457  { "dbdelete", CmdDbDelete, "",
458  "delete existing configuration db"
459  },
460  { "dbnew", CmdDbNew, "",
461  "create new, empty configuration db"
462  },
463  { "dbprint", CmdDbPrint, "",
464  "print out configuration db"
465  },
466  { "dbread", CmdDbRead, "<filename>",
467  "read configuration db from file"
468  },
469 
470  { "delete", CmdDelete, "<section> <key>",
471  "delete entry from section"
472  },
473 
474  { "find", CmdFind, "<pattern>",
475  "find all entries that partially match pattern"
476  },
477 
478  { "getd", CmdGetd, "<section> <key>",
479  "get key=<double> in section"
480  },
481  { "geti", CmdGeti, "<section> <key>",
482  "get key=<int> in section"
483  },
484  { "gets", CmdGets, "<section> <key>",
485  "get key=<string> in section"
486  },
487 
488  { "help", CmdHelp, "",
489  "print list of commands"
490  },
491  { "log", CmdLog, "<level>",
492  "set logging level [0-4]"
493  },
494  { "quit", CmdQuit, "",
495  "quit program"
496  },
497 
498  { "sectdelete", CmdSectDelete, "<section>",
499  "delete section in configuration db"
500  },
501  { "sectnew", CmdSectNew, "<section>",
502  "create new, empty section in configuration db"
503  },
504 
505  { "setd", CmdSetd, "<section> <key> <double>",
506  "set key=<double> in section"
507  },
508  { "seti", CmdSeti, "<section> <key> <int>",
509  "set key=<int> in section"
510  },
511  { "sets", CmdSets, "<section> <key> <string>",
512  "set key=<string> in section"
513  },
514 
515  {NULL, }
516 };
517 
518 /*!
519  * \brief Print command help.
520  *
521  * \param argc Command argument count.
522  * \param argv Array of arguments.
523  */
524 static void CmdHelp(int argc, char *argv[])
525 {
526  Cmd_T *pCmd;
527  int n;
528 
529  for(pCmd=CmdTbl; pCmd->m_sCmdName!=NULL; pCmd++)
530  {
531  n = printf("%s %s", pCmd->m_sCmdName, pCmd->m_sCmdHelpArgs);
532  printf("%*s - %s\n", 30-n, "", pCmd->m_sCmdHelpDesc);
533  }
534 }
535 
536 /*!
537  * \brief Tokenize input.
538  *
539  * \param string Input string
540  * \param [out] tokv Array of tokens.
541  * \param tokmax Maximum number of tokens.
542  *
543  * \return Number of tokens.
544  */
545 static int Tokenize(char *string, char *tokv[], size_t tokmax)
546 {
547  int tokc = 0;
548 
549  while( tokc < tokmax )
550  {
551  while(*string && isspace((int)*string))
552  {
553  string++;
554  }
555  if(!*string)
556  {
557  break;
558  }
559  tokv[tokc] = string;
560  while(*string && !isspace((int)*string))
561  {
562  string++;
563  }
564  tokc++;
565  if( *string == 0 )
566  {
567  break;
568  }
569  *string++ = 0;
570  }
571 
572  return tokc;
573 }
574 
575 /*!
576  * \brief Match command.
577  *
578  * \param sPattern (Partial) command string.
579  * \param tblCmds Table of commands.
580  */
581 static Cmd_T *MatchCmd(const char *sPattern, Cmd_T tblCmds[])
582 {
583  Cmd_T *p;
584  Cmd_T *pCmd = NULL;
585  size_t n;
586  bool_t bIsUnique = true;
587  int cnt;
588 
589  n = strlen(sPattern);
590 
591  // find command
592  for(p=tblCmds; p->m_sCmdName!=NULL; p++)
593  {
594  if( !strncmp(sPattern, p->m_sCmdName, n) )
595  {
596  pCmd = p;
597  break;
598  }
599  }
600 
601  // no matching command found
602  if( pCmd == NULL )
603  {
604  fprintf(stderr, "Error: %s: Command not found\n", sPattern);
605  return NULL;
606  }
607 
608  // verify uniqueness
609  for(p=tblCmds, cnt=0; p->m_sCmdName!=NULL; p++)
610  {
611  if( (p != pCmd) && !strncmp(sPattern, p->m_sCmdName, n) )
612  {
613  cnt++;
614 
615  // first non-unique
616  if( bIsUnique )
617  {
618  fprintf(stderr, "Error: %s: Command not unique: Matches %s %s ",
619  sPattern, pCmd->m_sCmdName, p->m_sCmdName);
620  bIsUnique = false;
621  }
622  // subsequent non-unique
623  else if( cnt < 3 )
624  {
625  fprintf(stderr, "%s ", p->m_sCmdName);
626  }
627  // too many to print
628  else
629  {
630  fprintf(stderr, "...");
631  break;
632  }
633  }
634  }
635 
636  if( !bIsUnique )
637  {
638  fprintf(stderr, "\n");
639  return NULL;
640  }
641 
642  return pCmd;
643 }
644 
645 /*!
646  * \brief Example main.
647  *
648  * \param argc Command-line argument count.
649  * \param argv Command-line argument list.
650  *
651  * \par Exit Status:
652  * Program exits with 0 success, \h_gt 0 on failure.
653  */
654 int main(int argc, char *argv[])
655 {
656  char input[256];
657  int tokc;
658  char *tokv[16];
659  Cmd_T *pCmd;
660 
661  printf(" Configuration Example\n");
662  printf("(enter 'help' for list of commands; "
663  "partial command matching supported)\n\n");
664 
665  // process user commands
666  for(;;)
667  {
668  printf("config> ");
669 
670  // read user input
671  if( !fgets(input, (int)sizeof(input), stdin) )
672  {
673  break;
674  }
675 
676  // tokenize input
677  tokc = Tokenize(input, tokv, arraysize(tokv));
678 
679  if( tokc <= 0 )
680  {
681  continue;
682  }
683 
684  // find command
685  pCmd = MatchCmd(tokv[0], CmdTbl);
686 
687  if( pCmd != NULL )
688  {
689  // execute command
690  pCmd->m_fnCmdExec(tokc, tokv);
691  }
692  }
693 
694  return 0;
695 }
void ConfigIterDelete(ConfigIter_T *pIter)
Delete a configuration iterator.
Definition: config.c:985
int main(int argc, char *argv[])
Example main.
const char * m_sCmdHelpArgs
command help arguments
static void CmdSetd(int argc, char *argv[])
Set or create key=<double> entry in section.
int ConfigDelete(Config_T *pConfig, const char *sSectionName, const char *sKey)
Delete entry from the configuration database.
Definition: config.c:906
static void CmdGetd(int argc, char *argv[])
Get configuration value string converting to double.
static void CmdSectDelete(int argc, char *argv[])
Delete entier configuration db section.
static void CmdFind(int argc, char *argv[])
Find configuration key=values matching substring.
int ConfigSetStr(Config_T *pConfig, const char *sSectionName, const char *sKey, const char *sVal)
Set or update a string value in the configuration database.
Definition: config.c:809
#define OK
Okay.
Definition: rnrconfig.h:301
Configuration parser declarations.
#define NULL
null pointer
Definition: rnrconfig.h:199
static void CmdDbNew(int argc, char *argv[])
Create new, empty configuration db.
int LOG_SET_THRESHOLD(int nLevel)
Set new logging threshold level.
Definition: log.c:96
const char * ConfigGetStr(Config_T *pConfig, const char *sSectionName, const char *sKey)
Get a string value from the configuration database.
Definition: config.c:682
void ConfigDbPrint(Config_T *pConfig, FILE *fp)
Print configuration database to the output file stream.
Definition: config.c:514
ConfigIter_T * ConfigDbIterNew(Config_T *pConfig)
Create a new configuration database iterator.
Definition: config.c:943
static void CmdDbRead(int argc, char *argv[])
Create new configuration db from file.
#define arraysize(array)
array size, i.e. number of array entries
Definition: rnrconfig.h:259
Config_T * ConfigDbNew(const char *sMainName)
Create and initialize a new empty configuration database.
Definition: config.c:243
static int Tokenize(char *string, char *tokv[], size_t tokmax)
Tokenize input.
CmdExec_T m_fnCmdExec
command execution function
static Cmd_T * MatchCmd(const char *sPattern, Cmd_T tblCmds[])
Match command.
static void CmdHelp(int, char *[])
Print command help.
static void CmdDbPrint(int argc, char *argv[])
Print out entire configuration db.
int ConfigSectionDelete(Config_T *pConfig, ConfigSection_T *pSect)
Delete a section from the configuration database.
Definition: config.c:600
static void CmdDbDelete(int argc, char *argv[])
Delete configuration db.
ConfigSection_T * ConfigSectionNew(Config_T *pConfig, const char *sSectionName)
Add a new empty section to the configuration database.
Definition: config.c:547
const char * ConfigIterNext(ConfigIter_T *pIter)
Get the next value in iteration.
Definition: config.c:1004
static Config_T * TheConfig
the configuration db
const char * m_sCmdName
command name
static void CmdSeti(int argc, char *argv[])
Set or create key=<int> entry in section.
static void CmdSets(int argc, char *argv[])
Set or create key=<string> entry in section.
int bool_t
"boolean" T/F
Definition: rnrconfig.h:187
ConfigSection_T * ConfigSectionGet(Config_T *pConfig, const char *sSectionName)
Get a section from the configuration database.
Definition: config.c:635
RoadNarrows Robotics common configuration file.
static void CmdGets(int argc, char *argv[])
Get configuration value string.
static void CmdQuit(int argc, char *argv[])
Quit this example program.
static void CmdSectNew(int argc, char *argv[])
Create new, empty configuration db section.
static int ConfigGetInt(Config_T *pConfig, const char *sSectionName, const char *sKey, int *pVal)
Get and convert an int value from the configuration database.
Definition: config.h:152
#define CHKNOCFG()
Check that the configuration db does not exist.
void(* CmdExec_T)(int, char *[])
command execution function type
static void CmdGeti(int argc, char *argv[])
Get configuration value string converting to int.
void ConfigDbDelete(Config_T *pConfig)
Delete the configuration database.
Definition: config.c:295
command structure type
int ConfigSetDouble(Config_T *pConfig, const char *sSectionName, const char *sKey, double fVal)
Set or update a double value in the configuration database.
Definition: config.c:883
static void CmdLog(int argc, char *argv[])
Set diagnotics logging level.
static Cmd_T CmdTbl[]
The command set.
static void CmdDelete(int argc, char *argv[])
Delete configuration key.
static int ConfigSetInt(Config_T *pConfig, const char *sSectionName, const char *sKey, int iVal)
Set or update an int value in the configuration database.
Definition: config.h:226
Logger declarations.
ConfigIter_T * ConfigSectionIterNew(Config_T *pConfig, const char *sSectionName)
Create a new configuration section iterator.
Definition: config.c:963
#define CHKARGS(argc, min)
Check argument count against minimum required.
int ConfigGetDouble(Config_T *pConfig, const char *sSectionName, const char *sKey, double *pVal)
Get and convert a double value from the configuration database.
Definition: config.c:759
const char * ConfigDbGetName(Config_T *pConfig)
Get the current name assigned to the configuration database.
Definition: config.c:486
const char * m_sCmdHelpDesc
command help description
Config_T * ConfigDbRead(const char *sFileName)
Create a new configuration database from a configuration file.
Definition: config.c:326
#define CHKCFG()
Check that the configuration db exists.