rename NETWORK_socket API to NETWORK_connection (to make room for the new actual...
[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     }
606   else
607     {
608       *value = NULL;
609     }
610   return ret;
611 }
612
613 /**
614  * Get a configuration value that should be in a set of
615  * "GNUNET_YES" or "GNUNET_NO".
616  *
617  * @return GNUNET_YES, GNUNET_NO or GNUNET_SYSERR
618  */
619 int
620 GNUNET_CONFIGURATION_get_value_yesno (const struct GNUNET_CONFIGURATION_Handle *cfg,
621                                       const char *section, const char *option)
622 {
623   static const char *yesno[] = { "YES", "NO", NULL };
624   const char *val;
625   int ret;
626
627   ret = GNUNET_CONFIGURATION_get_value_choice (cfg,
628                                                section, option, yesno, &val);
629   if (ret == GNUNET_SYSERR)
630     return ret;
631   if (val == yesno[0])
632     return GNUNET_YES;
633   return GNUNET_NO;
634 }
635
636
637 /**
638  * Iterate over the set of filenames stored in a configuration value.
639  *
640  * @return number of filenames iterated over, -1 on error
641  */
642 int
643 GNUNET_CONFIGURATION_iterate_value_filenames (const struct
644                                               GNUNET_CONFIGURATION_Handle
645                                               *cfg, const char *section,
646                                               const char *option,
647                                               GNUNET_FileNameCallback cb,
648                                               void *cls)
649 {
650   char *list;
651   char *pos;
652   char *end;
653   char old;
654   int ret;
655
656   if (GNUNET_OK !=
657       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
658     return 0;
659   GNUNET_assert (list != NULL);
660   ret = 0;
661   pos = list;
662   while (1)
663     {
664       while (pos[0] == ' ')
665         pos++;
666       if (strlen (pos) == 0)
667         break;
668       end = pos + 1;
669       while ((end[0] != ' ') && (end[0] != '\0'))
670         {
671           if (end[0] == '\\')
672             {
673               switch (end[1])
674                 {
675                 case '\\':
676                 case ' ':
677                   memmove (end, &end[1], strlen (&end[1]) + 1);
678                 case '\0':
679                   /* illegal, but just keep it */
680                   break;
681                 default:
682                   /* illegal, but just ignore that there was a '/' */
683                   break;
684                 }
685             }
686           end++;
687         }
688       old = end[0];
689       end[0] = '\0';
690       if (strlen (pos) > 0)
691         {
692           ret++;
693           if ((cb != NULL) && (GNUNET_OK != cb (cls, pos)))
694             {
695               ret = GNUNET_SYSERR;
696               break;
697             }
698         }
699       if (old == '\0')
700         break;
701       pos = end + 1;
702     }
703   GNUNET_free (list);
704   return ret;
705 }
706
707 static char *
708 escape_name (const char *value)
709 {
710   char *escaped;
711   const char *rpos;
712   char *wpos;
713
714   escaped = GNUNET_malloc (strlen (value) * 2 + 1);
715   memset (escaped, 0, strlen (value) * 2 + 1);
716   rpos = value;
717   wpos = escaped;
718   while (rpos[0] != '\0')
719     {
720       switch (rpos[0])
721         {
722         case '\\':
723         case ' ':
724           wpos[0] = '\\';
725           wpos[1] = rpos[0];
726           wpos += 2;
727           break;
728         default:
729           wpos[0] = rpos[0];
730           wpos++;
731         }
732       rpos++;
733     }
734   return escaped;
735 }
736
737 static int
738 test_match (void *cls, const char *fn)
739 {
740   const char *of = cls;
741   return (0 == strcmp (of, fn)) ? GNUNET_SYSERR : GNUNET_OK;
742 }
743
744 /**
745  * Append a filename to a configuration value that
746  * represents a list of filenames
747  *
748  * @param value filename to append
749  * @return GNUNET_OK on success,
750  *         GNUNET_NO if the filename already in the list
751  *         GNUNET_SYSERR on error
752  */
753 int
754 GNUNET_CONFIGURATION_append_value_filename (struct GNUNET_CONFIGURATION_Handle
755                                             *cfg,
756                                             const char *section,
757                                             const char *option,
758                                             const char *value)
759 {
760   char *escaped;
761   char *old;
762   char *nw;
763
764   if (GNUNET_SYSERR
765       == GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
766                                                        section,
767                                                        option,
768                                                        &test_match,
769                                                        (void *) value))
770     return GNUNET_NO;           /* already exists */
771   if (GNUNET_OK !=
772       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &old))
773     old = GNUNET_strdup ("");
774   escaped = escape_name (value);
775   nw = GNUNET_malloc (strlen (old) + strlen (escaped) + 2);
776   strcpy (nw, old);
777   strcat (nw, " ");
778   strcat (nw, escaped);
779   GNUNET_CONFIGURATION_set_value_string (cfg, section, option, nw);
780   GNUNET_free (old);
781   GNUNET_free (nw);
782   GNUNET_free (escaped);
783   return GNUNET_OK;
784 }
785
786
787 /**
788  * Remove a filename from a configuration value that
789  * represents a list of filenames
790  *
791  * @param value filename to remove
792  * @return GNUNET_OK on success,
793  *         GNUNET_NO if the filename is not in the list,
794  *         GNUNET_SYSERR on error
795  */
796 int
797 GNUNET_CONFIGURATION_remove_value_filename (struct GNUNET_CONFIGURATION_Handle
798                                             *cfg,
799                                             const char *section,
800                                             const char *option,
801                                             const char *value)
802 {
803   char *list;
804   char *pos;
805   char *end;
806   char *match;
807   char old;
808   int ret;
809
810   if (GNUNET_OK !=
811       GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &list))
812     return GNUNET_NO;
813   match = escape_name (value);
814   ret = 0;
815   pos = list;
816   while (1)
817     {
818       while (pos[0] == ' ')
819         pos++;
820       if (strlen (pos) == 0)
821         break;
822       end = pos + 1;
823       while ((end[0] != ' ') && (end[0] != '\0'))
824         {
825           if (end[0] == '\\')
826             {
827               switch (end[1])
828                 {
829                 case '\\':
830                 case ' ':
831                   end++;
832                   break;
833                 case '\0':
834                   /* illegal, but just keep it */
835                   break;
836                 default:
837                   /* illegal, but just ignore that there was a '/' */
838                   break;
839                 }
840             }
841           end++;
842         }
843       old = end[0];
844       end[0] = '\0';
845       if (strlen (pos) > 0)
846         {
847           if (0 == strcmp (pos, match))
848             {
849               memmove (pos, &end[1], strlen (&end[1]) + 1);
850
851               if (pos != list)
852                 pos[-1] = ' ';  /* previously changed to "\0" */
853               GNUNET_CONFIGURATION_set_value_string (cfg,
854                                                      section, option, list);
855               GNUNET_free (list);
856               GNUNET_free (match);
857               return GNUNET_OK;
858             }
859         }
860       if (old == '\0')
861         break;
862       pos = end + 1;
863     }
864   GNUNET_free (list);
865   GNUNET_free (match);
866   return GNUNET_NO;
867 }
868
869
870 /**
871  * Load configuration (starts with defaults, then loads
872  * system-specific configuration).
873  */
874 int
875 GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg,
876                            const char *cfgfn)
877 {
878   char *baseconfig;
879   char *ipath;
880
881   ipath = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_DATADIR);
882   if (ipath == NULL)
883     return GNUNET_SYSERR;
884   baseconfig = NULL;
885   GNUNET_asprintf (&baseconfig,
886                    "%s%s%s", ipath, DIR_SEPARATOR_STR, "defaults.conf");
887   GNUNET_free (ipath);
888   if ((GNUNET_OK !=
889        GNUNET_CONFIGURATION_parse (cfg, baseconfig)) ||
890       (!((cfgfn == NULL) ||
891          (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, cfgfn)))))
892     {
893       GNUNET_free (baseconfig);
894       return GNUNET_SYSERR;
895     }
896   GNUNET_free (baseconfig);
897   if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (cfg,
898                                                       "TESTING",
899                                                       "WEAKRANDOM")) &&
900       (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (cfg,
901                                                            "TESTING",
902                                                            "WEAKRANDOM")))
903     GNUNET_CRYPTO_random_disable_entropy_gathering ();
904   return GNUNET_OK;
905 }
906
907
908
909 /* end of configuration.c */