Logo AND Algorithmique Numérique Distribuée

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