0ce672dd9bb16ba8397e683be7d7d764c194656f
[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  * @brief configuration entry
38  */
39 struct ConfigEntry
40 {
41
42   /**
43    * This is a linked list.
44    */
45   struct ConfigEntry *next;
46
47   /**
48    * key for this entry
49    */
50   char *key;
51
52   /**
53    * current, commited value
54    */
55   char *val;
56 };
57
58 /**
59  * @brief configuration section
60  */
61 struct ConfigSection
62 {
63   /**
64    * This is a linked list.
65    */
66   struct ConfigSection *next;
67
68   /**
69    * entries in the section
70    */
71   struct ConfigEntry *entries;
72
73   /**
74    * name of the section
75    */
76   char *name;
77 };
78
79 /**
80  * @brief configuration data
81  */
82 struct GNUNET_CONFIGURATION_Handle
83 {
84   /**
85    * Configuration sections.
86    */
87   struct ConfigSection *sections;
88
89   /**
90    * Modification indication since last save
91    * GNUNET_NO if clean, GNUNET_YES if dirty,
92    * GNUNET_SYSERR on error (i.e. last save failed)
93    */
94   int dirty;
95
96 };
97
98 /**
99  * Create a GNUNET_CONFIGURATION_Configuration.
100  */
101 struct GNUNET_CONFIGURATION_Handle *
102 GNUNET_CONFIGURATION_create ()
103 {
104   return GNUNET_malloc (sizeof (struct GNUNET_CONFIGURATION_Handle));
105 }
106
107 void
108 GNUNET_CONFIGURATION_destroy (struct GNUNET_CONFIGURATION_Handle *cfg)
109 {
110   struct ConfigSection *sec;
111   struct ConfigEntry *ent;
112
113   while (NULL != (sec = cfg->sections))
114     {
115       cfg->sections = sec->next;
116       while (NULL != (ent = sec->entries))
117         {
118           sec->entries = ent->next;
119           GNUNET_free (ent->key);
120           GNUNET_free_non_null (ent->val);
121           GNUNET_free (ent);
122         }
123       GNUNET_free (sec->name);
124       GNUNET_free (sec);
125     }
126   GNUNET_free (cfg);
127 }
128
129 int
130 GNUNET_CONFIGURATION_parse (struct GNUNET_CONFIGURATION_Handle *cfg,
131                             const char *filename)
132 {
133   int dirty;
134   char line[256];
135   char tag[64];
136   char value[192];
137   FILE *fp;
138   unsigned int nr;
139   int i;
140   int emptyline;
141   int ret;
142   char *section;
143   char *fn;
144
145   fn = GNUNET_STRINGS_filename_expand (filename);
146   dirty = cfg->dirty;           /* back up value! */
147   if (NULL == (fp = FOPEN (fn, "r")))
148     {
149       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
150       GNUNET_free (fn);
151       return GNUNET_SYSERR;
152     }
153   GNUNET_free (fn);
154   ret = GNUNET_OK;
155   section = GNUNET_strdup ("");
156   memset (line, 0, 256);
157   nr = 0;
158   while (NULL != fgets (line, 255, fp))
159     {
160       nr++;
161       for (i = 0; i < 255; i++)
162         if (line[i] == '\t')
163           line[i] = ' ';
164       if (line[0] == '\n' || line[0] == '#' || line[0] == '%' ||
165           line[0] == '\r')
166         continue;
167       emptyline = 1;
168       for (i = 0; (i < 255 && line[i] != 0); i++)
169         if (line[i] != ' ' && line[i] != '\n' && line[i] != '\r')
170           emptyline = 0;
171       if (emptyline == 1)
172         continue;
173       /* remove tailing whitespace */
174       for (i = strlen (line) - 1; (i >= 0) && (isspace (line[i])); i--)
175         line[i] = '\0';
176       if (1 == sscanf (line, "@INLINE@ %191[^\n]", value))
177         {
178           /* @INLINE@ value */
179           if (0 != GNUNET_CONFIGURATION_parse (cfg, value))
180             ret = GNUNET_SYSERR;        /* failed to parse included config */
181         }
182       else if (1 == sscanf (line, "[%99[^]]]", value))
183         {
184           /* [value] */
185           GNUNET_free (section);
186           section = GNUNET_strdup (value);
187         }
188       else if (2 == sscanf (line, " %63[^= ] = %191[^\n]", tag, value))
189         {
190           /* tag = value */
191           /* Strip LF */
192           i = strlen (value) - 1;
193           while ((i >= 0) && (isspace (value[i])))
194             value[i--] = '\0';
195           /* remove quotes */
196           i = 0;
197           if (value[0] == '"')
198             {
199               i = 1;
200               while ((value[i] != '\0') && (value[i] != '"'))
201                 i++;
202               if (value[i] == '"')
203                 {
204                   value[i] = '\0';
205                   i = 1;
206                 }
207               else
208                 i = 0;
209             }
210           GNUNET_CONFIGURATION_set_value_string (cfg,
211                                                  section, tag, &value[i]);
212         }
213       else if (1 == sscanf (line, " %63[^= ] =[^\n]", tag))
214         {
215           /* tag = */
216           GNUNET_CONFIGURATION_set_value_string (cfg, section, tag, "");
217         }
218       else
219         {
220           /* parse error */
221           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
222                       _
223                       ("Syntax error in configuration file `%s' at line %u.\n"),
224                       filename, nr);
225           ret = GNUNET_SYSERR;
226           break;
227         }
228     }
229   GNUNET_assert (0 == fclose (fp));
230   /* restore dirty flag - anything we set in the meantime
231      came from disk */
232   cfg->dirty = dirty;
233   GNUNET_free (section);
234   return ret;
235 }
236
237 int
238 GNUNET_CONFIGURATION_test_dirty (const struct GNUNET_CONFIGURATION_Handle *cfg)
239 {
240   return cfg->dirty;
241 }
242
243 int
244 GNUNET_CONFIGURATION_write (struct GNUNET_CONFIGURATION_Handle *data,
245                             const char *filename)
246 {
247   struct ConfigSection *sec;
248   struct ConfigEntry *ent;
249   FILE *fp;
250   int error;
251   char *fn;
252   char *val;
253   char *pos;
254
255   fn = GNUNET_STRINGS_filename_expand (filename);
256   GNUNET_DISK_directory_create_for_file (fn);
257   if (NULL == (fp = FOPEN (fn, "w")))
258     {
259       GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fopen", fn);
260       GNUNET_free (fn);
261       return GNUNET_SYSERR;
262     }
263   GNUNET_free (fn);
264   error = 0;
265   sec = data->sections;
266   while (sec != NULL)
267     {
268       if (0 > fprintf (fp, "[%s]\n", sec->name))
269         {
270           error = 1;
271           break;
272         }
273       ent = sec->entries;
274       while (ent != NULL)
275         {
276           if (ent->val != NULL)
277             {
278               val = GNUNET_malloc (strlen (ent->val) * 2 + 1);
279               strcpy (val, ent->val);
280               while (NULL != (pos = strstr (val, "\n")))
281                 {
282                   memmove (&pos[2], &pos[1], strlen (&pos[1]));
283                   pos[0] = '\\';
284                   pos[1] = 'n';
285                 }
286               if (0 > fprintf (fp, "%s = %s\n", ent->key, val))
287                 {
288                   error = 1;
289                   GNUNET_free (val);
290                   break;
291                 }
292               GNUNET_free (val);
293             }
294           ent = ent->next;
295         }
296       if (error != 0)
297         break;
298       if (0 > fprintf (fp, "\n"))
299         {
300           error = 1;
301           break;
302         }
303       sec = sec->next;
304     }
305   if (error != 0)
306     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "fprintf", filename);
307   GNUNET_assert (0 == fclose (fp));
308   if (error != 0)
309     {
310       data->dirty = GNUNET_SYSERR;      /* last write failed */
311       return GNUNET_SYSERR;
312     }
313   data->dirty = GNUNET_NO;      /* last write succeeded */
314   return GNUNET_OK;
315 }
316
317
318 void GNUNET_CONFIGURATION_iterate (const struct GNUNET_CONFIGURATION_Handle *cfg,
319                                    GNUNET_CONFIGURATION_Iterator iter,
320                                    void *iter_cls)
321 {
322   struct ConfigSection *spos;
323   struct ConfigEntry *epos;
324
325   spos = cfg->sections;
326   while (spos != NULL)
327     {
328       epos = spos->entries;
329       while (epos != NULL)
330         {
331           iter (iter_cls, spos->name, epos->key, epos->val);
332           epos = epos->next;
333         }
334       spos = spos->next;
335     }
336 }
337
338
339 static void
340 copy_entry (void *cls,
341             const char *section,
342             const char *option,
343             const char *value)
344 {
345   struct GNUNET_CONFIGURATION_Handle *dst = cls;
346   GNUNET_CONFIGURATION_set_value_string (dst, section, option, value);
347 }
348
349
350 struct GNUNET_CONFIGURATION_Handle *
351 GNUNET_CONFIGURATION_dup (const struct GNUNET_CONFIGURATION_Handle *cfg)
352 {
353   struct GNUNET_CONFIGURATION_Handle *ret;
354
355   ret = GNUNET_CONFIGURATION_create ();
356   GNUNET_CONFIGURATION_iterate (cfg, &copy_entry, ret);
357   return ret;
358 }
359
360
361 static struct ConfigSection *
362 findSection (const struct GNUNET_CONFIGURATION_Handle *data, const char *section)
363 {
364   struct ConfigSection *pos;
365
366   pos = data->sections;
367   while ((pos != NULL) && (0 != strcasecmp (section, pos->name)))
368     pos = pos->next;
369   return pos;
370 }
371
372
373 static struct ConfigEntry *
374 findEntry (const struct GNUNET_CONFIGURATION_Handle *data,
375            const char *section, const char *key)
376 {
377   struct ConfigSection *sec;
378   struct ConfigEntry *pos;
379
380   sec = findSection (data, section);
381   if (sec == NULL)
382     return NULL;
383   pos = sec->entries;
384   while ((pos != NULL) && (0 != strcasecmp (key, pos->key)))
385     pos = pos->next;
386   return pos;
387 }
388
389 void
390 GNUNET_CONFIGURATION_set_value_string (struct GNUNET_CONFIGURATION_Handle
391                                        *data,
392                                        const char *section,
393                                        const char *option, const char *value)
394 {
395   struct ConfigSection *sec;
396   struct ConfigEntry *e;
397
398   e = findEntry (data, section, option);
399   if (e != NULL)
400     {
401       GNUNET_free_non_null (e->val);
402       e->val = GNUNET_strdup (value);
403       return;
404     }
405   sec = findSection (data, section);
406   if (sec == NULL)
407     {
408       sec = GNUNET_malloc (sizeof (struct ConfigSection));
409       sec->name = GNUNET_strdup (section);
410       sec->next = data->sections;
411       data->sections = sec;
412     }
413   e = GNUNET_malloc (sizeof (struct ConfigEntry));
414   e->key = GNUNET_strdup (option);
415   e->val = GNUNET_strdup (value);
416   e->next = sec->entries;
417   sec->entries = e;
418 }
419
420 void
421 GNUNET_CONFIGURATION_set_value_number (struct GNUNET_CONFIGURATION_Handle
422                                        *cfg, const char *section,
423                                        const char *option,
424                                        unsigned long long number)
425 {
426   char s[64];
427   GNUNET_snprintf (s, 64, "%llu", number);
428   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, s);
429 }
430
431 int
432 GNUNET_CONFIGURATION_get_value_number (const struct GNUNET_CONFIGURATION_Handle
433                                        *cfg, const char *section,
434                                        const char *option,
435                                        unsigned long long *number)
436 {
437   struct ConfigEntry *e;
438
439   e = findEntry (cfg, section, option);
440   if (e == NULL)
441     return GNUNET_SYSERR;
442   if (1 != SSCANF (e->val, "%llu", number))
443     return GNUNET_SYSERR;
444   return GNUNET_OK;
445 }
446
447 int
448 GNUNET_CONFIGURATION_get_value_time (const struct GNUNET_CONFIGURATION_Handle
449                                      *cfg, const char *section,
450                                      const char *option,
451                                      struct GNUNET_TIME_Relative *time)
452 {
453   unsigned long long num;
454   int ret;
455
456   ret = GNUNET_CONFIGURATION_get_value_number (cfg,
457                                                section,
458                                                option,
459                                                &num);
460   if (ret == GNUNET_OK)
461     time->value = (uint64_t) num;
462   return ret;
463 }
464
465 int
466 GNUNET_CONFIGURATION_get_value_string (const struct GNUNET_CONFIGURATION_Handle
467                                        *cfg, const char *section,
468                                        const char *option, char **value)
469 {
470   struct ConfigEntry *e;
471
472   e = findEntry (cfg, section, option);
473   if ((e == NULL) || (e->val == NULL))
474     {
475       *value = NULL;
476       return GNUNET_SYSERR;
477     }
478   *value = GNUNET_strdup (e->val);
479   return GNUNET_OK;
480 }
481
482 int
483 GNUNET_CONFIGURATION_get_value_choice (const struct GNUNET_CONFIGURATION_Handle
484                                        *cfg, const char *section,
485                                        const char *option,
486                                        const char **choices,
487                                        const char **value)
488 {
489   struct ConfigEntry *e;
490   int i;
491
492   e = findEntry (cfg, section, option);
493   if (e == NULL)
494     return GNUNET_SYSERR;
495   i = 0;
496   while (choices[i] != NULL)
497     {
498       if (0 == strcasecmp (choices[i], e->val))
499         break;
500       i++;
501     }
502   if (choices[i] == NULL)
503     {
504       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
505                   _("Configuration value '%s' for '%s'"
506                     " in section '%s' is not in set of legal choices\n"),
507                   e->val, option, section);
508       return GNUNET_SYSERR;
509     }
510   *value = choices[i];
511   return GNUNET_OK;
512 }
513
514 /**
515  * Test if we have a value for a particular option
516  * @return GNUNET_YES if so, GNUNET_NO if not.
517  */
518 int
519 GNUNET_CONFIGURATION_have_value (const struct GNUNET_CONFIGURATION_Handle *cfg,
520                                  const char *section, const char *option)
521 {
522   struct ConfigEntry *e;
523   if ((NULL == (e = findEntry (cfg, section, option))) || (e->val == NULL))
524     return GNUNET_NO;
525   return GNUNET_YES;
526 }
527
528 /**
529  * Expand an expression of the form "$FOO/BAR" to "DIRECTORY/BAR"
530  * where either in the "PATHS" section or the environtment
531  * "FOO" is set to "DIRECTORY".
532  *
533  * @param old string to $-expand (will be freed!)
534  * @return $-expanded string
535  */
536 char *
537 GNUNET_CONFIGURATION_expand_dollar (const struct GNUNET_CONFIGURATION_Handle *cfg,
538                                     char *orig)
539 {
540   int i;
541   char *prefix;
542   char *result;
543   const char *post;
544   const char *env;
545
546   if (orig[0] != '$')
547     return orig;
548   i = 0;
549   while ((orig[i] != '/') && (orig[i] != '\\') && (orig[i] != '\0'))
550     i++;
551   if (orig[i] == '\0')
552     {
553       post = "";
554     }
555   else
556     {
557       orig[i] = '\0';
558       post = &orig[i + 1];
559     }
560   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg,
561                                                           "PATHS",
562                                                           &orig[1], &prefix))
563     {
564       if (NULL == (env = getenv (&orig[1])))
565         {
566           orig[i] = DIR_SEPARATOR;
567           return orig;
568         }
569       prefix = GNUNET_strdup (env);
570     }
571   result = GNUNET_malloc (strlen (prefix) + strlen (post) + 2);
572   strcpy (result, prefix);
573   if ((strlen (prefix) == 0) ||
574       ((prefix[strlen (prefix) - 1] != DIR_SEPARATOR) && (strlen (post) > 0)))
575     strcat (result, DIR_SEPARATOR_STR);
576   strcat (result, post);
577   GNUNET_free (prefix);
578   GNUNET_free (orig);
579   return result;
580 }
581
582 /**
583  * Get a configuration value that should be a string.
584  * @param value will be set to a freshly allocated configuration
585  *        value, or NULL if option is not specified
586  * @return GNUNET_OK on success, GNUNET_SYSERR on error
587  */
588 int
589 GNUNET_CONFIGURATION_get_value_filename (const struct GNUNET_CONFIGURATION_Handle
590                                          *data, const char *section,
591                                          const char *option, char **value)
592 {
593   int ret;
594   char *tmp;
595
596   tmp = NULL;
597   ret = GNUNET_CONFIGURATION_get_value_string (data, section, option, &tmp);
598   if (ret == GNUNET_SYSERR)
599     return ret;
600   if (tmp != NULL)
601     {
602       tmp = GNUNET_CONFIGURATION_expand_dollar (data, tmp);
603       *value = GNUNET_STRINGS_filename_expand (tmp);
604       GNUNET_free (tmp);
605       if (*value == NULL)
606         ret = GNUNET_SYSERR;
607     }
608   else
609     {
610       *value = NULL;
611     }
612   return ret;
613 }
614
615 /**
616  * Get a configuration value that should be in a set of
617  * "GNUNET_YES" or "GNUNET_NO".
618  *
619  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
620  */
621 int
622 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg,
623                                       const char *section, const char *option)
624 {
625   static const char *yesno[] = { "YES", "NO", NULL };
626   const char *val;
627   int ret;
628
629   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
630                                                section, option, yesno, &val);
631   if (ret == GNUNET_SYSERR)
632     return ret;
633   if (val == yesno[0])
634     return GNUNET_YES;
635   return GNUNET_NO;
636 }
637
638
639 /**
640  * Iterate over the set of filenames stored in a configuration value.
641  *
642  * @return number of filenames iterated over, -1 on error
643  */
644 int
645 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
646                                               GNUNET_CONFIGURATION_Handle
647                                               *cfg, const char *section,
648                                               const char *option,
649                                               GNUNET_FileNameCallback cb,
650                                               void *cls)
651 {
652   char *list;
653   char *pos;
654   char *end;
655   char old;
656   int ret;
657
658   if (GNUNET_OK !=
659       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
660     return 0;
661   GNUNET_assert (list != NULL);
662   ret = 0;
663   pos = list;
664   while (1)
665     {
666       while (pos[0] == ' ')
667         pos++;
668       if (strlen (pos) == 0)
669         break;
670       end = pos + 1;
671       while ((end[0] != ' ') && (end[0] != '\0'))
672         {
673           if (end[0] == '\\')
674             {
675               switch (end[1])
676                 {
677                 case '\\':
678                 case ' ':
679                   memmove (end, &end[1], strlen (&end[1]) + 1);
680                 case '\0':
681                   /* illegal, but just keep it */
682                   break;
683                 default:
684                   /* illegal, but just ignore that there was a '/' */
685                   break;
686                 }
687             }
688           end++;
689         }
690       old = end[0];
691       end[0] = '\0';
692       if (strlen (pos) > 0)
693         {
694           ret++;
695           if ((cb != NULL) && (GNUNET_OK != cb (cls, pos)))
696             {
697               ret = GNUNET_SYSERR;
698               break;
699             }
700         }
701       if (old == '\0')
702         break;
703       pos = end + 1;
704     }
705   GNUNET_free (list);
706   return ret;
707 }
708
709 static char *
710 escape_name (const char *value)
711 {
712   char *escaped;
713   const char *rpos;
714   char *wpos;
715
716   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
717   memset (escaped, 0, strlen (value) * 2 + 1);
718   rpos = value;
719   wpos = escaped;
720   while (rpos[0] != '\0')
721     {
722       switch (rpos[0])
723         {
724         case '\\':
725         case ' ':
726           wpos[0] = '\\';
727           wpos[1] = rpos[0];
728           wpos += 2;
729           break;
730         default:
731           wpos[0] = rpos[0];
732           wpos++;
733         }
734       rpos++;
735     }
736   return escaped;
737 }
738
739 static int
740 test_match (void *cls, const char *fn)
741 {
742   const char *of = cls;
743   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
744 }
745
746 /**
747  * Append a filename to a configuration value that
748  * represents a list of filenames
749  *
750  * @param value filename to append
751  * @return GNUNET_OK on success,
752  *         GNUNET_NO if the filename already in the list
753  *         GNUNET_SYSERR on error
754  */
755 int
756 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
757                                             *cfg,
758                                             const char *section,
759                                             const char *option,
760                                             const char *value)
761 {
762   char *escaped;
763   char *old;
764   char *nw;
765
766   if (GNUNET_SYSERR
767       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
768                                                        section,
769                                                        option,
770                                                        &test_match,
771                                                        (void *) value))
772     return GNUNET_NO;           /* already exists */
773   if (GNUNET_OK !=
774       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
775     old = GNUNET_strdup ("");
776   escaped = escape_name (value);
777   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
778   strcpy (nw, old);
779   strcat (nw, " ");
780   strcat (nw, escaped);
781   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
782   GNUNET_free (old);
783   GNUNET_free (nw);
784   GNUNET_free (escaped);
785   return GNUNET_OK;
786 }
787
788
789 /**
790  * Remove a filename from a configuration value that
791  * represents a list of filenames
792  *
793  * @param value filename to remove
794  * @return GNUNET_OK on success,
795  *         GNUNET_NO if the filename is not in the list,
796  *         GNUNET_SYSERR on error
797  */
798 int
799 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
800                                             *cfg,
801                                             const char *section,
802                                             const char *option,
803                                             const char *value)
804 {
805   char *list;
806   char *pos;
807   char *end;
808   char *match;
809   char old;
810   int ret;
811
812   if (GNUNET_OK !=
813       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
814     return GNUNET_NO;
815   match = escape_name (value);
816   ret = 0;
817   pos = list;
818   while (1)
819     {
820       while (pos[0] == ' ')
821         pos++;
822       if (strlen (pos) == 0)
823         break;
824       end = pos + 1;
825       while ((end[0] != ' ') && (end[0] != '\0'))
826         {
827           if (end[0] == '\\')
828             {
829               switch (end[1])
830                 {
831                 case '\\':
832                 case ' ':
833                   end++;
834                   break;
835                 case '\0':
836                   /* illegal, but just keep it */
837                   break;
838                 default:
839                   /* illegal, but just ignore that there was a '/' */
840                   break;
841                 }
842             }
843           end++;
844         }
845       old = end[0];
846       end[0] = '\0';
847       if (strlen (pos) > 0)
848         {
849           if (0 == strcmp (pos, match))
850             {
851               memmove (pos, &end[1], strlen (&end[1]) + 1);
852
853               if (pos != list)
854                 pos[-1] = ' ';  /* previously changed to "\0" */
855               GNUNET_CONFIGURATION_set_value_string (cfg,
856                                                      section, option, list);
857               GNUNET_free (list);
858               GNUNET_free (match);
859               return GNUNET_OK;
860             }
861         }
862       if (old == '\0')
863         break;
864       pos = end + 1;
865     }
866   GNUNET_free (list);
867   GNUNET_free (match);
868   return GNUNET_NO;
869 }
870
871
872 /**
873  * Load configuration (starts with defaults, then loads
874  * system-specific configuration).
875  */
876 int
877 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
878                            const char *cfgfn)
879 {
880   char *baseconfig;
881   char *ipath;
882
883   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
884   if (ipath == NULL)
885     return GNUNET_SYSERR;
886   baseconfig = NULL;
887   GNUNET_asprintf (&baseconfig,
888                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
889   GNUNET_free (ipath);
890   if ((GNUNET_OK !=
891        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
892       (!((cfgfn == NULL) ||
893          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, cfgfn)))))
894     {
895       GNUNET_free (baseconfig);
896       return GNUNET_SYSERR;
897     }
898   GNUNET_free (baseconfig);
899   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
900                                                       "TESTING",
901                                                       "WEAKRANDOM")) &&
902       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
903                                                            "TESTING",
904                                                            "WEAKRANDOM")))
905     GNUNET_CRYPTO_random_disable_entropy_gathering ();
906   return GNUNET_OK;
907 }
908
909
910
911 /* end of configuration.c */