LRN: Fix automake deps to allow -j* builds again
[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 values of a section in the configuration.
394  *
395  * @param cfg configuration to inspect
396  * @param section the section
397  * @param iter function to call on each option
398  * @param iter_cls closure for iter
399  */
400 void
401 GNUNET_CONFIGURATION_iterate_section_values (const struct GNUNET_CONFIGURATION_Handle *cfg,
402                               const char *section,
403                               GNUNET_CONFIGURATION_Iterator iter,
404                               void *iter_cls)
405 {
406   struct ConfigSection *spos;
407   struct ConfigEntry *epos;
408
409   spos = cfg->sections;
410   while ((spos != NULL) && (0 != strcmp (spos->name, section)))
411     spos = spos->next;
412
413   if (spos == NULL)
414     return;
415
416   epos = spos->entries;
417   while (epos != NULL)
418     {
419       iter (iter_cls, spos->name, epos->key, epos->val);
420       epos = epos->next;
421     }
422 }
423
424
425 /**
426  * Iterate over all sections in the configuration.
427  *
428  * @param cfg configuration to inspect
429  * @param iter function to call on each section
430  * @param iter_cls closure for iter
431  */
432 void
433 GNUNET_CONFIGURATION_iterate_sections (const struct GNUNET_CONFIGURATION_Handle *cfg,
434                                        GNUNET_CONFIGURATION_Section_Iterator iter,
435                                        void *iter_cls)
436 {
437   struct ConfigSection *spos;
438   struct ConfigSection *next;
439
440   next = cfg->sections; 
441   while (next != NULL)
442     {
443       spos = next;
444       next = spos->next;
445       iter (iter_cls, spos->name);
446     }
447 }
448
449 /**
450  * Remove the given section and all options in it.
451  *
452  * @param cfg configuration to inspect
453  * @param section name of the section to remove
454  */
455 void GNUNET_CONFIGURATION_remove_section (struct GNUNET_CONFIGURATION_Handle *cfg,
456                                           const char *section)
457 {
458   struct ConfigSection *spos;
459   struct ConfigSection *prev;
460   struct ConfigEntry *ent;
461
462   prev = NULL;
463   spos = cfg->sections; 
464   while (spos != NULL)   
465     {
466       if (0 == strcmp (section,
467                        spos->name))
468         {
469           if (prev == NULL)
470             cfg->sections = spos->next;
471           else
472             prev->next = spos->next;
473           while (NULL != (ent = spos->entries))
474             {
475               spos->entries = ent->next;
476               GNUNET_free (ent->key);
477               GNUNET_free_non_null (ent->val);
478               GNUNET_free (ent);
479               cfg->dirty = GNUNET_YES;
480             }
481           GNUNET_free (spos->name);
482           GNUNET_free (spos);
483           return;
484         }
485       prev = spos;
486       spos = spos->next;
487     }
488 }
489
490
491 /**
492  * Copy a configuration value to the given target configuration.
493  * Overwrites existing entries.
494  *
495  * @param cls the destination configuration (struct GNUNET_CONFIGURATION_Handle*)
496  * @param section section for the value
497  * @param option option name of the value
498  * @param value value to copy 
499  */
500 static void
501 copy_entry (void *cls,
502             const char *section, const char *option, const char *value)
503 {
504   struct GNUNET_CONFIGURATION_Handle *dst = cls;
505   GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
506 }
507
508
509 /**
510  * Duplicate an existing configuration object.
511  *
512  * @param cfg configuration to duplicate
513  * @return duplicate configuration
514  */
515 struct GNUNET_CONFIGURATION_Handle *
516 GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
517 {
518   struct GNUNET_CONFIGURATION_Handle *ret;
519
520   ret = GNUNET_CONFIGURATION_create ();
521   GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
522   return ret;
523 }
524
525
526 /**
527  * FIXME.
528  *
529  * @param cfg FIXME
530  * @param section FIXME
531  * @return matching entry, NULL if not found
532  */
533 static struct ConfigSection *
534 findSection (const struct GNUNET_CONFIGURATION_Handle *cfg,
535              const char *section)
536 {
537   struct ConfigSection *pos;
538
539   pos = cfg->sections;
540   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
541     pos = pos->next;
542   return pos;
543 }
544
545
546 /**
547  * Find an entry from a configuration.
548  *
549  * @param cfg handle to the configuration
550  * @param section section the option is in
551  * @param key the option
552  * @return matching entry, NULL if not found
553  */
554 static struct ConfigEntry *
555 findEntry (const struct GNUNET_CONFIGURATION_Handle *cfg,
556            const char *section, const char *key)
557 {
558   struct ConfigSection *sec;
559   struct ConfigEntry *pos;
560
561   sec = findSection (cfg, section);
562   if (sec == NULL)
563     return NULL;
564   pos = sec->entries;
565   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
566     pos = pos->next;
567   return pos;
568 }
569
570
571 /**
572  * A callback function, compares entries from two configurations
573  * (default against a new configuration) and write the diffs in a
574  * diff-configuration object (the callback object).
575  *
576  * @param cls the diff configuration (struct DiffHandle*)
577  * @param section section for the value (of the default conf.)
578  * @param option option name of the value (of the default conf.)
579  * @param value value to copy (of the default conf.)
580  */
581 static void
582 compareEntries (void *cls,
583                 const char *section, const char *option, const char *value)
584 {
585   struct DiffHandle *dh = cls;
586   struct ConfigEntry *entNew;
587  
588   entNew = findEntry (dh->cfgDefault, section, option);
589   if ( (entNew != NULL) &&
590        (strcmp (entNew->val, value) == 0) )
591     return;
592   GNUNET_CONFIGURATION_set_value_string (dh->cfgDiff,
593                                          section,
594                                          option,
595                                          value);
596 }
597
598
599 /**
600  * Write only configuration entries that have been changed to configuration file
601  * @param cfgDefault default configuration
602  * @param cfgNew new configuration
603  * @param filename where to write the configuration diff between default and new
604  * @return GNUNET_OK on success, GNUNET_SYSERR on error
605  */
606 int
607 GNUNET_CONFIGURATION_write_diffs (const struct GNUNET_CONFIGURATION_Handle
608                                   *cfgDefault,
609                                   const struct GNUNET_CONFIGURATION_Handle *cfgNew,
610                                   const char *filename)
611 {
612   int ret;
613   struct DiffHandle diffHandle;
614
615   diffHandle.cfgDiff = GNUNET_CONFIGURATION_create ();
616   diffHandle.cfgDefault = cfgDefault;
617   GNUNET_CONFIGURATION_iterate (cfgNew, compareEntries, &diffHandle);
618   ret = GNUNET_CONFIGURATION_write (diffHandle.cfgDiff, filename);
619   GNUNET_CONFIGURATION_destroy (diffHandle.cfgDiff);
620   return ret;
621 }
622
623
624 /**
625  * Set a configuration value that should be a string.
626  *
627  * @param cfg configuration to update
628  * @param section section of interest
629  * @param option option of interest
630  * @param value value to set
631  */
632 void
633 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle
634                                        *cfg,
635                                        const char *section,
636                                        const char *option, const char *value)
637 {
638   struct ConfigSection *sec;
639   struct ConfigEntry *e;
640
641   e = findEntry (cfg, section, option);
642   if (e != NULL)
643     {
644       GNUNET_free_non_null (e->val);
645       e->val = GNUNET_strdup (value);
646       return;
647     }
648   sec = findSection (cfg, section);
649   if (sec == NULL)
650     {
651       sec = GNUNET_malloc (sizeof (struct ConfigSection));
652       sec->name = GNUNET_strdup (section);
653       sec->next = cfg->sections;
654       cfg->sections = sec;
655     }
656   e = GNUNET_malloc (sizeof (struct ConfigEntry));
657   e->key = GNUNET_strdup (option);
658   e->val = GNUNET_strdup (value);
659   e->next = sec->entries;
660   sec->entries = e;
661 }
662
663
664 /**
665  * Set a configuration value that should be a number.
666  *
667  * @param cfg configuration to update
668  * @param section section of interest
669  * @param option option of interest
670  * @param number value to set
671  */
672 void
673 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle
674                                        *cfg, const char *section,
675                                        const char *option,
676                                        unsigned long long number)
677 {
678   char s[64];
679   GNUNET_snprintf (s, 64, "%llu", number);
680   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
681 }
682
683
684 /**
685  * Get a configuration value that should be a number.
686  *
687  * @param cfg configuration to inspect
688  * @param section section of interest
689  * @param option option of interest
690  * @param number where to store the numeric value of the option
691  * @return GNUNET_OK on success, GNUNET_SYSERR on error
692  */
693 int
694 GNUNET_CONFIGURATION_get_value_number (const struct
695                                        GNUNET_CONFIGURATION_Handle *cfg,
696                                        const char *section,
697                                        const char *option,
698                                        unsigned long long *number)
699 {
700   struct ConfigEntry *e;
701
702   e = findEntry (cfg, section, option);
703   if (e == NULL)
704     return GNUNET_SYSERR;
705   if (1 != SSCANF (e->val, "%llu", number))
706     return GNUNET_SYSERR;
707   return GNUNET_OK;
708 }
709
710
711 /**
712  * Get a configuration value that should be a relative time.
713  *
714  * @param cfg configuration to inspect
715  * @param section section of interest
716  * @param option option of interest
717  * @param time set to the time value stored in the configuration
718  * @return GNUNET_OK on success, GNUNET_SYSERR on error
719  */
720 int
721 GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle
722                                      *cfg, const char *section,
723                                      const char *option,
724                                      struct GNUNET_TIME_Relative *time)
725 {
726   struct ConfigEntry *e;
727   unsigned long long num;
728
729   e = findEntry (cfg, section, option);
730   if (e == NULL)
731     return GNUNET_SYSERR;
732   if ( (0 == strcasecmp (e->val, "infinity")) ||
733        (0 == strcasecmp (e->val, "forever")) )
734     {
735       *time = GNUNET_TIME_UNIT_FOREVER_REL;
736       return GNUNET_OK;
737     }
738   if (1 != SSCANF (e->val, "%llu", &num))
739     return GNUNET_SYSERR;
740   time->rel_value = (uint64_t) num;
741   return GNUNET_OK;
742 }
743
744
745 /**
746  * Get a configuration value that should be a string.
747  *
748  * @param cfg configuration to inspect
749  * @param section section of interest
750  * @param option option of interest
751  * @param value will be set to a freshly allocated configuration
752  *        value, or NULL if option is not specified
753  * @return GNUNET_OK on success, GNUNET_SYSERR on error
754  */
755 int
756 GNUNET_CONFIGURATION_get_value_string (const struct
757                                        GNUNET_CONFIGURATION_Handle *cfg,
758                                        const char *section,
759                                        const char *option, char **value)
760 {
761   struct ConfigEntry *e;
762
763   e = findEntry (cfg, section, option);
764   if ((e == NULL) || (e->val == NULL))
765     {
766       *value = NULL;
767       return GNUNET_SYSERR;
768     }
769   *value = GNUNET_strdup (e->val);
770   return GNUNET_OK;
771 }
772
773
774 /**
775  * Get a configuration value that should be in a set of
776  * predefined strings
777  *
778  * @param cfg configuration to inspect
779  * @param section section of interest
780  * @param option option of interest
781  * @param choices NULL-terminated list of legal values
782  * @param value will be set to an entry in the legal list,
783  *        or NULL if option is not specified and no default given
784  * @return GNUNET_OK on success, GNUNET_SYSERR on error
785  */
786 int
787 GNUNET_CONFIGURATION_get_value_choice (const struct
788                                        GNUNET_CONFIGURATION_Handle *cfg,
789                                        const char *section,
790                                        const char *option,
791                                        const char **choices,
792                                        const char **value)
793 {
794   struct ConfigEntry *e;
795   int i;
796
797   e = findEntry (cfg, section, option);
798   if (e == NULL)
799     return GNUNET_SYSERR;
800   i = 0;
801   while (choices[i] != NULL)
802     {
803       if (0 == strcasecmp (choices[i], e->val))
804         break;
805       i++;
806     }
807   if (choices[i] == NULL)
808     {
809       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
810                   _("Configuration value '%s' for '%s'"
811                     " in section '%s' is not in set of legal choices\n"),
812                   e->val, option, section);
813       return GNUNET_SYSERR;
814     }
815   *value = choices[i];
816   return GNUNET_OK;
817 }
818
819
820 /**
821  * Test if we have a value for a particular option
822  * @param cfg configuration to inspect
823  * @param section section of interest
824  * @param option option of interest
825  * @return GNUNET_YES if so, GNUNET_NO if not.
826  */
827 int
828 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle
829                                  *cfg, const char *section,
830                                  const char *option)
831 {
832   struct ConfigEntry *e;
833   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
834     return GNUNET_NO;
835   return GNUNET_YES;
836 }
837
838
839 /**
840  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
841  * where either in the "PATHS" section or the environtment
842  * "FOO" is set to "DIRECTORY".
843  *
844  * @param cfg configuration to use for path expansion
845  * @param orig string to $-expand (will be freed!)
846  * @return $-expanded string
847  */
848 char *
849 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle
850                                     *cfg, char *orig)
851 {
852   int i;
853   char *prefix;
854   char *result;
855   const char *post;
856   const char *env;
857
858   if (orig[0] != '$')
859     return orig;
860   i = 0;
861   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
862     i++;
863   if (orig[i] == '\0')
864     {
865       post = "";
866     }
867   else
868     {
869       orig[i] = '\0';
870       post = &orig[i + 1];
871     }
872   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg,
873                                                             "PATHS",
874                                                             &orig[1], &prefix))
875     {
876       if (NULL == (env = getenv (&orig[1])))
877         {
878           orig[i] = DIR_SEPARATOR;
879           return orig;
880         }
881       prefix = GNUNET_strdup (env);
882     }
883   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
884   strcpy (result, prefix);
885   if ((strlen (prefix) == 0) ||
886       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
887     strcat (result, DIR_SEPARATOR_STR);
888   strcat (result, post);
889   GNUNET_free (prefix);
890   GNUNET_free (orig);
891   return result;
892 }
893
894
895 /**
896  * Get a configuration value that should be a string.
897  *
898  * @param cfg configuration to inspect
899  * @param section section of interest
900  * @param option option of interest
901  * @param value will be set to a freshly allocated configuration
902  *        value, or NULL if option is not specified
903  * @return GNUNET_OK on success, GNUNET_SYSERR on error
904  */
905 int
906 GNUNET_CONFIGURATION_get_value_filename (const struct
907                                          GNUNET_CONFIGURATION_Handle *cfg,
908                                          const char *section,
909                                          const char *option, char **value)
910 {
911   char *tmp;
912
913   if (GNUNET_OK !=
914       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &tmp))
915     {
916       *value = NULL;
917       return GNUNET_SYSERR;
918     }
919   tmp = GNUNET_CONFIGURATION_expand_dollar (cfg, tmp);
920   *value = GNUNET_STRINGS_filename_expand (tmp);
921   GNUNET_free (tmp);
922   if (*value == NULL)
923     return GNUNET_SYSERR;
924   return GNUNET_OK;
925 }
926
927
928 /**
929  * Get a configuration value that should be in a set of
930  * "GNUNET_YES" or "GNUNET_NO".
931  *
932  * @param cfg configuration to inspect
933  * @param section section of interest
934  * @param option option of interest
935  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
936  */
937 int
938 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle
939                                       *cfg, const char *section,
940                                       const char *option)
941 {
942   static const char *yesno[] = { "YES", "NO", NULL };
943   const char *val;
944   int ret;
945
946   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
947                                                section, option, yesno, &val);
948   if (ret == GNUNET_SYSERR)
949     return ret;
950   if (val == yesno[0])
951     return GNUNET_YES;
952   return GNUNET_NO;
953 }
954
955
956 /**
957  * Iterate over the set of filenames stored in a configuration value.
958  *
959  * @param cfg configuration to inspect
960  * @param section section of interest
961  * @param option option of interest
962  * @param cb function to call on each filename
963  * @param cb_cls closure for cb
964  * @return number of filenames iterated over, -1 on error
965  */
966 int
967 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
968                                               GNUNET_CONFIGURATION_Handle
969                                               *cfg, const char *section,
970                                               const char *option,
971                                               GNUNET_FileNameCallback cb,
972                                               void *cb_cls)
973 {
974   char *list;
975   char *pos;
976   char *end;
977   char old;
978   int ret;
979
980   if (GNUNET_OK !=
981       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
982     return 0;
983   GNUNET_assert (list != NULL);
984   ret = 0;
985   pos = list;
986   while (1)
987     {
988       while (pos[0] == ' ')
989         pos++;
990       if (strlen (pos) == 0)
991         break;
992       end = pos + 1;
993       while ((end[0] != ' ') && (end[0] != '\0'))
994         {
995           if (end[0] == '\\')
996             {
997               switch (end[1])
998                 {
999                 case '\\':
1000                 case ' ':
1001                   memmove (end, &end[1], strlen (&end[1]) + 1);
1002                 case '\0':
1003                   /* illegal, but just keep it */
1004                   break;
1005                 default:
1006                   /* illegal, but just ignore that there was a '/' */
1007                   break;
1008                 }
1009             }
1010           end++;
1011         }
1012       old = end[0];
1013       end[0] = '\0';
1014       if (strlen (pos) > 0)
1015         {
1016           ret++;
1017           if ((cb != NULL) && (GNUNET_OK != cb (cb_cls, pos)))
1018             {
1019               ret = GNUNET_SYSERR;
1020               break;
1021             }
1022         }
1023       if (old == '\0')
1024         break;
1025       pos = end + 1;
1026     }
1027   GNUNET_free (list);
1028   return ret;
1029 }
1030
1031
1032 /**
1033  * FIXME.
1034  *
1035  * @param value FIXME
1036  * @return FIXME
1037  */
1038 static char *
1039 escape_name (const char *value)
1040 {
1041   char *escaped;
1042   const char *rpos;
1043   char *wpos;
1044
1045   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
1046   memset (escaped, 0, strlen (value) * 2 + 1);
1047   rpos = value;
1048   wpos = escaped;
1049   while (rpos[0] != '\0')
1050     {
1051       switch (rpos[0])
1052         {
1053         case '\\':
1054         case ' ':
1055           wpos[0] = '\\';
1056           wpos[1] = rpos[0];
1057           wpos += 2;
1058           break;
1059         default:
1060           wpos[0] = rpos[0];
1061           wpos++;
1062         }
1063       rpos++;
1064     }
1065   return escaped;
1066 }
1067
1068
1069 /**
1070  * FIXME.
1071  *
1072  * @param cls string we compare with (const char*)
1073  * @param fn filename we are currently looking at
1074  * @return GNUNET_OK if the names do not match, GNUNET_SYSERR if they do
1075  */
1076 static int
1077 test_match (void *cls, const char *fn)
1078 {
1079   const char *of = cls;
1080   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
1081 }
1082
1083
1084 /**
1085  * Append a filename to a configuration value that
1086  * represents a list of filenames
1087  *
1088  * @param cfg configuration to update
1089  * @param section section of interest
1090  * @param option option of interest
1091  * @param value filename to append
1092  * @return GNUNET_OK on success,
1093  *         GNUNET_NO if the filename already in the list
1094  *         GNUNET_SYSERR on error
1095  */
1096 int
1097 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
1098                                             *cfg,
1099                                             const char *section,
1100                                             const char *option,
1101                                             const char *value)
1102 {
1103   char *escaped;
1104   char *old;
1105   char *nw;
1106
1107   if (GNUNET_SYSERR
1108       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
1109                                                        section,
1110                                                        option,
1111                                                        &test_match,
1112                                                        (void *) value))
1113     return GNUNET_NO;           /* already exists */
1114   if (GNUNET_OK !=
1115       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
1116     old = GNUNET_strdup ("");
1117   escaped = escape_name (value);
1118   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
1119   strcpy (nw, old);
1120   if (strlen (old) > 0)
1121     strcat (nw, " ");
1122   strcat (nw, escaped);
1123   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
1124   GNUNET_free (old);
1125   GNUNET_free (nw);
1126   GNUNET_free (escaped);
1127   return GNUNET_OK;
1128 }
1129
1130
1131 /**
1132  * Remove a filename from a configuration value that
1133  * represents a list of filenames
1134  *
1135  * @param cfg configuration to update
1136  * @param section section of interest
1137  * @param option option of interest
1138  * @param value filename to remove
1139  * @return GNUNET_OK on success,
1140  *         GNUNET_NO if the filename is not in the list,
1141  *         GNUNET_SYSERR on error
1142  */
1143 int
1144 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
1145                                             *cfg,
1146                                             const char *section,
1147                                             const char *option,
1148                                             const char *value)
1149 {
1150   char *list;
1151   char *pos;
1152   char *end;
1153   char *match;
1154   char old;
1155
1156   if (GNUNET_OK !=
1157       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
1158     return GNUNET_NO;
1159   match = escape_name (value);
1160   pos = list;
1161   while (1)
1162     {
1163       while (pos[0] == ' ')
1164         pos++;
1165       if (strlen (pos) == 0)
1166         break;
1167       end = pos + 1;
1168       while ((end[0] != ' ') && (end[0] != '\0'))
1169         {
1170           if (end[0] == '\\')
1171             {
1172               switch (end[1])
1173                 {
1174                 case '\\':
1175                 case ' ':
1176                   end++;
1177                   break;
1178                 case '\0':
1179                   /* illegal, but just keep it */
1180                   break;
1181                 default:
1182                   /* illegal, but just ignore that there was a '/' */
1183                   break;
1184                 }
1185             }
1186           end++;
1187         }
1188       old = end[0];
1189       end[0] = '\0';
1190       if (0 == strcmp (pos, match))
1191         {
1192           if (old != '\0')
1193             memmove (pos, &end[1], strlen (&end[1]) + 1);
1194           else
1195             {
1196               if (pos != list) 
1197                 pos[-1] = '\0';
1198               else
1199                 pos[0] = '\0';
1200             }
1201           GNUNET_CONFIGURATION_set_value_string (cfg,
1202                                                  section, option, list);
1203           GNUNET_free (list);
1204           GNUNET_free (match);
1205           return GNUNET_OK;
1206         }        
1207       if (old == '\0')
1208         break;
1209       end[0] = old;
1210       pos = end + 1;
1211     }
1212   GNUNET_free (list);
1213   GNUNET_free (match);
1214   return GNUNET_NO;
1215 }
1216
1217
1218 /**
1219  * Load configuration (starts with defaults, then loads
1220  * system-specific configuration).
1221  *
1222  * @param cfg configuration to update
1223  * @param filename name of the configuration file, NULL to load defaults
1224  * @return GNUNET_OK on success, GNUNET_SYSERR on error
1225  */
1226 int
1227 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
1228                            const char *filename)
1229 {
1230   char *baseconfig;
1231   char *ipath;
1232
1233   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
1234   if (ipath == NULL)
1235     return GNUNET_SYSERR;
1236   baseconfig = NULL;
1237   GNUNET_asprintf (&baseconfig,
1238                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
1239   GNUNET_free (ipath);
1240   if ((GNUNET_OK !=
1241        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
1242       (!((filename == NULL) ||
1243          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, filename)))))
1244     {
1245       GNUNET_free (baseconfig);
1246       return (filename == NULL) ? GNUNET_OK : GNUNET_SYSERR;
1247     }
1248   GNUNET_free (baseconfig);
1249   if ( ((GNUNET_YES != GNUNET_CONFIGURATION_have_value (cfg,
1250                                                         "PATHS",
1251                                                         "DEFAULTCONFIG"))) &&
1252        (filename != NULL) )
1253     GNUNET_CONFIGURATION_set_value_string (cfg,
1254                                            "PATHS",
1255                                            "DEFAULTCONFIG",
1256                                            filename);
1257   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
1258                                                       "TESTING",
1259                                                       "WEAKRANDOM")) &&
1260       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
1261                                                            "TESTING",
1262                                                            "WEAKRANDOM")))
1263     GNUNET_CRYPTO_random_disable_entropy_gathering ();
1264   return GNUNET_OK;
1265 }
1266
1267
1268
1269 /* end of configuration.c */