Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
b10cd74bdc5ceef0d6ad830d8fe250ef176bb8eb
[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_CATEGORY(config);
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   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) free(h->name);
53     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     if ((errcode=gras_dict_cursor_get_key(cursor,(char**)&name))  != no_error ||
132         (errcode=gras_dict_cursor_get_data(cursor,(void**)&cell)) != no_error) {
133       gras_dict_cursor_free(cursor);
134       return;
135     }
136
137     printf("%s  %s:",indent,key);
138     fflush(stdout);
139
140     size = gras_dynar_length(cell->content);
141     printf("%d_to_%d_%s. Actual size=%d. List of values:\n",
142            cell->min,cell->max,gras_cfgelm_type_name[cell->type],
143            size);
144
145     switch (cell->type) {
146     case gras_cfgelm_int:
147       for (i=0; i<size; i++) {
148         gras_dynar_get(cell->content,i,&ival);
149         printf ("%s    %d\n",indent,ival);
150       }
151       break;
152
153     case gras_cfgelm_double:
154       for (i=0; i<size; i++) {
155         gras_dynar_get(cell->content,i,&dval);
156         printf ("%s    %f\n",indent,dval);
157       }
158       break;
159
160     case gras_cfgelm_string:
161       for (i=0; i<size; i++) {
162         gras_dynar_get(cell->content,i,&sval);
163         printf ("%s    %s\n",indent,sval);
164       }
165       break;
166
167     case gras_cfgelm_host:
168       for (i=0; i<size; i++) {
169         gras_dynar_get(cell->content,i,&hval);
170         printf ("%s    %s:%d\n",indent,hval.name,hval.port);
171       }
172       break;
173
174     default:
175       printf("%s    Invalid type!!\n",indent);
176     }
177
178   }
179
180   if (name) printf("%s<< End of the config set '%s'\n",indent,name);
181
182   gras_dict_cursor_free(cursor);
183   return;
184 }
185
186 /**
187  * gras_cfgelm_free:
188  *
189  * @data: the data to be freed (typed as void* to be usable as free funct in dict)
190  *
191  * free an config element
192  */
193
194 void gras_cfgelm_free(void *data) {
195   gras_cfgelm_t *c=(gras_cfgelm_t *)data;
196
197   if (!c) return;
198   gras_dynar_free(c->content);
199   free(c);
200 }
201
202 /*----[ Registering stuff ]-----------------------------------------------*/
203
204 /**
205  * gras_cfg_register:
206  * @cfg: the config set
207  * @type: the type of the config element
208  * @min: the minimum
209  * @max: the maximum
210  *
211  * register an element within a config set
212  */
213
214 gras_error_t
215 gras_cfg_register(gras_cfg_t *cfg,
216                   const char *name, gras_cfgelm_type_t type,
217                   int min, int max){
218   gras_cfgelm_t *res;
219   gras_error_t errcode;
220
221   TRYCATCH(mismatch_error,gras_dict_retrieve((gras_dict_t*)cfg,name,(void**)&res));
222
223   if (errcode != mismatch_error) {
224     WARN1("Config elem %s registered twice.",name);
225     /* Will be removed by the insertion of the new one */
226   } 
227
228   res=malloc(sizeof(gras_cfgelm_t));
229   if (!res)
230     RAISE_MALLOC;
231
232   res->type=type;
233   res->min=min;
234   res->max=max;
235
236   switch (type) {
237   case gras_cfgelm_int:
238     TRY(gras_dynar_new(&(res->content), sizeof(int), NULL));
239     break;
240
241   case gras_cfgelm_double:
242     TRY(gras_dynar_new(&(res->content), sizeof(double), NULL));
243     break;
244
245   case gras_cfgelm_string:
246    TRY(gras_dynar_new(&(res->content),sizeof(char*),&gras_cfg_str_free));
247    break;
248
249   case gras_cfgelm_host:
250    TRY(gras_dynar_new(&(res->content),sizeof(gras_host_t*),&gras_cfg_host_free));
251    break;
252
253   default:
254     ERROR1("%d is an invalide type code",type);
255   }
256     
257   return gras_dict_insert((gras_dict_t*)cfg,name,res,&gras_cfgelm_free);
258 }
259
260 /**
261  * gras_cfg_unregister:
262  * 
263  * @cfg: the config set
264  * @name: the name of the elem to be freed
265  * 
266  * unregister an element from a config set. 
267  * Note that it removes both the DTD and the actual content.
268  */
269
270 gras_error_t
271 gras_cfg_unregister(gras_cfg_t *cfg,const char *name) {
272   return gras_dict_remove((gras_dict_t*)cfg,name);
273 }
274
275 /**
276  * gras_cfg_register_str:
277  *
278  * @cfg: the config set
279  * @entry: a string describing the element to register
280  *
281  * Parse a string and register the stuff described.
282  */
283
284 gras_error_t
285 gras_cfg_register_str(gras_cfg_t *cfg,const char *entry) {
286   char *entrycpy=strdup(entry);
287   char *tok;
288
289   int min,max;
290   gras_cfgelm_type_t type;
291
292   gras_error_t errcode;
293
294   tok=strchr(entrycpy, ':');
295   if (!tok) {
296     ERROR3("%s%s%s",
297           "Invalid config element descriptor: ",entry,
298           "; Should be <name>:<min nb>_to_<max nb>_<type>");
299     free(entrycpy);
300     gras_abort();
301   }
302   *(tok++)='\0';
303
304   min=strtol(tok, &tok, 10);
305   if (!tok) {
306     ERROR1("Invalid minimum in config element descriptor %s",entry);
307     free(entrycpy);
308     gras_abort();
309   }
310
311   if (!strcmp(tok,"_to_")){
312     ERROR3("%s%s%s",
313           "Invalid config element descriptor: ",entry,
314           "; Should be <name>:<min nb>_to_<max nb>_<type>");
315     free(entrycpy);
316     gras_abort();
317   }
318   tok += strlen("_to_");
319
320   max=strtol(tok, &tok, 10);
321   if (!tok) {
322     ERROR1("Invalid maximum in config element descriptor %s",entry);
323     free(entrycpy);
324     gras_abort();
325   }
326
327   if (*(tok++)!='_') {
328     ERROR3("%s%s%s",
329           "Invalid config element descriptor: ",entry,
330           "; Should be <name>:<min nb>_to_<max nb>_<type>");
331     free(entrycpy);
332     gras_abort();
333   }
334
335   for (type=0; 
336        type<gras_cfgelm_type_count && strcmp(tok,gras_cfgelm_type_name[type]); 
337        type++);
338   if (type == gras_cfgelm_type_count) {
339     ERROR3("%s%s%s",
340           "Invalid type in config element descriptor: ",entry,
341           "; Should be one of 'string', 'int', 'host' or 'double'.");
342     free(entrycpy);
343     gras_abort();
344   }
345
346   TRYCLEAN(gras_cfg_register(cfg,entrycpy,type,min,max),
347            free(entrycpy));
348
349   free(entrycpy); /* strdup'ed by dict mechanism, but cannot be const */
350   return no_error;
351 }
352
353 /**
354  * gras_cfg_check:
355  *
356  * @cfg: the config set
357  * 
358  * Check the config set
359  */
360
361 gras_error_t
362 gras_cfg_check(gras_cfg_t *cfg) {
363   gras_dict_cursor_t *cursor; 
364   gras_cfgelm_t *cell;
365   char *name;
366   int size;
367
368   gras_assert0(cfg,"NULL config set.");
369
370   gras_dict_foreach((gras_dict_t*)cfg,cursor,name,cell) {
371     size = gras_dynar_length(cell->content);
372     if (cell->min > size) { 
373       ERROR4("Config elem %s needs at least %d %s, but there is only %d values.",
374              name,
375              cell->min,
376              gras_cfgelm_type_name[cell->type],
377              size);
378       return mismatch_error;
379     }
380
381     if (cell->max < size) {
382       ERROR4("Config elem %s accepts at most %d %s, but there is %d values.",
383              name,
384              cell->max,
385              gras_cfgelm_type_name[cell->type],
386              size);
387       return mismatch_error;
388     }
389
390   }
391
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   gras_error_t errcode;
400
401   TRYCATCH(mismatch_error,gras_dict_retrieve((gras_dict_t*)cfg,name,(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
409   gras_assert3((*whereto)->type == type,
410                "You tried to access to the config element %s as an %s, but its type is %s.",
411                name,
412                gras_cfgelm_type_name[type],
413                gras_cfgelm_type_name[(*whereto)->type]);
414
415   return no_error;
416 }
417
418 /**
419  * gras_cfg_get_type:
420  *
421  * @cfg: the config set
422  * @name: the name of the element 
423  * @type: the result
424  *
425  * Give the type of the config element
426  */
427
428 gras_error_t
429 gras_cfg_get_type(gras_cfg_t *cfg, const char *name, 
430                       /* OUT */gras_cfgelm_type_t *type) {
431
432   gras_cfgelm_t *cell;
433   gras_error_t errcode;
434
435   TRYCATCH(mismatch_error,gras_dict_retrieve((gras_dict_t*)cfg,name,(void**)&cell));
436
437   if (errcode == mismatch_error) {
438     ERROR1("Can't get the type of '%s' since this cell does not exist",
439            name);
440     return mismatch_error;
441   }
442
443   *type=cell->type;
444
445   return no_error;
446 }
447
448 /*----[ Setting ]---------------------------------------------------------*/
449 /** 
450  * gras_cfg_set_vargs(): 
451  * @cfg: config set to fill
452  * @varargs: NULL-terminated list of pairs {(const char*)key, value}
453  *
454  * Add some values to the config set.
455  * @warning: if the list isn't NULL terminated, it will segfault. 
456  */
457 gras_error_t
458 gras_cfg_set_vargs(gras_cfg_t *cfg, va_list pa) {
459   char *str,*name;
460   int i;
461   double d;
462   gras_cfgelm_type_t type;
463
464   gras_error_t errcode;
465   
466   while ((name=va_arg(pa,char *))) {
467
468     if (!gras_cfg_get_type(cfg,name,&type)) {
469       ERROR1("Can't set the property '%s' since it's not registered",name);
470       return mismatch_error;
471     }
472
473     switch (type) {
474     case gras_cfgelm_host:
475       str = va_arg(pa, char *);
476       i=va_arg(pa,int);
477       TRY(gras_cfg_set_host(cfg,name,str,i));
478       break;
479       
480     case gras_cfgelm_string:
481       str=va_arg(pa, char *);
482       TRY(gras_cfg_set_string(cfg, name, str));
483       break;
484
485     case gras_cfgelm_int:
486       i=va_arg(pa,int);
487       TRY(gras_cfg_set_int(cfg,name,i));
488       break;
489
490     case gras_cfgelm_double:
491       d=va_arg(pa,double);
492       TRY(gras_cfg_set_double(cfg,name,d));
493       break;
494
495     default: 
496       RAISE1(unknown_error,"Config element cell %s not valid.",name);
497     }
498   }
499   return no_error;
500 }
501
502 /** 
503  * gras_cfg_set():
504  * @cfg: config set to fill
505  * @varargs: NULL-terminated list of pairs {(const char*)key, value}
506  *
507  * Add some values to the config set.
508  * @warning: if the list isn't NULL terminated, it will segfault. 
509  */
510 gras_error_t gras_cfg_set(gras_cfg_t *cfg, ...) {
511   va_list pa;
512   gras_error_t errcode;
513
514   va_start(pa,cfg);
515   errcode=gras_cfg_set_vargs(cfg,pa);
516   va_end(pa);
517   return errcode;
518 }
519
520 /**
521  * gras_cfg_set_parse():
522  * @cfg: config set to fill
523  * @options: a string containing the content to add to the config set. This
524  * is a '\t',' ' or '\n' separated list of cells. Each individual cell is
525  * like "[name]:[value]" where [name] is the name of an already registred 
526  * cell, and [value] conforms to the data type under which this cell was
527  * registred.
528  *
529  * Add the cells described in a string to a config set.
530  */
531
532 gras_error_t
533 gras_cfg_set_parse(gras_cfg_t *cfg, const char *options) {
534   int i;
535   double d;
536   char *str;
537
538   gras_cfgelm_t *cell;
539   char *optionlist_cpy;
540   char *option,  *name,*val;
541
542   int len;
543   gras_error_t errcode;
544
545   if (!options || !strlen(options)) { /* nothing to do */
546     return no_error;
547   }
548   optionlist_cpy=strdup(options);
549
550   DEBUG1("Options list='%s'",options);
551   option=optionlist_cpy;
552   while (1) { /* breaks in the code */
553
554     if (!option) 
555       break;
556     name=option;
557     len=strlen(name);
558     DEBUG3("Parse list '%s'. len=%d; option-name=%d",name,len,option-name);
559
560     /* Pass the value */
561     while (option-name<=(len-1) && *option != ' ' && *option != '\n' && *option != '\t') {
562       //fprintf(stderr,"Take %c.\n",*option);
563       option++;
564     }
565     if (option-name == len) {
566       //fprintf(stderr,"Boundary=EOL\n");
567       option=NULL; /* don't do next iteration */
568
569     } else {
570       //fprintf(stderr,"Boundary on '%c'. len=%d;option-name=%d\n",*option,len,option-name);
571
572       /* Pass the following blank chars */
573       *(option++)='\0';
574       while (option-name<(len-1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
575         //      fprintf(stderr,"Ignore a blank char.\n");
576         option++;
577       }
578       if (option-name == len-1)
579         option=NULL; /* don't do next iteration */
580     }
581     DEBUG2("this='%s';rest='%s'",name,option);
582
583     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
584       continue;
585     if (!strlen(name))
586       break;
587     
588     val=strchr(name,':');
589     if (!val) {
590       free(optionlist_cpy);
591       gras_assert1(FALSE,
592                    "Malformated option: '%s'; Should be of the form 'name:value'",
593                    name);
594     }
595     *(val++)='\0';
596
597     DEBUG2("name='%s';val='%s'",name,val);
598
599     errcode=gras_dict_retrieve((gras_dict_t*)cfg,name,(void**)&cell);
600     switch (errcode) {
601     case no_error:
602       break;
603     case mismatch_error:
604       ERROR1("No registrated cell corresponding to '%s'.",name);
605       free(optionlist_cpy);
606       return mismatch_error;
607       break;
608     default:
609       free(optionlist_cpy);
610       return errcode;
611     }
612
613     switch (cell->type) {
614     case gras_cfgelm_string:
615       TRYCLEAN(gras_cfg_set_string(cfg, name, val),
616                free(optionlist_cpy));
617       break;
618
619     case gras_cfgelm_int:
620       i=strtol(val, &val, 0);
621       if (val==NULL) {
622         free(optionlist_cpy);   
623         gras_assert1(FALSE,
624                      "Value of option %s not valid. Should be an integer",
625                      name);
626       }
627
628       TRYCLEAN(gras_cfg_set_int(cfg,name,i),
629                free(optionlist_cpy));
630       break;
631
632     case gras_cfgelm_double:
633       d=strtod(val, &val);
634       if (val==NULL) {
635         free(optionlist_cpy);   
636         gras_assert1(FALSE,
637                "Value of option %s not valid. Should be a double",
638                name);
639       }
640
641       TRYCLEAN(gras_cfg_set_double(cfg,name,d),
642                free(optionlist_cpy));
643       break;
644
645     case gras_cfgelm_host:
646       str=val;
647       val=strchr(val,':');
648       if (!val) {
649         free(optionlist_cpy);   
650         gras_assert1(FALSE,
651                "Value of option %s not valid. Should be an host (machine:port)",
652                name);
653       }
654
655       *(val++)='\0';
656       i=strtol(val, &val, 0);
657       if (val==NULL) {
658         free(optionlist_cpy);   
659         gras_assert1(FALSE,
660                "Value of option %s not valid. Should be an host (machine:port)",
661                name);
662       }
663
664       TRYCLEAN(gras_cfg_set_host(cfg,name,str,i),
665                free(optionlist_cpy));
666       break;      
667
668     default: 
669       free(optionlist_cpy);
670       RAISE1(unknown_error,"Type of config element %s is not valid.",name);
671     }
672     
673   }
674   free(optionlist_cpy);
675   return no_error;
676 }
677
678 /**
679  * gras_cfg_set_int:
680  *
681  * @cfg: the config set
682  * @name: the name of the cell
683  * @val: the value of the cell
684  *
685  * Set the value of the cell @name in @cfg with the provided value.
686  */ 
687 gras_error_t
688 gras_cfg_set_int(gras_cfg_t *cfg,const char*name, int val) {
689   gras_cfgelm_t *cell;
690   gras_error_t errcode;
691
692   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
693
694   if (cell->max > 1) {
695     return gras_dynar_push(cell->content,&val);
696   } else {
697     return gras_dynar_set(cell->content,0,&val);
698   }
699 }
700
701 /**
702  * gras_cfg_set_double:
703  * @cfg: the config set
704  * @name: the name of the cell
705  * @val: the doule to set
706  * 
707  * Set the value of the cell @name in @cfg with the provided value.
708  */ 
709
710 gras_error_t
711 gras_cfg_set_double(gras_cfg_t *cfg,const char*name, double val) {
712   gras_cfgelm_t *cell;
713   gras_error_t errcode;
714
715   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
716
717   if (cell->max > 1) {
718     return gras_dynar_push(cell->content,&val);
719   } else {
720     return gras_dynar_set(cell->content,0,&val);
721   }
722 }
723
724 /**
725  * gras_cfg_set_string:
726  * 
727  * @cfg: the config set
728  * @name: the name of the cell
729  * @val: the value to be added
730  *
731  * Set the value of the cell @name in @cfg with the provided value.
732  */ 
733
734 gras_error_t
735 gras_cfg_set_string(gras_cfg_t *cfg,const char*name, const char*val) { 
736   gras_cfgelm_t *cell;
737   gras_error_t errcode;
738
739   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
740
741   if (cell->max > 1) {
742     return gras_dynar_push(cell->content,&val);
743   } else {
744     return gras_dynar_set(cell->content,0,&val);
745   }
746 }
747
748 /**
749  * gras_cfg_set_host:
750  * 
751  * @cfg: the config set
752  * @name: the name of the cell
753  * @host: the host
754  * @port: the port number
755  *
756  * Set the value of the cell @name in @cfg with the provided value 
757  * on the given @host to the given @port
758  */ 
759
760 gras_error_t 
761 gras_cfg_set_host(gras_cfg_t *cfg,const char*name, 
762                   const char *host,int port) {
763   gras_cfgelm_t *cell;
764   gras_error_t errcode;
765   gras_host_t *val=malloc(sizeof(gras_host_t));
766
767   if (!val)
768     RAISE_MALLOC;
769   val->name = strdup(name);
770   val->port = port;
771
772   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
773
774   if (cell->max > 1) {
775     return gras_dynar_push(cell->content,&val);
776   } else {
777     return gras_dynar_set(cell->content,0,&val);
778   }
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_retrieve((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 %d values\n",
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 %d 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 %d 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 %d 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;
1083
1084   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
1085   *dynar = cell->content;
1086   return no_error;
1087 }
1088