Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Some work to get it ansi compliant, still much to doo
[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=(char*)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=(char*)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=%ld",
562            name,len,(long)(option-name));
563
564     /* Pass the value */
565     while (option-name<=(len-1) && *option != ' ' && *option != '\n' && *option != '\t') {
566       /*fprintf(stderr,"Take %c.\n",*option);*/
567       option++;
568     }
569     if (option-name == len) {
570       /*fprintf(stderr,"Boundary=EOL\n");*/
571       option=NULL; /* don't do next iteration */
572
573     } else {
574       /*fprintf(stderr,"Boundary on '%c'. len=%d;option-name=%d\n",*option,len,option-name);*/
575
576       /* Pass the following blank chars */
577       *(option++)='\0';
578       while (option-name<(len-1) && (*option == ' ' || *option == '\n' || *option == '\t')) {
579         /*      fprintf(stderr,"Ignore a blank char.\n");*/
580         option++;
581       }
582       if (option-name == len-1)
583         option=NULL; /* don't do next iteration */
584     }
585     DEBUG2("parse now:'%s'; parse later:'%s'",name,option);
586
587     if (name[0] == ' ' || name[0] == '\n' || name[0] == '\t')
588       continue;
589     if (!strlen(name))
590       break;
591     
592     val=strchr(name,':');
593     if (!val) {
594       gras_free(optionlist_cpy);
595       gras_assert1(FALSE,
596                    "Malformated option: '%s'; Should be of the form 'name:value'",
597                    name);
598     }
599     *(val++)='\0';
600
601     DEBUG2("name='%s';val='%s'",name,val);
602
603     errcode=gras_dict_get((gras_dict_t*)cfg,name,(void**)&cell);
604     switch (errcode) {
605     case no_error:
606       break;
607     case mismatch_error:
608       ERROR1("No registrated cell corresponding to '%s'.",name);
609       gras_free(optionlist_cpy);
610       return mismatch_error;
611       break;
612     default:
613       gras_free(optionlist_cpy);
614       return errcode;
615     }
616
617     switch (cell->type) {
618     case gras_cfgelm_string:
619       TRYCLEAN(gras_cfg_set_string(cfg, name, val),
620                gras_free(optionlist_cpy));
621       break;
622
623     case gras_cfgelm_int:
624       i=strtol(val, &val, 0);
625       if (val==NULL) {
626         gras_free(optionlist_cpy);      
627         gras_assert1(FALSE,
628                      "Value of option %s not valid. Should be an integer",
629                      name);
630       }
631
632       TRYCLEAN(gras_cfg_set_int(cfg,name,i),
633                gras_free(optionlist_cpy));
634       break;
635
636     case gras_cfgelm_double:
637       d=strtod(val, &val);
638       if (val==NULL) {
639         gras_free(optionlist_cpy);      
640         gras_assert1(FALSE,
641                "Value of option %s not valid. Should be a double",
642                name);
643       }
644
645       TRYCLEAN(gras_cfg_set_double(cfg,name,d),
646                gras_free(optionlist_cpy));
647       break;
648
649     case gras_cfgelm_host:
650       str=val;
651       val=strchr(val,':');
652       if (!val) {
653         gras_free(optionlist_cpy);      
654         gras_assert1(FALSE,
655                "Value of option %s not valid. Should be an host (machine:port)",
656                name);
657       }
658
659       *(val++)='\0';
660       i=strtol(val, &val, 0);
661       if (val==NULL) {
662         gras_free(optionlist_cpy);      
663         gras_assert1(FALSE,
664                "Value of option %s not valid. Should be an host (machine:port)",
665                name);
666       }
667
668       TRYCLEAN(gras_cfg_set_host(cfg,name,str,i),
669                gras_free(optionlist_cpy));
670       break;      
671
672     default: 
673       gras_free(optionlist_cpy);
674       RAISE1(unknown_error,"Type of config element %s is not valid.",name);
675     }
676     
677   }
678   gras_free(optionlist_cpy);
679   return no_error;
680 }
681
682 /**
683  * gras_cfg_set_int:
684  *
685  * @cfg: the config set
686  * @name: the name of the cell
687  * @val: the value of the cell
688  *
689  * Set the value of the cell @name in @cfg with the provided value.
690  */ 
691 gras_error_t
692 gras_cfg_set_int(gras_cfg_t *cfg,const char*name, int val) {
693   gras_cfgelm_t *cell;
694   gras_error_t errcode;
695
696   VERB2("Configuration setting: %s=%d",name,val);
697   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
698
699   if (cell->max > 1) {
700     return gras_dynar_push(cell->content,&val);
701   } else {
702     return gras_dynar_set(cell->content,0,&val);
703   }
704 }
705
706 /**
707  * gras_cfg_set_double:
708  * @cfg: the config set
709  * @name: the name of the cell
710  * @val: the doule to set
711  * 
712  * Set the value of the cell @name in @cfg with the provided value.
713  */ 
714
715 gras_error_t
716 gras_cfg_set_double(gras_cfg_t *cfg,const char*name, double val) {
717   gras_cfgelm_t *cell;
718   gras_error_t errcode;
719
720   VERB2("Configuration setting: %s=%f",name,val);
721   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
722
723   if (cell->max > 1) {
724     return gras_dynar_push(cell->content,&val);
725   } else {
726     return gras_dynar_set(cell->content,0,&val);
727   }
728 }
729
730 /**
731  * gras_cfg_set_string:
732  * 
733  * @cfg: the config set
734  * @name: the name of the cell
735  * @val: the value to be added
736  *
737  * Set the value of the cell @name in @cfg with the provided value.
738  */ 
739
740 gras_error_t
741 gras_cfg_set_string(gras_cfg_t *cfg,const char*name, const char*val) { 
742   gras_cfgelm_t *cell;
743   gras_error_t errcode;
744   char *newval = (char*)strdup(val);
745
746   VERB2("Configuration setting: %s=%s",name,val);
747   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
748
749   if (cell->max > 1) {
750     return gras_dynar_push(cell->content,&newval);
751   } else {
752     return gras_dynar_set(cell->content,0,&newval);
753   }
754 }
755
756 /**
757  * gras_cfg_set_host:
758  * 
759  * @cfg: the config set
760  * @name: the name of the cell
761  * @host: the host
762  * @port: the port number
763  *
764  * Set the value of the cell @name in @cfg with the provided value 
765  * on the given @host to the given @port
766  */ 
767
768 gras_error_t 
769 gras_cfg_set_host(gras_cfg_t *cfg,const char*name, 
770                   const char *host,int port) {
771   gras_cfgelm_t *cell;
772   gras_error_t errcode;
773   gras_host_t *val=gras_new(gras_host_t,1);
774
775   VERB3("Configuration setting: %s=%s:%d",name,host,port);
776   if (!val)
777     RAISE_MALLOC;
778   val->name = (char*)strdup(name);
779   val->port = port;
780
781   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
782
783   if (cell->max > 1) {
784     return gras_dynar_push(cell->content,&val);
785   } else {
786     return gras_dynar_set(cell->content,0,&val);
787   }
788 }
789
790 /* ---- [ Removing ] ---- */
791
792 /**
793  * gras_cfg_rm_int:
794  *
795  * @cfg: the config set
796  * @name: the name of the cell
797  * @val: the value to be removed
798  *
799  * Remove the provided @val from the cell @name in @cfg.
800  */
801 gras_error_t gras_cfg_rm_int   (gras_cfg_t *cfg,const char*name, int val) {
802
803   gras_cfgelm_t *cell;
804   int cpt,seen;
805   gras_error_t errcode;
806
807   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
808   
809   gras_dynar_foreach(cell->content,cpt,seen) {
810     if (seen == val) {
811       gras_dynar_cursor_rm(cell->content,&cpt);
812       return no_error;
813     }
814   }
815
816   ERROR2("Can't remove the value %d of config element %s: value not found.",
817          val,name);
818   return mismatch_error;
819 }
820
821 /**
822  * gras_cfg_rm_double:
823  *
824  * @cfg: the config set
825  * @name: the name of the cell
826  * @val: the value to be removed
827  *
828  * Remove the provided @val from the cell @name in @cfg.
829  */
830
831 gras_error_t gras_cfg_rm_double(gras_cfg_t *cfg,const char*name, double val) {
832   gras_cfgelm_t *cell;
833   int cpt;
834   double seen;
835   gras_error_t errcode;
836
837   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
838   
839   gras_dynar_foreach(cell->content,cpt,seen) {
840     if (seen == val) {
841       gras_dynar_cursor_rm(cell->content,&cpt);
842       return no_error;
843     }
844   }
845
846   ERROR2("Can't remove the value %f of config element %s: value not found.",
847          val,name);
848   return mismatch_error;
849 }
850
851 /**
852  * gras_cfg_rm_string:
853  *
854  * @cfg: the config set
855  * @name: the name of the cell
856  * @val: the value of the string which will be removed
857  *
858  * Remove the provided @val from the cell @name in @cfg.
859  */
860 gras_error_t
861 gras_cfg_rm_string(gras_cfg_t *cfg,const char*name, const char *val) {
862   gras_cfgelm_t *cell;
863   int cpt;
864   char *seen;
865   gras_error_t errcode;
866
867   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
868   
869   gras_dynar_foreach(cell->content,cpt,seen) {
870     if (!strcpy(seen,val)) {
871       gras_dynar_cursor_rm(cell->content,&cpt);
872       return no_error;
873     }
874   }
875
876   ERROR2("Can't remove the value %s of config element %s: value not found.",
877          val,name);
878   return mismatch_error;
879 }
880
881 /**
882  * gras_cfg_rm_host:
883  * 
884  * @cfg: the config set
885  * @name: the name of the cell
886  * @host: the hostname
887  * @port: the port number
888  *
889  * Remove the provided @host:@port from the cell @name in @cfg.
890  */
891
892 gras_error_t
893 gras_cfg_rm_host  (gras_cfg_t *cfg,const char*name, const char *host,int port) {
894   gras_cfgelm_t *cell;
895   int cpt;
896   gras_host_t *seen;
897   gras_error_t errcode;
898
899   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
900   
901   gras_dynar_foreach(cell->content,cpt,seen) {
902     if (!strcpy(seen->name,host) && seen->port == port) {
903       gras_dynar_cursor_rm(cell->content,&cpt);
904       return no_error;
905     }
906   }
907
908   ERROR3("Can't remove the value %s:%d of config element %s: value not found.",
909          host,port,name);
910   return mismatch_error;
911 }
912
913 /* rm everything */
914
915 /**
916  * gras_cfg_empty:
917  * 
918  * @cfg: the config set
919  * @name: the name of the cell
920  *
921  * rm evenything
922  */
923
924 gras_error_t 
925 gras_cfg_empty(gras_cfg_t *cfg,const char*name) {
926   gras_cfgelm_t *cell;
927
928   gras_error_t errcode;
929
930   TRYCATCH(mismatch_error,
931            gras_dict_get((gras_dict_t*)cfg,name,(void**)&cell));
932   if (errcode == mismatch_error) {
933     ERROR1("Can't empty  '%s' since this config element does not exist",
934            name);
935     return mismatch_error;
936   }
937
938   if (cell) {
939     gras_dynar_reset(cell->content);
940   }
941   return no_error;
942 }
943
944 /*----[ Getting ]---------------------------------------------------------*/
945
946 /**
947  * gras_cfg_get_int:
948  * @cfg: the config set
949  * @name: the name of the cell
950  * @val: the wanted value
951  *
952  * Returns the first value from the config set under the given name.
953  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
954  * instead.
955  *
956  * @warning the returned value is the actual content of the config set
957  */
958 gras_error_t
959 gras_cfg_get_int   (gras_cfg_t  *cfg, 
960                     const char *name,
961                     int        *val) {
962   gras_cfgelm_t *cell;
963   gras_error_t errcode;
964
965   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_int,&cell));
966
967   if (gras_dynar_length(cell->content) > 1) {
968     WARN2("You asked for the first value of the config element '%s', but there is %lu values",
969              name, gras_dynar_length(cell->content));
970   }
971
972   gras_dynar_get(cell->content, 0, (void*)val);
973   return no_error;
974 }
975
976 /**
977  * gras_cfg_get_double:
978  * @cfg: the config set
979  * @name: the name of the cell
980  * @val: the wanted value
981  *
982  * Returns the first value from the config set under the given name.
983  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
984  * instead.
985  *
986  * @warning the returned value is the actual content of the config set
987  */
988
989 gras_error_t
990 gras_cfg_get_double(gras_cfg_t *cfg,
991                     const char *name,
992                     double     *val) {
993   gras_cfgelm_t *cell;
994   gras_error_t errcode;
995
996   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_double,&cell));
997
998   if (gras_dynar_length(cell->content) > 1) {
999     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
1000              name, gras_dynar_length(cell->content));
1001   }
1002
1003   gras_dynar_get(cell->content, 0, (void*)val);
1004   return no_error;
1005 }
1006
1007 /**
1008  * gras_cfg_get_string:
1009  *
1010  * @th: the config set
1011  * @name: the name of the cell
1012  * @val: the wanted value
1013  *
1014  * Returns the first value from the config set under the given name.
1015  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
1016  * instead.
1017  *
1018  * @warning the returned value is the actual content of the config set
1019  */
1020
1021 gras_error_t gras_cfg_get_string(gras_cfg_t *cfg,
1022                                  const char *name,
1023                                  char      **val) {
1024   gras_cfgelm_t *cell;
1025   gras_error_t errcode;
1026
1027   *val=NULL;
1028
1029   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_string,&cell));
1030
1031   if (gras_dynar_length(cell->content) > 1) {
1032     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
1033              name, gras_dynar_length(cell->content));
1034   }
1035
1036   gras_dynar_get(cell->content, 0, (void*)val);
1037   return no_error;
1038 }
1039
1040 /**
1041  * gras_cfg_get_host:
1042  *
1043  * @cfg: the config set
1044  * @name: the name of the cell
1045  * @host: the host
1046  * @port: the port number
1047  *
1048  * Returns the first value from the config set under the given name.
1049  * If there is more than one value, it will issue a warning. Consider using gras_cfg_get_dynar() 
1050  * instead.
1051  *
1052  * @warning the returned value is the actual content of the config set
1053  */
1054
1055 gras_error_t gras_cfg_get_host  (gras_cfg_t *cfg,
1056                                  const char *name,
1057                                  char      **host,
1058                                  int        *port) {
1059   gras_cfgelm_t *cell;
1060   gras_error_t errcode;
1061   gras_host_t *val;
1062
1063   TRY (gras_cfgelm_get(cfg,name,gras_cfgelm_host,&cell));
1064
1065   if (gras_dynar_length(cell->content) > 1) {
1066     WARN2("You asked for the first value of the config element '%s', but there is %lu values\n",
1067              name, gras_dynar_length(cell->content));
1068   }
1069
1070   gras_dynar_get(cell->content, 0, (void*)val);
1071   *host=val->name;
1072   *port=val->port;
1073   
1074   return no_error;
1075 }
1076
1077 /**
1078  * gras_cfg_get_dynar:
1079  * @cfg: where to search in
1080  * @name: what to search for
1081  * @dynar: result
1082  *
1083  * Get the data stored in the config bag. 
1084  *
1085  * @warning the returned value is the actual content of the config set
1086  */
1087 gras_error_t gras_cfg_get_dynar (gras_cfg_t    *cfg,
1088                                  const char    *name,
1089                                  gras_dynar_t **dynar) {
1090   gras_cfgelm_t *cell;
1091   gras_error_t errcode = gras_dict_get((gras_dict_t*)cfg,name,
1092                                        (void**)&cell);
1093
1094   if (errcode == mismatch_error) {
1095     ERROR1("No registered cell %s in this config set",
1096            name);
1097     return mismatch_error;
1098   }
1099   if (errcode != no_error)
1100      return errcode;
1101
1102   *dynar = cell->content;
1103   return no_error;
1104 }
1105