add API to remove section
[oweals/gnunet.git] / src / util / configuration.c
1 /*
2      This file is part of GNUnet.
3      (C) 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 2, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file src/util/configuration.c
23  * @brief configuration management
24  *
25  * @author Christian Grothoff
26  */
27
28 #include "platform.h"
29 #include "gnunet_common.h"
30 #include "gnunet_configuration_lib.h"
31 #include "gnunet_crypto_lib.h"
32 #include "gnunet_disk_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_strings_lib.h"
35
36
37 /**
38  * @brief configuration entry
39  */
40 struct ConfigEntry
41 {
42
43   /**
44    * This is a linked list.
45    */
46   struct ConfigEntry *next;
47
48   /**
49    * key for this entry
50    */
51   char *key;
52
53   /**
54    * current, commited value
55    */
56   char *val;
57 };
58
59
60 /**
61  * @brief configuration section
62  */
63 struct ConfigSection
64 {
65   /**
66    * This is a linked list.
67    */
68   struct ConfigSection *next;
69
70   /**
71    * entries in the section
72    */
73   struct ConfigEntry *entries;
74
75   /**
76    * name of the section
77    */
78   char *name;
79 };
80
81
82 /**
83  * @brief configuration data
84  */
85 struct GNUNET_CONFIGURATION_Handle
86 {
87   /**
88    * Configuration sections.
89    */
90   struct ConfigSection *sections;
91
92   /**
93    * Modification indication since last save
94    * GNUNET_NO if clean, GNUNET_YES if dirty,
95    * GNUNET_SYSERR on error (i.e. last save failed)
96    */
97   int dirty;
98
99 };
100
101
102 /**
103  * Used for diffing a configuration object against
104  * the default one
105  */
106 struct DiffHandle
107 {
108   const struct GNUNET_CONFIGURATION_Handle *cfgDefault;
109   struct GNUNET_CONFIGURATION_Handle *cfgDiff;
110 };
111
112
113
114 /**
115  * Create a GNUNET_CONFIGURATION_Handle.
116  *
117  * @return fresh configuration object
118  */
119 struct GNUNET_CONFIGURATION_Handle *
120 GNUNET_CONFIGURATION_create ()
121 {
122   return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle));
123 }
124
125
126 /**
127  * Destroy configuration object.
128  *
129  * @param cfg configuration to destroy
130  */
131 void
132 GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
133 {
134   struct ConfigSection *sec;
135
136   while (NULL != (sec = cfg->sections))
137     GNUNET_CONFIGURATION_remove_section (cfg, sec->name);
138   GNUNET_free (cfg);
139 }
140
141
142 /**
143  * Parse a configuration file, add all of the options in the
144  * file to the configuration environment.
145  *
146  * @param cfg configuration to update
147  * @param filename name of the configuration file
148  * @return GNUNET_OK on success, GNUNET_SYSERR on error
149  */
150 int
151 GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
152                             const char *filename)
153 {
154   int dirty;
155   char line[256];
156   char tag[64];
157   char value[192];
158   FILE *fp;
159   unsigned int nr;
160   int i;
161   int emptyline;
162   int ret;
163   char *section;
164   char *fn;
165
166   fn = GNUNET_STRINGS_filename_expand (filename);
167   if (fn == NULL)
168     return GNUNET_SYSERR;
169   dirty = cfg->dirty;           /* back up value! */
170   if (NULL == (fp = FOPEN (fn, "r")))
171     {
172       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
173       GNUNET_free (fn);
174       return GNUNET_SYSERR;
175     }
176   GNUNET_free (fn);
177   ret = GNUNET_OK;
178   section = GNUNET_strdup ("");
179   memset (line, 0, 256);
180   nr = 0;
181   while (NULL != fgets (line, 255, fp))
182     {
183       nr++;
184       for (i = 0; i < 255; i++)
185         if (line[i] == '\t')
186           line[i] = ' ';
187       if (line[0] == '\n' || line[0] == '#' || line[0] == '%' ||
188           line[0] == '\r')
189         continue;
190       emptyline = 1;
191       for (i = 0; (i < 255 && line[i] != 0); i++)
192         if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r')
193           emptyline = 0;
194       if (emptyline == 1)
195         continue;
196       /* remove tailing whitespace */
197       for (i = strlen (line) - 1; (i >= 0) && (isspace ( (unsigned char) line[i])); i--)
198         line[i] = '\0';
199       if (1 == sscanf (line, "@INLINE@ %191[^\n]", value))
200         {
201           /* @INLINE@ value */
202           if (GNUNET_OK != GNUNET_CONFIGURATION_parse (cfg, value))
203             ret = GNUNET_SYSERR;        /* failed to parse included config */
204         }
205       else if (1 == sscanf (line, "[%99[^]]]", value))
206         {
207           /* [value] */
208           GNUNET_free (section);
209           section = GNUNET_strdup (value);
210         }
211       else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value))
212         {
213           /* tag = value */
214           /* Strip LF */
215           i = strlen (value) - 1;
216           while ((i >= 0) && (isspace ( (unsigned char) value[i])))
217             value[i--] = '\0';
218           /* remove quotes */
219           i = 0;
220           if (value[0] == '"')
221             {
222               i = 1;
223               while ((value[i] != '\0') && (value[i] != '"'))
224                 i++;
225               if (value[i] == '"')
226                 {
227                   value[i] = '\0';
228                   i = 1;
229                 }
230               else
231                 i = 0;
232             }
233           GNUNET_CONFIGURATION_set_value_string (cfg,
234                                                  section, tag, &value[i]);
235         }
236       else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag))
237         {
238           /* tag = */
239           GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, "");
240         }
241       else
242         {
243           /* parse error */
244           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
245                       _
246                       ("Syntax error in configuration file `%s' at line %u.\n"),
247                       filename, nr);
248           ret = GNUNET_SYSERR;
249           break;
250         }
251     }
252   GNUNET_assert (0 == fclose (fp));
253   /* restore dirty flag - anything we set in the meantime
254      came from disk */
255   cfg->dirty = dirty;
256   GNUNET_free (section);
257   return ret;
258 }
259
260
261 /**
262  * Test if there are configuration options that were
263  * changed since the last save.
264  *
265  * @param cfg configuration to inspect
266  * @return GNUNET_NO if clean, GNUNET_YES if dirty, GNUNET_SYSERR on error (i.e. last save failed)
267  */
268 int
269 GNUNET_CONFIGURATION_is_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
270 {
271   return cfg->dirty;
272 }
273
274
275 /**
276  * Write configuration file.
277  *
278  * @param cfg configuration to write
279  * @param filename where to write the configuration
280  * @return GNUNET_OK on success, GNUNET_SYSERR on error
281  */
282 int
283 GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *cfg,
284                             const char *filename)
285 {
286   struct ConfigSection *sec;
287   struct ConfigEntry *ent;
288   FILE *fp;
289   int error;
290   char *fn;
291   char *val;
292   char *pos;
293
294   fn = GNUNET_STRINGS_filename_expand (filename);
295   if (fn == NULL)
296     return GNUNET_SYSERR;
297   if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (fn))
298     {
299       GNUNET_free (fn);
300       return GNUNET_SYSERR;
301     }
302   if (NULL == (fp = FOPEN (fn, "w")))
303     {
304       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
305       GNUNET_free (fn);
306       return GNUNET_SYSERR;
307     }
308   GNUNET_free (fn);
309   error = 0;
310   sec = cfg->sections;
311   while (sec != NULL)
312     {
313       if (0 > fprintf (fp, "[%s]\n", sec->name))
314         {
315           error = 1;
316           break;
317         }
318       ent = sec->entries;
319       while (ent != NULL)
320         {
321           if (ent->val != NULL)
322             {
323               val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
324               strcpy (val, ent->val);
325               while (NULL != (pos = strstr (val, "\n")))
326                 {
327                   memmove (&pos[2], &pos[1], strlen (&pos[1]));
328                   pos[0] = '\\';
329                   pos[1] = 'n';
330                 }
331               if (0 > fprintf (fp, "%s = %s\n", ent->key, val))
332                 {
333                   error = 1;
334                   GNUNET_free (val);
335                   break;
336                 }
337               GNUNET_free (val);
338             }
339           ent = ent->next;
340         }
341       if (error != 0)
342         break;
343       if (0 > fprintf (fp, "\n"))
344         {
345           error = 1;
346           break;
347         }
348       sec = sec->next;
349     }
350   if (error != 0)
351     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename);
352   GNUNET_assert (0 == fclose (fp));
353   if (error != 0)
354     {
355       cfg->dirty = GNUNET_SYSERR;       /* last write failed */
356       return GNUNET_SYSERR;
357     }
358   cfg->dirty = GNUNET_NO;       /* last write succeeded */
359   return GNUNET_OK;
360 }
361
362
363 /**
364  * Iterate over all options in the configuration.
365  *
366  * @param cfg configuration to inspect
367  * @param iter function to call on each option
368  * @param iter_cls closure for iter
369  */
370 void
371 GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
372                               GNUNET_CONFIGURATION_Iterator iter,
373                               void *iter_cls)
374 {
375   struct ConfigSection *spos;
376   struct ConfigEntry *epos;
377
378   spos = cfg->sections;
379   while (spos != NULL)
380     {
381       epos = spos->entries;
382       while (epos != NULL)
383         {
384           iter (iter_cls, spos->name, epos->key, epos->val);
385           epos = epos->next;
386         }
387       spos = spos->next;
388     }
389 }
390
391
392 /**
393  * Iterate over all sections in the configuration.
394  *
395  * @param cfg configuration to inspect
396  * @param iter function to call on each section
397  * @param iter_cls closure for iter
398  */
399 void
400 GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle *cfg,
401                                        GNUNET_CONFIGURATION_Section_Iterator iter,
402                                        void *iter_cls)
403 {
404   struct ConfigSection *spos;
405   struct ConfigSection *next;
406
407   next = cfg->sections; 
408   while (next != NULL)
409     {
410       spos = next;
411       next = spos->next;
412       iter (iter_cls, spos->name);
413     }
414 }
415
416 /**
417  * Remove the given section and all options in it.
418  *
419  * @param cfg configuration to inspect
420  * @param section name of the section to remove
421  */
422 void GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
423                                           const char *section)
424 {
425   struct ConfigSection *spos;
426   struct ConfigSection *prev;
427   struct ConfigEntry *ent;
428
429   prev = NULL;
430   spos = cfg->sections; 
431   while (spos != NULL)   
432     {
433       if (0 == strcmp (section,
434                        spos->name))
435         {
436           if (prev == NULL)
437             cfg->sections = spos->next;
438           else
439             prev->next = spos->next;
440           while (NULL != (ent = spos->entries))
441             {
442               spos->entries = ent->next;
443               GNUNET_free (ent->key);
444               GNUNET_free_non_null (ent->val);
445               GNUNET_free (ent);
446               cfg->dirty = GNUNET_YES;
447             }
448           GNUNET_free (spos->name);
449           GNUNET_free (spos);
450           return;
451         }
452       prev = spos;
453       spos = spos->next;
454     }
455 }
456
457
458 /**
459  * Copy a configuration value to the given target configuration.
460  * Overwrites existing entries.
461  *
462  * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*)
463  * @param section section for the value
464  * @param option option name of the value
465  * @param value value to copy 
466  */
467 static void
468 copy_entry (void *cls,
469             const char *section, const char *option, const char *value)
470 {
471   struct GNUNET_CONFIGURATION_Handle *dst = cls;
472   GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
473 }
474
475
476 /**
477  * Duplicate an existing configuration object.
478  *
479  * @param cfg configuration to duplicate
480  * @return duplicate configuration
481  */
482 struct GNUNET_CONFIGURATION_Handle *
483 GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
484 {
485   struct GNUNET_CONFIGURATION_Handle *ret;
486
487   ret = GNUNET_CONFIGURATION_create ();
488   GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
489   return ret;
490 }
491
492
493 /**
494  * FIXME.
495  *
496  * @param cfg FIXME
497  * @param section FIXME
498  * @return matching entry, NULL if not found
499  */
500 static struct ConfigSection *
501 findSection (const struct GNUNET_CONFIGURATION_Handle *cfg,
502              const char *section)
503 {
504   struct ConfigSection *pos;
505
506   pos = cfg->sections;
507   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
508     pos = pos->next;
509   return pos;
510 }
511
512
513 /**
514  * Find an entry from a configuration.
515  *
516  * @param cfg handle to the configuration
517  * @param section section the option is in
518  * @param key the option
519  * @return matching entry, NULL if not found
520  */
521 static struct ConfigEntry *
522 findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg,
523            const char *section, const char *key)
524 {
525   struct ConfigSection *sec;
526   struct ConfigEntry *pos;
527
528   sec = findSection (cfg, section);
529   if (sec == NULL)
530     return NULL;
531   pos = sec->entries;
532   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
533     pos = pos->next;
534   return pos;
535 }
536
537
538 /**
539  * A callback function, compares entries from two configurations
540  * (default against a new configuration) and write the diffs in a
541  * diff-configuration object (the callback object).
542  *
543  * @param cls the diff configuration (struct DiffHandle*)
544  * @param section section for the value (of the default conf.)
545  * @param option option name of the value (of the default conf.)
546  * @param value value to copy (of the default conf.)
547  */
548 static void
549 compareEntries (void *cls,
550                 const char *section, const char *option, const char *value)
551 {
552   struct DiffHandle *dh = cls;
553   struct ConfigEntry *entNew;
554  
555   entNew = findEntry (dh->cfgDefault, section, option);
556   if ( (entNew != NULL) &&
557        (strcmp (entNew->val, value) == 0) )
558     return;
559   GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff,
560                                          section,
561                                          option,
562                                          value);
563 }
564
565
566 /**
567  * Write only configuration entries that have been changed to configuration file
568  * @param cfgDefault default configuration
569  * @param cfgNew new configuration
570  * @param filename where to write the configuration diff between default and new
571  * @return GNUNET_OK on success, GNUNET_SYSERR on error
572  */
573 int
574 GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle
575                                   *cfgDefault,
576                                   const struct GNUNET_CONFIGURATION_Handle *cfgNew,
577                                   const char *filename)
578 {
579   int ret;
580   struct DiffHandle diffHandle;
581
582   diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
583   diffHandle.cfgDefault = cfgDefault;
584   GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle);
585   ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename);
586   GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff);
587   return ret;
588 }
589
590
591 /**
592  * Set a configuration value that should be a string.
593  *
594  * @param cfg configuration to update
595  * @param section section of interest
596  * @param option option of interest
597  * @param value value to set
598  */
599 void
600 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle
601                                        *cfg,
602                                        const char *section,
603                                        const char *option, const char *value)
604 {
605   struct ConfigSection *sec;
606   struct ConfigEntry *e;
607
608   e = findEntry (cfg, section, option);
609   if (e != NULL)
610     {
611       GNUNET_free_non_null (e->val);
612       e->val = GNUNET_strdup (value);
613       return;
614     }
615   sec = findSection (cfg, section);
616   if (sec == NULL)
617     {
618       sec = GNUNET_malloc (sizeof (struct ConfigSection));
619       sec->name = GNUNET_strdup (section);
620       sec->next = cfg->sections;
621       cfg->sections = sec;
622     }
623   e = GNUNET_malloc (sizeof (struct ConfigEntry));
624   e->key = GNUNET_strdup (option);
625   e->val = GNUNET_strdup (value);
626   e->next = sec->entries;
627   sec->entries = e;
628 }
629
630
631 /**
632  * Set a configuration value that should be a number.
633  *
634  * @param cfg configuration to update
635  * @param section section of interest
636  * @param option option of interest
637  * @param number value to set
638  */
639 void
640 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle
641                                        *cfg, const char *section,
642                                        const char *option,
643                                        unsigned long long number)
644 {
645   char s[64];
646   GNUNET_snprintf (s, 64, "%llu", number);
647   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
648 }
649
650
651 /**
652  * Get a configuration value that should be a number.
653  *
654  * @param cfg configuration to inspect
655  * @param section section of interest
656  * @param option option of interest
657  * @param number where to store the numeric value of the option
658  * @return GNUNET_OK on success, GNUNET_SYSERR on error
659  */
660 int
661 GNUNET_CONFIGURATION_get_value_number (const struct
662                                        GNUNET_CONFIGURATION_Handle *cfg,
663                                        const char *section,
664                                        const char *option,
665                                        unsigned long long *number)
666 {
667   struct ConfigEntry *e;
668
669   e = findEntry (cfg, section, option);
670   if (e == NULL)
671     return GNUNET_SYSERR;
672   if (1 != SSCANF (e->val, "%llu", number))
673     return GNUNET_SYSERR;
674   return GNUNET_OK;
675 }
676
677
678 /**
679  * Get a configuration value that should be a relative time.
680  *
681  * @param cfg configuration to inspect
682  * @param section section of interest
683  * @param option option of interest
684  * @param time set to the time value stored in the configuration
685  * @return GNUNET_OK on success, GNUNET_SYSERR on error
686  */
687 int
688 GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle
689                                      *cfg, const char *section,
690                                      const char *option,
691                                      struct GNUNET_TIME_Relative *time)
692 {
693   unsigned long long num;
694   int ret;
695
696   ret = GNUNET_CONFIGURATION_get_value_number (cfg, section, option, &num);
697   if (ret == GNUNET_OK)
698     time->rel_value = (uint64_t) num;
699   return ret;
700 }
701
702
703 /**
704  * Get a configuration value that should be a string.
705  *
706  * @param cfg configuration to inspect
707  * @param section section of interest
708  * @param option option of interest
709  * @param value will be set to a freshly allocated configuration
710  *        value, or NULL if option is not specified
711  * @return GNUNET_OK on success, GNUNET_SYSERR on error
712  */
713 int
714 GNUNET_CONFIGURATION_get_value_string (const struct
715                                        GNUNET_CONFIGURATION_Handle *cfg,
716                                        const char *section,
717                                        const char *option, char **value)
718 {
719   struct ConfigEntry *e;
720
721   e = findEntry (cfg, section, option);
722   if ((e == NULL) || (e->val == NULL))
723     {
724       *value = NULL;
725       return GNUNET_SYSERR;
726     }
727   *value = GNUNET_strdup (e->val);
728   return GNUNET_OK;
729 }
730
731
732 /**
733  * Get a configuration value that should be in a set of
734  * predefined strings
735  *
736  * @param cfg configuration to inspect
737  * @param section section of interest
738  * @param option option of interest
739  * @param choices NULL-terminated list of legal values
740  * @param value will be set to an entry in the legal list,
741  *        or NULL if option is not specified and no default given
742  * @return GNUNET_OK on success, GNUNET_SYSERR on error
743  */
744 int
745 GNUNET_CONFIGURATION_get_value_choice (const struct
746                                        GNUNET_CONFIGURATION_Handle *cfg,
747                                        const char *section,
748                                        const char *option,
749                                        const char **choices,
750                                        const char **value)
751 {
752   struct ConfigEntry *e;
753   int i;
754
755   e = findEntry (cfg, section, option);
756   if (e == NULL)
757     return GNUNET_SYSERR;
758   i = 0;
759   while (choices[i] != NULL)
760     {
761       if (0 == strcasecmp (choices[i], e->val))
762         break;
763       i++;
764     }
765   if (choices[i] == NULL)
766     {
767       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
768                   _("Configuration value '%s' for '%s'"
769                     " in section '%s' is not in set of legal choices\n"),
770                   e->val, option, section);
771       return GNUNET_SYSERR;
772     }
773   *value = choices[i];
774   return GNUNET_OK;
775 }
776
777
778 /**
779  * Test if we have a value for a particular option
780  * @param cfg configuration to inspect
781  * @param section section of interest
782  * @param option option of interest
783  * @return GNUNET_YES if so, GNUNET_NO if not.
784  */
785 int
786 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle
787                                  *cfg, const char *section,
788                                  const char *option)
789 {
790   struct ConfigEntry *e;
791   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
792     return GNUNET_NO;
793   return GNUNET_YES;
794 }
795
796
797 /**
798  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
799  * where either in the "PATHS" section or the environtment
800  * "FOO" is set to "DIRECTORY".
801  *
802  * @param cfg configuration to use for path expansion
803  * @param orig string to $-expand (will be freed!)
804  * @return $-expanded string
805  */
806 char *
807 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
808                                     *cfg, char *orig)
809 {
810   int i;
811   char *prefix;
812   char *result;
813   const char *post;
814   const char *env;
815
816   if (orig[0] != '$')
817     return orig;
818   i = 0;
819   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
820     i++;
821   if (orig[i] == '\0')
822     {
823       post = "";
824     }
825   else
826     {
827       orig[i] = '\0';
828       post = &orig[i + 1];
829     }
830   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
831                                                             "PATHS",
832                                                             &orig[1], &prefix))
833     {
834       if (NULL == (env = getenv (&orig[1])))
835         {
836           orig[i] = DIR_SEPARATOR;
837           return orig;
838         }
839       prefix = GNUNET_strdup (env);
840     }
841   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
842   strcpy (result, prefix);
843   if ((strlen (prefix) == 0) ||
844       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
845     strcat (result, DIR_SEPARATOR_STR);
846   strcat (result, post);
847   GNUNET_free (prefix);
848   GNUNET_free (orig);
849   return result;
850 }
851
852
853 /**
854  * Get a configuration value that should be a string.
855  *
856  * @param cfg configuration to inspect
857  * @param section section of interest
858  * @param option option of interest
859  * @param value will be set to a freshly allocated configuration
860  *        value, or NULL if option is not specified
861  * @return GNUNET_OK on success, GNUNET_SYSERR on error
862  */
863 int
864 GNUNET_CONFIGURATION_get_value_filename (const struct
865                                          GNUNET_CONFIGURATION_Handle *cfg,
866                                          const char *section,
867                                          const char *option, char **value)
868 {
869   char *tmp;
870
871   if (GNUNET_OK !=
872       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
873     {
874       *value = NULL;
875       return GNUNET_SYSERR;
876     }
877   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
878   *value = GNUNET_STRINGS_filename_expand (tmp);
879   GNUNET_free (tmp);
880   if (*value == NULL)
881     return GNUNET_SYSERR;
882   return GNUNET_OK;
883 }
884
885
886 /**
887  * Get a configuration value that should be in a set of
888  * "GNUNET_YES" or "GNUNET_NO".
889  *
890  * @param cfg configuration to inspect
891  * @param section section of interest
892  * @param option option of interest
893  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
894  */
895 int
896 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
897                                       *cfg, const char *section,
898                                       const char *option)
899 {
900   static const char *yesno[] = { "YES", "NO", NULL };
901   const char *val;
902   int ret;
903
904   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
905                                                section, option, yesno, &val);
906   if (ret == GNUNET_SYSERR)
907     return ret;
908   if (val == yesno[0])
909     return GNUNET_YES;
910   return GNUNET_NO;
911 }
912
913
914 /**
915  * Iterate over the set of filenames stored in a configuration value.
916  *
917  * @param cfg configuration to inspect
918  * @param section section of interest
919  * @param option option of interest
920  * @param cb function to call on each filename
921  * @param cb_cls closure for cb
922  * @return number of filenames iterated over, -1 on error
923  */
924 int
925 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
926                                               GNUNET_CONFIGURATION_Handle
927                                               *cfg, const char *section,
928                                               const char *option,
929                                               GNUNET_FileNameCallback cb,
930                                               void *cb_cls)
931 {
932   char *list;
933   char *pos;
934   char *end;
935   char old;
936   int ret;
937
938   if (GNUNET_OK !=
939       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
940     return 0;
941   GNUNET_assert (list != NULL);
942   ret = 0;
943   pos = list;
944   while (1)
945     {
946       while (pos[0] == ' ')
947         pos++;
948       if (strlen (pos) == 0)
949         break;
950       end = pos + 1;
951       while ((end[0] != ' ') && (end[0] != '\0'))
952         {
953           if (end[0] == '\\')
954             {
955               switch (end[1])
956                 {
957                 case '\\':
958                 case ' ':
959                   memmove (end, &end[1], strlen (&end[1]) + 1);
960                 case '\0':
961                   /* illegal, but just keep it */
962                   break;
963                 default:
964                   /* illegal, but just ignore that there was a '/' */
965                   break;
966                 }
967             }
968           end++;
969         }
970       old = end[0];
971       end[0] = '\0';
972       if (strlen (pos) > 0)
973         {
974           ret++;
975           if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
976             {
977               ret = GNUNET_SYSERR;
978               break;
979             }
980         }
981       if (old == '\0')
982         break;
983       pos = end + 1;
984     }
985   GNUNET_free (list);
986   return ret;
987 }
988
989
990 /**
991  * FIXME.
992  *
993  * @param value FIXME
994  * @return FIXME
995  */
996 static char *
997 escape_name (const char *value)
998 {
999   char *escaped;
1000   const char *rpos;
1001   char *wpos;
1002
1003   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1004   memset (escaped, 0, strlen (value) * 2 + 1);
1005   rpos = value;
1006   wpos = escaped;
1007   while (rpos[0] != '\0')
1008     {
1009       switch (rpos[0])
1010         {
1011         case '\\':
1012         case ' ':
1013           wpos[0] = '\\';
1014           wpos[1] = rpos[0];
1015           wpos += 2;
1016           break;
1017         default:
1018           wpos[0] = rpos[0];
1019           wpos++;
1020         }
1021       rpos++;
1022     }
1023   return escaped;
1024 }
1025
1026
1027 /**
1028  * FIXME.
1029  *
1030  * @param cls string we compare with (const char*)
1031  * @param fn filename we are currently looking at
1032  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1033  */
1034 static int
1035 test_match (void *cls, const char *fn)
1036 {
1037   const char *of = cls;
1038   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1039 }
1040
1041
1042 /**
1043  * Append a filename to a configuration value that
1044  * represents a list of filenames
1045  *
1046  * @param cfg configuration to update
1047  * @param section section of interest
1048  * @param option option of interest
1049  * @param value filename to append
1050  * @return GNUNET_OK on success,
1051  *         GNUNET_NO if the filename already in the list
1052  *         GNUNET_SYSERR on error
1053  */
1054 int
1055 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1056                                             *cfg,
1057                                             const char *section,
1058                                             const char *option,
1059                                             const char *value)
1060 {
1061   char *escaped;
1062   char *old;
1063   char *nw;
1064
1065   if (GNUNET_SYSERR
1066       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
1067                                                        section,
1068                                                        option,
1069                                                        &test_match,
1070                                                        (void *) value))
1071     return GNUNET_NO;           /* already exists */
1072   if (GNUNET_OK !=
1073       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1074     old = GNUNET_strdup ("");
1075   escaped = escape_name (value);
1076   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1077   strcpy (nw, old);
1078   if (strlen (old) > 0)
1079     strcat (nw, " ");
1080   strcat (nw, escaped);
1081   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1082   GNUNET_free (old);
1083   GNUNET_free (nw);
1084   GNUNET_free (escaped);
1085   return GNUNET_OK;
1086 }
1087
1088
1089 /**
1090  * Remove a filename from a configuration value that
1091  * represents a list of filenames
1092  *
1093  * @param cfg configuration to update
1094  * @param section section of interest
1095  * @param option option of interest
1096  * @param value filename to remove
1097  * @return GNUNET_OK on success,
1098  *         GNUNET_NO if the filename is not in the list,
1099  *         GNUNET_SYSERR on error
1100  */
1101 int
1102 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1103                                             *cfg,
1104                                             const char *section,
1105                                             const char *option,
1106                                             const char *value)
1107 {
1108   char *list;
1109   char *pos;
1110   char *end;
1111   char *match;
1112   char old;
1113
1114   if (GNUNET_OK !=
1115       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1116     return GNUNET_NO;
1117   match = escape_name (value);
1118   pos = list;
1119   while (1)
1120     {
1121       while (pos[0] == ' ')
1122         pos++;
1123       if (strlen (pos) == 0)
1124         break;
1125       end = pos + 1;
1126       while ((end[0] != ' ') && (end[0] != '\0'))
1127         {
1128           if (end[0] == '\\')
1129             {
1130               switch (end[1])
1131                 {
1132                 case '\\':
1133                 case ' ':
1134                   end++;
1135                   break;
1136                 case '\0':
1137                   /* illegal, but just keep it */
1138                   break;
1139                 default:
1140                   /* illegal, but just ignore that there was a '/' */
1141                   break;
1142                 }
1143             }
1144           end++;
1145         }
1146       old = end[0];
1147       end[0] = '\0';
1148       if (0 == strcmp (pos, match))
1149         {
1150           if (old != '\0')
1151             memmove (pos, &end[1], strlen (&end[1]) + 1);
1152           else
1153             {
1154               if (pos != list) 
1155                 pos[-1] = '\0';
1156               else
1157                 pos[0] = '\0';
1158             }
1159           GNUNET_CONFIGURATION_set_value_string (cfg,
1160                                                  section, option, list);
1161           GNUNET_free (list);
1162           GNUNET_free (match);
1163           return GNUNET_OK;
1164         }        
1165       if (old == '\0')
1166         break;
1167       end[0] = old;
1168       pos = end + 1;
1169     }
1170   GNUNET_free (list);
1171   GNUNET_free (match);
1172   return GNUNET_NO;
1173 }
1174
1175
1176 /**
1177  * Load configuration (starts with defaults, then loads
1178  * system-specific configuration).
1179  *
1180  * @param cfg configuration to update
1181  * @param filename name of the configuration file, NULL to load defaults
1182  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1183  */
1184 int
1185 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1186                            const char *filename)
1187 {
1188   char *baseconfig;
1189   char *ipath;
1190
1191   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1192   if (ipath == NULL)
1193     return GNUNET_SYSERR;
1194   baseconfig = NULL;
1195   GNUNET_asprintf (&baseconfig,
1196                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
1197   GNUNET_free (ipath);
1198   if ((GNUNET_OK !=
1199        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
1200       (!((filename == NULL) ||
1201          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, filename)))))
1202     {
1203       GNUNET_free (baseconfig);
1204       return (filename == NULL) ? GNUNET_OK : GNUNET_SYSERR;
1205     }
1206   GNUNET_free (baseconfig);
1207   if ( ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg,
1208                                                         "PATHS",
1209                                                         "DEFAULTCONFIG"))) &&
1210        (filename != NULL) )
1211     GNUNET_CONFIGURATION_set_value_string (cfg,
1212                                            "PATHS",
1213                                            "DEFAULTCONFIG",
1214                                            filename);
1215   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
1216                                                       "TESTING",
1217                                                       "WEAKRANDOM")) &&
1218       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
1219                                                            "TESTING",
1220                                                            "WEAKRANDOM")))
1221     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1222   return GNUNET_OK;
1223 }
1224
1225
1226
1227 /* end of configuration.c */