undo
[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   struct ConfigEntry *e;
694   unsigned long long num;
695
696   e = findEntry (cfg, section, option);
697   if (e == NULL)
698     return GNUNET_SYSERR;
699   if ( (0 == strcasecmp (e->val, "infinity")) ||
700        (0 == strcasecmp (e->val, "forever")) )
701     {
702       *time = GNUNET_TIME_UNIT_FOREVER_REL;
703       return GNUNET_OK;
704     }
705   if (1 != SSCANF (e->val, "%llu", &num))
706     return GNUNET_SYSERR;
707   time->rel_value = (uint64_t) num;
708   return GNUNET_OK;
709 }
710
711
712 /**
713  * Get a configuration value that should be a string.
714  *
715  * @param cfg configuration to inspect
716  * @param section section of interest
717  * @param option option of interest
718  * @param value will be set to a freshly allocated configuration
719  *        value, or NULL if option is not specified
720  * @return GNUNET_OK on success, GNUNET_SYSERR on error
721  */
722 int
723 GNUNET_CONFIGURATION_get_value_string (const struct
724                                        GNUNET_CONFIGURATION_Handle *cfg,
725                                        const char *section,
726                                        const char *option, char **value)
727 {
728   struct ConfigEntry *e;
729
730   e = findEntry (cfg, section, option);
731   if ((e == NULL) || (e->val == NULL))
732     {
733       *value = NULL;
734       return GNUNET_SYSERR;
735     }
736   *value = GNUNET_strdup (e->val);
737   return GNUNET_OK;
738 }
739
740
741 /**
742  * Get a configuration value that should be in a set of
743  * predefined strings
744  *
745  * @param cfg configuration to inspect
746  * @param section section of interest
747  * @param option option of interest
748  * @param choices NULL-terminated list of legal values
749  * @param value will be set to an entry in the legal list,
750  *        or NULL if option is not specified and no default given
751  * @return GNUNET_OK on success, GNUNET_SYSERR on error
752  */
753 int
754 GNUNET_CONFIGURATION_get_value_choice (const struct
755                                        GNUNET_CONFIGURATION_Handle *cfg,
756                                        const char *section,
757                                        const char *option,
758                                        const char **choices,
759                                        const char **value)
760 {
761   struct ConfigEntry *e;
762   int i;
763
764   e = findEntry (cfg, section, option);
765   if (e == NULL)
766     return GNUNET_SYSERR;
767   i = 0;
768   while (choices[i] != NULL)
769     {
770       if (0 == strcasecmp (choices[i], e->val))
771         break;
772       i++;
773     }
774   if (choices[i] == NULL)
775     {
776       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
777                   _("Configuration value '%s' for '%s'"
778                     " in section '%s' is not in set of legal choices\n"),
779                   e->val, option, section);
780       return GNUNET_SYSERR;
781     }
782   *value = choices[i];
783   return GNUNET_OK;
784 }
785
786
787 /**
788  * Test if we have a value for a particular option
789  * @param cfg configuration to inspect
790  * @param section section of interest
791  * @param option option of interest
792  * @return GNUNET_YES if so, GNUNET_NO if not.
793  */
794 int
795 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle
796                                  *cfg, const char *section,
797                                  const char *option)
798 {
799   struct ConfigEntry *e;
800   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
801     return GNUNET_NO;
802   return GNUNET_YES;
803 }
804
805
806 /**
807  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
808  * where either in the "PATHS" section or the environtment
809  * "FOO" is set to "DIRECTORY".
810  *
811  * @param cfg configuration to use for path expansion
812  * @param orig string to $-expand (will be freed!)
813  * @return $-expanded string
814  */
815 char *
816 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
817                                     *cfg, char *orig)
818 {
819   int i;
820   char *prefix;
821   char *result;
822   const char *post;
823   const char *env;
824
825   if (orig[0] != '$')
826     return orig;
827   i = 0;
828   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
829     i++;
830   if (orig[i] == '\0')
831     {
832       post = "";
833     }
834   else
835     {
836       orig[i] = '\0';
837       post = &orig[i + 1];
838     }
839   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
840                                                             "PATHS",
841                                                             &orig[1], &prefix))
842     {
843       if (NULL == (env = getenv (&orig[1])))
844         {
845           orig[i] = DIR_SEPARATOR;
846           return orig;
847         }
848       prefix = GNUNET_strdup (env);
849     }
850   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
851   strcpy (result, prefix);
852   if ((strlen (prefix) == 0) ||
853       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
854     strcat (result, DIR_SEPARATOR_STR);
855   strcat (result, post);
856   GNUNET_free (prefix);
857   GNUNET_free (orig);
858   return result;
859 }
860
861
862 /**
863  * Get a configuration value that should be a string.
864  *
865  * @param cfg configuration to inspect
866  * @param section section of interest
867  * @param option option of interest
868  * @param value will be set to a freshly allocated configuration
869  *        value, or NULL if option is not specified
870  * @return GNUNET_OK on success, GNUNET_SYSERR on error
871  */
872 int
873 GNUNET_CONFIGURATION_get_value_filename (const struct
874                                          GNUNET_CONFIGURATION_Handle *cfg,
875                                          const char *section,
876                                          const char *option, char **value)
877 {
878   char *tmp;
879
880   if (GNUNET_OK !=
881       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
882     {
883       *value = NULL;
884       return GNUNET_SYSERR;
885     }
886   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
887   *value = GNUNET_STRINGS_filename_expand (tmp);
888   GNUNET_free (tmp);
889   if (*value == NULL)
890     return GNUNET_SYSERR;
891   return GNUNET_OK;
892 }
893
894
895 /**
896  * Get a configuration value that should be in a set of
897  * "GNUNET_YES" or "GNUNET_NO".
898  *
899  * @param cfg configuration to inspect
900  * @param section section of interest
901  * @param option option of interest
902  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
903  */
904 int
905 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
906                                       *cfg, const char *section,
907                                       const char *option)
908 {
909   static const char *yesno[] = { "YES", "NO", NULL };
910   const char *val;
911   int ret;
912
913   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
914                                                section, option, yesno, &val);
915   if (ret == GNUNET_SYSERR)
916     return ret;
917   if (val == yesno[0])
918     return GNUNET_YES;
919   return GNUNET_NO;
920 }
921
922
923 /**
924  * Iterate over the set of filenames stored in a configuration value.
925  *
926  * @param cfg configuration to inspect
927  * @param section section of interest
928  * @param option option of interest
929  * @param cb function to call on each filename
930  * @param cb_cls closure for cb
931  * @return number of filenames iterated over, -1 on error
932  */
933 int
934 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
935                                               GNUNET_CONFIGURATION_Handle
936                                               *cfg, const char *section,
937                                               const char *option,
938                                               GNUNET_FileNameCallback cb,
939                                               void *cb_cls)
940 {
941   char *list;
942   char *pos;
943   char *end;
944   char old;
945   int ret;
946
947   if (GNUNET_OK !=
948       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
949     return 0;
950   GNUNET_assert (list != NULL);
951   ret = 0;
952   pos = list;
953   while (1)
954     {
955       while (pos[0] == ' ')
956         pos++;
957       if (strlen (pos) == 0)
958         break;
959       end = pos + 1;
960       while ((end[0] != ' ') && (end[0] != '\0'))
961         {
962           if (end[0] == '\\')
963             {
964               switch (end[1])
965                 {
966                 case '\\':
967                 case ' ':
968                   memmove (end, &end[1], strlen (&end[1]) + 1);
969                 case '\0':
970                   /* illegal, but just keep it */
971                   break;
972                 default:
973                   /* illegal, but just ignore that there was a '/' */
974                   break;
975                 }
976             }
977           end++;
978         }
979       old = end[0];
980       end[0] = '\0';
981       if (strlen (pos) > 0)
982         {
983           ret++;
984           if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
985             {
986               ret = GNUNET_SYSERR;
987               break;
988             }
989         }
990       if (old == '\0')
991         break;
992       pos = end + 1;
993     }
994   GNUNET_free (list);
995   return ret;
996 }
997
998
999 /**
1000  * FIXME.
1001  *
1002  * @param value FIXME
1003  * @return FIXME
1004  */
1005 static char *
1006 escape_name (const char *value)
1007 {
1008   char *escaped;
1009   const char *rpos;
1010   char *wpos;
1011
1012   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1013   memset (escaped, 0, strlen (value) * 2 + 1);
1014   rpos = value;
1015   wpos = escaped;
1016   while (rpos[0] != '\0')
1017     {
1018       switch (rpos[0])
1019         {
1020         case '\\':
1021         case ' ':
1022           wpos[0] = '\\';
1023           wpos[1] = rpos[0];
1024           wpos += 2;
1025           break;
1026         default:
1027           wpos[0] = rpos[0];
1028           wpos++;
1029         }
1030       rpos++;
1031     }
1032   return escaped;
1033 }
1034
1035
1036 /**
1037  * FIXME.
1038  *
1039  * @param cls string we compare with (const char*)
1040  * @param fn filename we are currently looking at
1041  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1042  */
1043 static int
1044 test_match (void *cls, const char *fn)
1045 {
1046   const char *of = cls;
1047   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1048 }
1049
1050
1051 /**
1052  * Append a filename to a configuration value that
1053  * represents a list of filenames
1054  *
1055  * @param cfg configuration to update
1056  * @param section section of interest
1057  * @param option option of interest
1058  * @param value filename to append
1059  * @return GNUNET_OK on success,
1060  *         GNUNET_NO if the filename already in the list
1061  *         GNUNET_SYSERR on error
1062  */
1063 int
1064 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1065                                             *cfg,
1066                                             const char *section,
1067                                             const char *option,
1068                                             const char *value)
1069 {
1070   char *escaped;
1071   char *old;
1072   char *nw;
1073
1074   if (GNUNET_SYSERR
1075       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
1076                                                        section,
1077                                                        option,
1078                                                        &test_match,
1079                                                        (void *) value))
1080     return GNUNET_NO;           /* already exists */
1081   if (GNUNET_OK !=
1082       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1083     old = GNUNET_strdup ("");
1084   escaped = escape_name (value);
1085   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1086   strcpy (nw, old);
1087   if (strlen (old) > 0)
1088     strcat (nw, " ");
1089   strcat (nw, escaped);
1090   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1091   GNUNET_free (old);
1092   GNUNET_free (nw);
1093   GNUNET_free (escaped);
1094   return GNUNET_OK;
1095 }
1096
1097
1098 /**
1099  * Remove a filename from a configuration value that
1100  * represents a list of filenames
1101  *
1102  * @param cfg configuration to update
1103  * @param section section of interest
1104  * @param option option of interest
1105  * @param value filename to remove
1106  * @return GNUNET_OK on success,
1107  *         GNUNET_NO if the filename is not in the list,
1108  *         GNUNET_SYSERR on error
1109  */
1110 int
1111 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1112                                             *cfg,
1113                                             const char *section,
1114                                             const char *option,
1115                                             const char *value)
1116 {
1117   char *list;
1118   char *pos;
1119   char *end;
1120   char *match;
1121   char old;
1122
1123   if (GNUNET_OK !=
1124       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1125     return GNUNET_NO;
1126   match = escape_name (value);
1127   pos = list;
1128   while (1)
1129     {
1130       while (pos[0] == ' ')
1131         pos++;
1132       if (strlen (pos) == 0)
1133         break;
1134       end = pos + 1;
1135       while ((end[0] != ' ') && (end[0] != '\0'))
1136         {
1137           if (end[0] == '\\')
1138             {
1139               switch (end[1])
1140                 {
1141                 case '\\':
1142                 case ' ':
1143                   end++;
1144                   break;
1145                 case '\0':
1146                   /* illegal, but just keep it */
1147                   break;
1148                 default:
1149                   /* illegal, but just ignore that there was a '/' */
1150                   break;
1151                 }
1152             }
1153           end++;
1154         }
1155       old = end[0];
1156       end[0] = '\0';
1157       if (0 == strcmp (pos, match))
1158         {
1159           if (old != '\0')
1160             memmove (pos, &end[1], strlen (&end[1]) + 1);
1161           else
1162             {
1163               if (pos != list) 
1164                 pos[-1] = '\0';
1165               else
1166                 pos[0] = '\0';
1167             }
1168           GNUNET_CONFIGURATION_set_value_string (cfg,
1169                                                  section, option, list);
1170           GNUNET_free (list);
1171           GNUNET_free (match);
1172           return GNUNET_OK;
1173         }        
1174       if (old == '\0')
1175         break;
1176       end[0] = old;
1177       pos = end + 1;
1178     }
1179   GNUNET_free (list);
1180   GNUNET_free (match);
1181   return GNUNET_NO;
1182 }
1183
1184
1185 /**
1186  * Load configuration (starts with defaults, then loads
1187  * system-specific configuration).
1188  *
1189  * @param cfg configuration to update
1190  * @param filename name of the configuration file, NULL to load defaults
1191  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1192  */
1193 int
1194 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1195                            const char *filename)
1196 {
1197   char *baseconfig;
1198   char *ipath;
1199
1200   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1201   if (ipath == NULL)
1202     return GNUNET_SYSERR;
1203   baseconfig = NULL;
1204   GNUNET_asprintf (&baseconfig,
1205                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
1206   GNUNET_free (ipath);
1207   if ((GNUNET_OK !=
1208        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
1209       (!((filename == NULL) ||
1210          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, filename)))))
1211     {
1212       GNUNET_free (baseconfig);
1213       return (filename == NULL) ? GNUNET_OK : GNUNET_SYSERR;
1214     }
1215   GNUNET_free (baseconfig);
1216   if ( ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg,
1217                                                         "PATHS",
1218                                                         "DEFAULTCONFIG"))) &&
1219        (filename != NULL) )
1220     GNUNET_CONFIGURATION_set_value_string (cfg,
1221                                            "PATHS",
1222                                            "DEFAULTCONFIG",
1223                                            filename);
1224   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
1225                                                       "TESTING",
1226                                                       "WEAKRANDOM")) &&
1227       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
1228                                                            "TESTING",
1229                                                            "WEAKRANDOM")))
1230     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1231   return GNUNET_OK;
1232 }
1233
1234
1235
1236 /* end of configuration.c */