Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Interface revolution: do not try to survive to malloc failure
[simgrid.git] / src / xbt / config.c
1 /* $Id$ */
2
3 /* config - Dictionnary where the type of each cell is provided.            */
4
5 /* This is useful to build named structs, like option or property sets.     */
6
7 /* Authors: Martin Quinson                                                  */
8 /* Copyright (C) 2001,2002,2003,2004 the OURAGAN project.                   */
9
10 /* This program is free software; you can redistribute it and/or modify it
11    under the terms of the license (GNU LGPL) which comes with this package. */
12
13 #include "gras_private.h" /* prototypes of this module */
14
15 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(config,gros,"configuration support");
16
17 /* gras_cfgelm_t: the typedef corresponding to a config cell. 
18
19    Both data and DTD are mixed, but fixing it now would prevent me to ever
20    defend my thesis. */
21
22 typedef struct {
23   /* Allowed type of the cell */
24   gras_cfgelm_type_t type;
25   int min,max;
26
27   /* actual content 
28      (cannot be an union because type host uses both str and i) */
29   gras_dynar_t *content;
30 } gras_cfgelm_t;
31
32 static const char *gras_cfgelm_type_name[gras_cfgelm_type_count]=
33   {"int","double","string","host"};
34
35 /* Internal stuff used in cache to free a cell */
36 static void gras_cfgelm_free(void *data);
37
38 /* Retrieve the cell we'll modify */
39 static gras_error_t gras_cfgelm_get(gras_cfg_t *cfg, const char *name,
40                                     gras_cfgelm_type_t type,
41                                     /* OUT */ gras_cfgelm_t **whereto);
42
43 void gras_cfg_str_free(void *d);
44 void gras_cfg_host_free(void *d);
45
46 void gras_cfg_str_free(void *d){
47   gras_free(*(void**)d);
48 }
49 void gras_cfg_host_free(void *d){
50   gras_host_t *h=(gras_host_t*) *(void**)d; 
51   if (h) {
52     if (h->name) gras_free(h->name);
53     gras_free(h);
54   }
55 }
56
57 /*----[ Memory management ]-----------------------------------------------*/
58
59 /**
60  * gras_cfg_new:
61  *
62  * @whereto: 
63  *
64  * Initialise an config set
65  */
66
67
68 void gras_cfg_new(gras_cfg_t **whereto) {
69   gras_dict_new((gras_dict_t**)whereto);
70 }
71
72 /**
73  * gras_cfg_cpy:
74  *
75  * @whereto: the config set to be created
76  * @tocopy: the source data
77  *
78  */
79
80 void
81 gras_cfg_cpy(gras_cfg_t **whereto, gras_cfg_t *tocopy) {
82   gras_dict_cursor_t *cursor=NULL; 
83   gras_cfgelm_t *cell=NULL;
84   char *name=NULL;
85   
86   *whereto=NULL;
87   gras_assert0(tocopy,"cannot copy NULL config");
88
89   gras_dict_foreach((gras_dict_t*)tocopy,cursor,name,cell) {
90     gras_cfg_register(*whereto, name, cell->type, cell->min, cell->max);
91   }
92 }
93
94 void gras_cfg_free(gras_cfg_t **cfg) {
95   gras_dict_free((gras_dict_t**)cfg);
96 }
97
98 /**
99  * gras_cfg_dump:
100  * @name: The name to give to this config set
101  * @indent: what to write at the begining of each line (right number of spaces)
102  * @cfg: the config set
103  *
104  * Dumps a config set for debuging purpose
105  */
106 void
107 gras_cfg_dump(const char *name,const char *indent,gras_cfg_t *cfg) {
108   gras_dict_t *dict = (gras_dict_t*) cfg;
109   gras_dict_cursor_t *cursor=NULL; 
110   gras_cfgelm_t *cell=NULL;
111   char *key=NULL;
112   int i; 
113   gras_error_t errcode;
114   int size;
115   int ival;
116   char *sval;
117   double dval;
118   gras_host_t hval;
119
120   if (name)
121     printf("%s>> Dumping of the config set '%s':\n",indent,name);
122   gras_dict_foreach(dict,cursor,key,cell) {
123
124     printf("%s  %s:",indent,key);
125
126     size = gras_dynar_length(cell->content);
127     printf("%d_to_%d_%s. Actual size=%d. List of values:\n",
128            cell->min,cell->max,gras_cfgelm_type_name[cell->type],
129            size);
130
131     switch (cell->type) {
132        
133     case gras_cfgelm_int:
134       for (i=0; i<size; i++) {
135         gras_dynar_get(cell->content,i,&ival);
136         printf ("%s    %d\n",indent,ival);
137       }
138       break;
139
140     case gras_cfgelm_double:
141       for (i=0; i<size; i++) {
142         gras_dynar_get(cell->content,i,&dval);
143         printf ("%s    %f\n",indent,dval);
144       }
145       break;
146
147     case gras_cfgelm_string:
148       for (i=0; i<size; i++) {
149         gras_dynar_get(cell->content,i,&sval);
150         printf ("%s    %s\n",indent,sval);
151       }
152       break;
153
154     case gras_cfgelm_host:
155       for (i=0; i<size; i++) {
156         gras_dynar_get(cell->content,i,&hval);
157         printf ("%s    %s:%d\n",indent,hval.name,hval.port);
158       }
159       break;
160
161     default:
162       printf("%s    Invalid type!!\n",indent);
163     }
164
165   }
166
167   if (name) printf("%s<< End of the config set '%s'\n",indent,name);
168   fflush(stdout);
169
170   gras_dict_cursor_free(cursor);
171   return;
172 }
173
174 /**
175  * gras_cfgelm_free:
176  *
177  * @data: the data to be freed (typed as void* to be usable as free funct in dict)
178  *
179  * free an config element
180  */
181
182 void gras_cfgelm_free(void *data) {
183   gras_cfgelm_t *c=(gras_cfgelm_t *)data;
184
185   if (!c) return;
186   gras_dynar_free(c->content);
187   gras_free(c);
188 }
189
190 /*----[ Registering stuff ]-----------------------------------------------*/
191
192 /**
193  * gras_cfg_register:
194  * @cfg: the config set
195  * @type: the type of the config element
196  * @min: the minimum
197  * @max: the maximum
198  *
199  * register an element within a config set
200  */
201
202 void
203 gras_cfg_register(gras_cfg_t *cfg,
204                   const char *name, gras_cfgelm_type_t type,
205                   int min, int max){
206   gras_cfgelm_t *res;
207   gras_error_t errcode;
208
209   DEBUG4("Register cfg elm %s (%d to %d %s)",name,min,max,gras_cfgelm_type_name[type]);
210   errcode = gras_dict_get((gras_dict_t*)cfg,name,(void**)&res);
211
212   if (errcode == no_error) {
213     WARN1("Config elem %s registered twice.",name);
214     /* Will be removed by the insertion of the new one */
215   } 
216   gras_assert_error(mismatch_error);
217
218   res=gras_new(gras_cfgelm_t,1);
219
220   res->type=type;
221   res->min=min;
222   res->max=max;
223
224   switch (type) {
225   case gras_cfgelm_int:
226     gras_dynar_new(&(res->content), sizeof(int), NULL);
227     break;
228
229   case gras_cfgelm_double:
230     gras_dynar_new(&(res->content), sizeof(double), NULL);
231     break;
232
233   case gras_cfgelm_string:
234    gras_dynar_new(&(res->content),sizeof(char*),&gras_cfg_str_free);
235    break;
236
237   case gras_cfgelm_host:
238    gras_dynar_new(&(res->content),sizeof(gras_host_t*),&gras_cfg_host_free);
239    break;
240
241   default:
242     ERROR1("%d is an invalide type code",type);
243   }
244     
245   gras_dict_set((gras_dict_t*)cfg,name,res,&gras_cfgelm_free);
246 }
247
248 /**
249  * gras_cfg_unregister:
250  * 
251  * @cfg: the config set
252  * @name: the name of the elem to be freed
253  * 
254  * unregister an element from a config set. 
255  * Note that it removes both the DTD and the actual content.
256  */
257
258 gras_error_t
259 gras_cfg_unregister(gras_cfg_t *cfg,const char *name) {
260   return gras_dict_remove((gras_dict_t*)cfg,name);
261 }
262
263 /**
264  * gras_cfg_register_str:
265  *
266  * @cfg: the config set
267  * @entry: a string describing the element to register
268  *
269  * Parse a string and register the stuff described.
270  */
271
272 gras_error_t
273 gras_cfg_register_str(gras_cfg_t *cfg,const char *entry) {
274   char *entrycpy=gras_strdup(entry);
275   char *tok;
276
277   int min,max;
278   gras_cfgelm_type_t type;
279
280   tok=strchr(entrycpy, ':');
281   if (!tok) {
282     ERROR3("%s%s%s",
283           "Invalid config element descriptor: ",entry,
284           "; Should be <name>:<min nb>_to_<max nb>_<type>");
285     gras_free(entrycpy);
286     gras_abort();
287   }
288   *(tok++)='\0';
289
290   min=strtol(tok, &tok, 10);
291   if (!tok) {
292     ERROR1("Invalid minimum in config element descriptor %s",entry);
293     gras_free(entrycpy);
294     gras_abort();
295   }
296
297   if (!strcmp(tok,"_to_")){
298     ERROR3("%s%s%s",
299           "Invalid config element descriptor: ",entry,
300           "; Should be <name>:<min nb>_to_<max nb>_<type>");
301     gras_free(entrycpy);
302     gras_abort();
303   }
304   tok += strlen("_to_");
305
306   max=strtol(tok, &tok, 10);
307   if (!tok) {
308     ERROR1("Invalid maximum in config element descriptor %s",entry);
309     gras_free(entrycpy);
310     gras_abort();
311   }
312
313   if (*(tok++)!='_') {
314     ERROR3("%s%s%s",
315           "Invalid config element descriptor: ",entry,
316           "; Should be <name>:<min nb>_to_<max nb>_<type>");
317     gras_free(entrycpy);
318     gras_abort();
319   }
320
321   for (type=0; 
322        type<gras_cfgelm_type_count && strcmp(tok,gras_cfgelm_type_name[type]); 
323        type++);
324   if (type == gras_cfgelm_type_count) {
325     ERROR3("%s%s%s",
326           "Invalid type in config element descriptor: ",entry,
327           "; Should be one of 'string', 'int', 'host' or 'double'.");
328     gras_free(entrycpy);
329     gras_abort();
330   }
331
332   gras_cfg_register(cfg,entrycpy,type,min,max);
333
334   gras_free(entrycpy); /* strdup'ed by dict mechanism, but cannot be const */
335   return no_error;
336 }
337
338 /**
339  * gras_cfg_check:
340  *
341  * @cfg: the config set
342  * 
343  * Check the config set
344  */
345
346 gras_error_t
347 gras_cfg_check(gras_cfg_t *cfg) {
348   gras_dict_cursor_t *cursor; 
349   gras_cfgelm_t *cell;
350   char *name;
351   int size;
352
353   gras_assert0(cfg,"NULL config set.");
354
355   gras_dict_foreach((gras_dict_t*)cfg,cursor,name,cell) {
356     size = gras_dynar_length(cell->content);
357     if (cell->min > size) { 
358       ERROR4("Config elem %s needs at least %d %s, but there is only %d values.",
359              name,
360              cell->min,
361              gras_cfgelm_type_name[cell->type],
362              size); 
363       gras_dict_cursor_free(cursor);
364       return mismatch_error;
365     }
366
367     if (cell->max < size) {
368       ERROR4("Config elem %s accepts at most %d %s, but there is %d values.",
369              name,
370              cell->max,
371              gras_cfgelm_type_name[cell->type],
372              size);
373       gras_dict_cursor_free(cursor);
374       return mismatch_error;
375     }
376
377   }
378
379   gras_dict_cursor_free(cursor);
380   return no_error;
381 }
382
383 static gras_error_t gras_cfgelm_get(gras_cfg_t *cfg,
384                                     const char *name,
385                                     gras_cfgelm_type_t type,
386                                     /* OUT */ gras_cfgelm_t **whereto){
387    
388   gras_error_t errcode = gras_dict_get((gras_dict_t*)cfg,name,
389                                        (void**)whereto);
390
391   if (errcode == mismatch_error) {
392     ERROR1("No registered cell %s in this config set",
393            name);
394     return mismatch_error;
395   }
396   if (errcode != no_error)
397      return errcode;
398
399   gras_assert3((*whereto)->type == type,
400                "You tried to access to the config element %s as an %s, but its type is %s.",
401                name,
402                gras_cfgelm_type_name[type],
403                gras_cfgelm_type_name[(*whereto)->type]);
404
405   return no_error;
406 }
407
408 /**
409  * gras_cfg_get_type:
410  *
411  * @cfg: the config set
412  * @name: the name of the element 
413  * @type: the result
414  *
415  * Give the type of the config element
416  */
417
418 gras_error_t
419 gras_cfg_get_type(gras_cfg_t *cfg, const char *name, 
420                       /* OUT */gras_cfgelm_type_t *type) {
421
422   gras_cfgelm_t *cell;
423   gras_error_t errcode;
424
425   TRYCATCH(mismatch_error,gras_dict_get((gras_dict_t*)cfg,name,(void**)&cell));
426
427   if (errcode == mismatch_error) {
428     ERROR1("Can't get the type of '%s' since this cell does not exist",
429            name);
430     return mismatch_error;
431   }
432
433   *type=cell->type;
434
435   return no_error;
436 }
437
438 /*----[ Setting ]---------------------------------------------------------*/
439 /** 
440  * gras_cfg_set_vargs(): 
441  * @cfg: config set to fill
442  * @varargs: NULL-terminated list of pairs {(const char*)key, value}
443  *
444  * Add some values to the config set.
445  * @warning: if the list isn't NULL terminated, it will segfault. 
446  */
447 gras_error_t
448 gras_cfg_set_vargs(gras_cfg_t *cfg, va_list pa) {
449   char *str,*name;
450   int i;
451   double d;
452   gras_cfgelm_type_t type;
453
454   gras_error_t errcode;
455   
456   while ((name=va_arg(pa,char *))) {
457
458     if (!gras_cfg_get_type(cfg,name,&type)) {
459       ERROR1("Can't set the property '%s' since it's not registered",name);
460       return mismatch_error;
461     }
462
463     switch (type) {
464     case gras_cfgelm_host:
465       str = va_arg(pa, char *);
466       i=va_arg(pa,int);
467       TRY(gras_cfg_set_host(cfg,name,str,i));
468       break;
469       
470     case gras_cfgelm_string:
471       str=va_arg(pa, char *);
472       TRY(gras_cfg_set_string(cfg, name, str));
473       break;
474
475     case gras_cfgelm_int:
476       i=va_arg(pa,int);
477       TRY(gras_cfg_set_int(cfg,name,i));
478       break;
479
480     case gras_cfgelm_double:
481       d=va_arg(pa,double);
482       TRY(gras_cfg_set_double(cfg,name,d));
483       break;
484
485     default: 
486       RAISE1(unknown_error,"Config element cell %s not valid.",name);
487     }
488   }
489   return no_error;
490 }
491
492 /** 
493  * gras_cfg_set():
494  * @cfg: config set to fill
495  * @varargs: NULL-terminated list of pairs {(const char*)key, value}
496  *
497  * Add some values to the config set.
498  * @warning: if the list isn't NULL terminated, it will segfault. 
499  */
500 gras_error_t gras_cfg_set(gras_cfg_t *cfg, ...) {
501   va_list pa;
502   gras_error_t errcode;
503
504   va_start(pa,cfg);
505   errcode=gras_cfg_set_vargs(cfg,pa);
506   va_end(pa);
507   return errcode;
508 }
509
510 /**
511  * gras_cfg_set_parse():
512  * @cfg: config set to fill
513  * @options: a string containing the content to add to the config set. This
514  * is a '\t',' ' or '\n' separated list of cells. Each individual cell is
515  * like "[name]:[value]" where [name] is the name of an already registred 
516  * cell, and [value] conforms to the data type under which this cell was
517  * registred.
518  *
519  * Add the cells described in a string to a config set.
520  */
521
522 gras_error_t
523 gras_cfg_set_parse(gras_cfg_t *cfg, const char *options) {
524   int i;
525   double d;
526   char *str;
527
528   gras_cfgelm_t *cell;
529   char *optionlist_cpy;
530   char *option,  *name,*val;
531
532   int len;
533   gras_error_t errcode;
534
535   GRAS_IN;
536   if (!options || !strlen(options)) { /* nothing to do */
537     return no_error;
538   }
539   optionlist_cpy=gras_strdup(options);
540
541   DEBUG1("List to parse and set:'%s'",options);
542   option=optionlist_cpy;
543   while (1) { /* breaks in the code */
544
545     if (!option) 
546       break;
547     name=option;
548     len=strlen(name);
549     DEBUG3("Still to parse and set: '%s'. len=%d; option-name=%ld",
550            name,len,(long)(option-name));
551
552     /* Pass the value */
553     while (option-name<=(len-1) && *option != ' ' && *option != '\n' && *option != '\t') {
554       /*fprintf(stderr,"Take %c.\n",*option);*/
555       option++;
556     }
557     if (option-name == len) {
558       /*fprintf(stderr,"Boundary=EOL\n");*/
559       option=NULL; /* don't do next iteration */
560
561     } else {
562       /*fprintf(stderr,"Boundary on '%c'. len=%d;option-name=%d\n",*option,len,option-name);*/
563
564       /* Pass the following blank chars */
565       *(option++)='\0';
566       while (option-name<(len-1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
567         /*      fprintf(stderr,"Ignore a blank char.\n");*/
568         option++;
569       }
570       if (option-name == len-1)
571         option=NULL; /* don't do next iteration */
572     }
573     DEBUG2("parse now:'%s'; parse later:'%s'",name,option);
574
575     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
576       continue;
577     if (!strlen(name))
578       break;
579     
580     val=strchr(name,':');
581     if (!val) {
582       gras_free(optionlist_cpy);
583       gras_assert1(FALSE,
584                    "Malformated option: '%s'; Should be of the form 'name:value'",
585                    name);
586     }
587     *(val++)='\0';
588
589     DEBUG2("name='%s';val='%s'",name,val);
590
591     errcode=gras_dict_get((gras_dict_t*)cfg,name,(void**)&cell);
592     switch (errcode) {
593     case no_error:
594       break;
595     case mismatch_error:
596       ERROR1("No registrated cell corresponding to '%s'.",name);
597       gras_free(optionlist_cpy);
598       return mismatch_error;
599       break;
600     default:
601       gras_free(optionlist_cpy);
602       return errcode;
603     }
604
605     switch (cell->type) {
606     case gras_cfgelm_string:
607       TRYCLEAN(gras_cfg_set_string(cfg, name, val),
608                gras_free(optionlist_cpy));
609       break;
610
611     case gras_cfgelm_int:
612       i=strtol(val, &val, 0);
613       if (val==NULL) {
614         gras_free(optionlist_cpy);      
615         gras_assert1(FALSE,
616                      "Value of option %s not valid. Should be an integer",
617                      name);
618       }
619
620       TRYCLEAN(gras_cfg_set_int(cfg,name,i),
621                gras_free(optionlist_cpy));
622       break;
623
624     case gras_cfgelm_double:
625       d=strtod(val, &val);
626       if (val==NULL) {
627         gras_free(optionlist_cpy);      
628         gras_assert1(FALSE,
629                "Value of option %s not valid. Should be a double",
630                name);
631       }
632
633       TRYCLEAN(gras_cfg_set_double(cfg,name,d),
634                gras_free(optionlist_cpy));
635       break;
636
637     case gras_cfgelm_host:
638       str=val;
639       val=strchr(val,':');
640       if (!val) {
641         gras_free(optionlist_cpy);      
642         gras_assert1(FALSE,
643                "Value of option %s not valid. Should be an host (machine:port)",
644                name);
645       }
646
647       *(val++)='\0';
648       i=strtol(val, &val, 0);
649       if (val==NULL) {
650         gras_free(optionlist_cpy);      
651         gras_assert1(FALSE,
652                "Value of option %s not valid. Should be an host (machine:port)",
653                name);
654       }
655
656       TRYCLEAN(gras_cfg_set_host(cfg,name,str,i),
657                gras_free(optionlist_cpy));
658       break;      
659
660     default: 
661       gras_free(optionlist_cpy);
662       RAISE1(unknown_error,"Type of config element %s is not valid.",name);
663     }
664     
665   }
666   gras_free(optionlist_cpy);
667   return no_error;
668 }
669
670 /**
671  * gras_cfg_set_int:
672  *
673  * @cfg: the config set
674  * @name: the name of the cell
675  * @val: the value of the cell
676  *
677  * Set the value of the cell @name in @cfg with the provided value.
678  */ 
679 gras_error_t
680 gras_cfg_set_int(gras_cfg_t *cfg,const char*name, int val) {
681   gras_cfgelm_t *cell;
682   gras_error_t errcode;
683
684   VERB2("Configuration setting: %s=%d",name,val);
685   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
686
687   if (cell->max > 1) {
688     gras_dynar_push(cell->content,&val);
689   } else {
690     gras_dynar_set(cell->content,0,&val);
691   }
692   return no_error;
693 }
694
695 /**
696  * gras_cfg_set_double:
697  * @cfg: the config set
698  * @name: the name of the cell
699  * @val: the doule to set
700  * 
701  * Set the value of the cell @name in @cfg with the provided value.
702  */ 
703
704 gras_error_t
705 gras_cfg_set_double(gras_cfg_t *cfg,const char*name, double val) {
706   gras_cfgelm_t *cell;
707   gras_error_t errcode;
708
709   VERB2("Configuration setting: %s=%f",name,val);
710   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
711
712   if (cell->max > 1) {
713     gras_dynar_push(cell->content,&val);
714   } else {
715     gras_dynar_set(cell->content,0,&val);
716   }
717   return no_error;
718 }
719
720 /**
721  * gras_cfg_set_string:
722  * 
723  * @cfg: the config set
724  * @name: the name of the cell
725  * @val: the value to be added
726  *
727  * Set the value of the cell @name in @cfg with the provided value.
728  */ 
729
730 gras_error_t
731 gras_cfg_set_string(gras_cfg_t *cfg,const char*name, const char*val) { 
732   gras_cfgelm_t *cell;
733   gras_error_t errcode;
734   char *newval = gras_strdup(val);
735
736   VERB2("Configuration setting: %s=%s",name,val);
737   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
738
739   if (cell->max > 1) {
740     gras_dynar_push(cell->content,&newval);
741   } else {
742     gras_dynar_set(cell->content,0,&newval);
743   }
744   return no_error;
745 }
746
747 /**
748  * gras_cfg_set_host:
749  * 
750  * @cfg: the config set
751  * @name: the name of the cell
752  * @host: the host
753  * @port: the port number
754  *
755  * Set the value of the cell @name in @cfg with the provided value 
756  * on the given @host to the given @port
757  */ 
758
759 gras_error_t 
760 gras_cfg_set_host(gras_cfg_t *cfg,const char*name, 
761                   const char *host,int port) {
762   gras_cfgelm_t *cell;
763   gras_error_t errcode;
764   gras_host_t *val=gras_new(gras_host_t,1);
765
766   VERB3("Configuration setting: %s=%s:%d",name,host,port);
767
768   val->name = gras_strdup(name);
769   val->port = port;
770
771   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
772
773   if (cell->max > 1) {
774     gras_dynar_push(cell->content,&val);
775   } else {
776     gras_dynar_set(cell->content,0,&val);
777   }
778   return no_error;
779 }
780
781 /* ---- [ Removing ] ---- */
782
783 /**
784  * gras_cfg_rm_int:
785  *
786  * @cfg: the config set
787  * @name: the name of the cell
788  * @val: the value to be removed
789  *
790  * Remove the provided @val from the cell @name in @cfg.
791  */
792 gras_error_t gras_cfg_rm_int   (gras_cfg_t *cfg,const char*name, int val) {
793
794   gras_cfgelm_t *cell;
795   int cpt,seen;
796   gras_error_t errcode;
797
798   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
799   
800   gras_dynar_foreach(cell->content,cpt,seen) {
801     if (seen == val) {
802       gras_dynar_cursor_rm(cell->content,&cpt);
803       return no_error;
804     }
805   }
806
807   ERROR2("Can't remove the value %d of config element %s: value not found.",
808          val,name);
809   return mismatch_error;
810 }
811
812 /**
813  * gras_cfg_rm_double:
814  *
815  * @cfg: the config set
816  * @name: the name of the cell
817  * @val: the value to be removed
818  *
819  * Remove the provided @val from the cell @name in @cfg.
820  */
821
822 gras_error_t gras_cfg_rm_double(gras_cfg_t *cfg,const char*name, double val) {
823   gras_cfgelm_t *cell;
824   int cpt;
825   double seen;
826   gras_error_t errcode;
827
828   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
829   
830   gras_dynar_foreach(cell->content,cpt,seen) {
831     if (seen == val) {
832       gras_dynar_cursor_rm(cell->content,&cpt);
833       return no_error;
834     }
835   }
836
837   ERROR2("Can't remove the value %f of config element %s: value not found.",
838          val,name);
839   return mismatch_error;
840 }
841
842 /**
843  * gras_cfg_rm_string:
844  *
845  * @cfg: the config set
846  * @name: the name of the cell
847  * @val: the value of the string which will be removed
848  *
849  * Remove the provided @val from the cell @name in @cfg.
850  */
851 gras_error_t
852 gras_cfg_rm_string(gras_cfg_t *cfg,const char*name, const char *val) {
853   gras_cfgelm_t *cell;
854   int cpt;
855   char *seen;
856   gras_error_t errcode;
857
858   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
859   
860   gras_dynar_foreach(cell->content,cpt,seen) {
861     if (!strcpy(seen,val)) {
862       gras_dynar_cursor_rm(cell->content,&cpt);
863       return no_error;
864     }
865   }
866
867   ERROR2("Can't remove the value %s of config element %s: value not found.",
868          val,name);
869   return mismatch_error;
870 }
871
872 /**
873  * gras_cfg_rm_host:
874  * 
875  * @cfg: the config set
876  * @name: the name of the cell
877  * @host: the hostname
878  * @port: the port number
879  *
880  * Remove the provided @host:@port from the cell @name in @cfg.
881  */
882
883 gras_error_t
884 gras_cfg_rm_host  (gras_cfg_t *cfg,const char*name, const char *host,int port) {
885   gras_cfgelm_t *cell;
886   int cpt;
887   gras_host_t *seen;
888   gras_error_t errcode;
889
890   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
891   
892   gras_dynar_foreach(cell->content,cpt,seen) {
893     if (!strcpy(seen->name,host) && seen->port == port) {
894       gras_dynar_cursor_rm(cell->content,&cpt);
895       return no_error;
896     }
897   }
898
899   ERROR3("Can't remove the value %s:%d of config element %s: value not found.",
900          host,port,name);
901   return mismatch_error;
902 }
903
904 /* rm everything */
905
906 /**
907  * gras_cfg_empty:
908  * 
909  * @cfg: the config set
910  * @name: the name of the cell
911  *
912  * rm evenything
913  */
914
915 gras_error_t 
916 gras_cfg_empty(gras_cfg_t *cfg,const char*name) {
917   gras_cfgelm_t *cell;
918
919   gras_error_t errcode;
920
921   TRYCATCH(mismatch_error,
922            gras_dict_get((gras_dict_t*)cfg,name,(void**)&cell));
923   if (errcode == mismatch_error) {
924     ERROR1("Can't empty  '%s' since this config element does not exist",
925            name);
926     return mismatch_error;
927   }
928
929   if (cell) {
930     gras_dynar_reset(cell->content);
931   }
932   return no_error;
933 }
934
935 /*----[ Getting ]---------------------------------------------------------*/
936
937 /**
938  * gras_cfg_get_int:
939  * @cfg: the config set
940  * @name: the name of the cell
941  * @val: the wanted value
942  *
943  * Returns the first value from the config set under the given name.
944  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
945  * instead.
946  *
947  * @warning the returned value is the actual content of the config set
948  */
949 gras_error_t
950 gras_cfg_get_int   (gras_cfg_t  *cfg, 
951                     const char *name,
952                     int        *val) {
953   gras_cfgelm_t *cell;
954   gras_error_t errcode;
955
956   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
957
958   if (gras_dynar_length(cell->content) > 1) {
959     WARN2("You asked for the first value of the config element '%s', but there is %lu values",
960              name, gras_dynar_length(cell->content));
961   }
962
963   gras_dynar_get(cell->content, 0, (void*)val);
964   return no_error;
965 }
966
967 /**
968  * gras_cfg_get_double:
969  * @cfg: the config set
970  * @name: the name of the cell
971  * @val: the wanted value
972  *
973  * Returns the first value from the config set under the given name.
974  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
975  * instead.
976  *
977  * @warning the returned value is the actual content of the config set
978  */
979
980 gras_error_t
981 gras_cfg_get_double(gras_cfg_t *cfg,
982                     const char *name,
983                     double     *val) {
984   gras_cfgelm_t *cell;
985   gras_error_t errcode;
986
987   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
988
989   if (gras_dynar_length(cell->content) > 1) {
990     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
991              name, gras_dynar_length(cell->content));
992   }
993
994   gras_dynar_get(cell->content, 0, (void*)val);
995   return no_error;
996 }
997
998 /**
999  * gras_cfg_get_string:
1000  *
1001  * @th: the config set
1002  * @name: the name of the cell
1003  * @val: the wanted value
1004  *
1005  * Returns the first value from the config set under the given name.
1006  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
1007  * instead.
1008  *
1009  * @warning the returned value is the actual content of the config set
1010  */
1011
1012 gras_error_t gras_cfg_get_string(gras_cfg_t *cfg,
1013                                  const char *name,
1014                                  char      **val) {
1015   gras_cfgelm_t *cell;
1016   gras_error_t errcode;
1017
1018   *val=NULL;
1019
1020   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
1021
1022   if (gras_dynar_length(cell->content) > 1) {
1023     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
1024              name, gras_dynar_length(cell->content));
1025   }
1026
1027   gras_dynar_get(cell->content, 0, (void*)val);
1028   return no_error;
1029 }
1030
1031 /**
1032  * gras_cfg_get_host:
1033  *
1034  * @cfg: the config set
1035  * @name: the name of the cell
1036  * @host: the host
1037  * @port: the port number
1038  *
1039  * Returns the first value from the config set under the given name.
1040  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
1041  * instead.
1042  *
1043  * @warning the returned value is the actual content of the config set
1044  */
1045
1046 gras_error_t gras_cfg_get_host  (gras_cfg_t *cfg,
1047                                  const char *name,
1048                                  char      **host,
1049                                  int        *port) {
1050   gras_cfgelm_t *cell;
1051   gras_error_t errcode;
1052   gras_host_t *val;
1053
1054   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
1055
1056   if (gras_dynar_length(cell->content) > 1) {
1057     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
1058              name, gras_dynar_length(cell->content));
1059   }
1060
1061   gras_dynar_get(cell->content, 0, (void*)val);
1062   *host=val->name;
1063   *port=val->port;
1064   
1065   return no_error;
1066 }
1067
1068 /**
1069  * gras_cfg_get_dynar:
1070  * @cfg: where to search in
1071  * @name: what to search for
1072  * @dynar: result
1073  *
1074  * Get the data stored in the config bag. 
1075  *
1076  * @warning the returned value is the actual content of the config set
1077  */
1078 gras_error_t gras_cfg_get_dynar (gras_cfg_t    *cfg,
1079                                  const char    *name,
1080                                  gras_dynar_t **dynar) {
1081   gras_cfgelm_t *cell;
1082   gras_error_t errcode = gras_dict_get((gras_dict_t*)cfg,name,
1083                                        (void**)&cell);
1084
1085   if (errcode == mismatch_error) {
1086     ERROR1("No registered cell %s in this config set",
1087            name);
1088     return mismatch_error;
1089   }
1090   if (errcode != no_error)
1091      return errcode;
1092
1093   *dynar = cell->content;
1094   return no_error;
1095 }
1096