Logo AND Algorithmique Numérique Distribuée

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