CFG_SIMPLE_INT on 64bit machine

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

CFG_SIMPLE_INT on 64bit machine

Martin Hömberg
Hello.

First and foremost: Thank you very much for producing such a helpful
library as libconfuse. I am using it to configure a small molecular
dynamics program, that I have written for my PhD in physics. It worked
great so far. However, I am now experiencing a small problem. I am not
sure, if you consider this as being a bug, but it took me half a day to
figure out what is going on.

The problem is that the name "CFG_SIMPLE_INT" suggests, that it operates
on an "int", but in fact it operates on a "long". On my 64bit machine
(Intel(R) Xeon(R) CPU E5420  @ 2.50GHz), sizeof(int)==4 and
sizeof(long)==8. If I now use CFG_SIMPLE_INT() on an int, and there is
something else stored in memory behind this int, it gets overwritten by
CFG_SIMPLE_INT().

The problem can be illustrated by the following code, where a[0] is
changed by an option, but a[1] should remain constant which it does not
in my case.

------------------------------------------
#include <stdio.h>
#include <confuse.h>

static int a[2] = {0, 4};

static cfg_opt_t opts[] = {
        CFG_SIMPLE_INT("b", &a[0]),
        CFG_END()
};

int main(int argc, char **argv)
{
        cfg_t *cfg;

        printf("1. a=%d b=%d\n", a[0], a[1]);

        cfg = cfg_init(opts, CFGF_NOCASE);
        if (cfg_parse(cfg, "config.txt")) {
                printf("Couldn't read config.txt. Goodbye.\n");
                return 1;
        }
       
        printf("2. a=%d b=%d\n", a[0], a[1]);

        return 0;
}
------------------------------------------

The configuration looks like this:
------------------------------------------
b = 25
------------------------------------------

The output looks like this:
------------------------------------------
hicegate1:~/test $ gcc confusebug.c -o bug -I../local/include
-L../local/lib -lconfuse -O2
hicegate1:~/test $ ./bug
1. a=0 b=4
2. a=25 b=0
------------------------------------------


If you consider this as a bug, then please fix it. If not, then it is
worth mentioning on your website. If you need further information about
my software/hardware then please let me know.


Best wishes from Göttingen, Germany,


Martin Hömberg







_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Carlo Marcelo Arenas Belon
On Sat, Apr 24, 2010 at 04:09:53PM +0200, Martin H?mberg wrote:
>
> If you consider this as a bug, then please fix it. If not, then it is
> worth mentioning on your website.

agree this should be on some FAQ but a google search for CFG_SIMPLE_INT
still shows the following warning as the first link :
 
  http://www.mail-archive.com/confuse-devel@.../msg00084.html

the changes required to use CFG_INT instead for your bug program and as
recommended in the tutorial/examples are inlined below and are minimal :

  http://www.nongnu.org/confuse/tutorial-html/ar01s02.html
  http://git.savannah.gnu.org/cgit/confuse.git/tree/examples/simple.c

Carlo

PS. throwing a warning when CFG_SIMPLE_INT is used in this buggy context
    might be better.

--- bug.c 2010-04-25 06:32:11.000000000 +0000
+++ bug2.c 2010-04-25 06:37:46.000000000 +0000
@@ -4,7 +4,7 @@
 static int a[2] = {0, 4};
 
 static cfg_opt_t opts[] = {
-        CFG_SIMPLE_INT("b", &a[0]),
+        CFG_INT("b", 0, CFGF_NONE),
         CFG_END()
 };
 
@@ -19,6 +19,7 @@
                 printf("Couldn't read config.txt. Goodbye.\n");
                 return 1;
         }
+        a[0] = cfg_getint(cfg, "b");
 
         printf("2. a=%d b=%d\n", a[0], a[1]);
 


_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

ohnobinki
On Sun, Apr 25, 2010 at 06:48:41AM +0000, Carlo Marcelo Arenas Belon wrote:
> On Sat, Apr 24, 2010 at 04:09:53PM +0200, Martin H?mberg wrote:
> >
> > If you consider this as a bug, then please fix it. If not, then it is
> > worth mentioning on your website.
>
> agree this should be on some FAQ

Howabout the following, which would show up in the API docs?

diff --git a/src/confuse.h b/src/confuse.h
index 69215b1..65b5b07 100644
--- a/src/confuse.h
+++ b/src/confuse.h
@@ -384,6 +384,9 @@ extern const char __export confuse_author[];
 
 /** Initialize a "simple" integer option (see documentation for
  * CFG_SIMPLE_STR for more information).
+ * Note that confuse uses long integers, so make sure that any pointer
+ * you provide for svalue points to a long int rather than a normal int.
+ * Otherwise, you will have strange problems on 64-bit architectures.
  */
 #define CFG_SIMPLE_INT(name, svalue) \
   __CFG_INT(name, 0, CFGF_NONE, svalue, 0)

--
ohnobinki

Look out for missing apostrophes!

_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel

attachment0 (205 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Martin Hedenfalk-4
29 apr 2010 kl. 04.16 skrev Nathan Phillip Brink:

> On Sun, Apr 25, 2010 at 06:48:41AM +0000, Carlo Marcelo Arenas Belon wrote:
>> On Sat, Apr 24, 2010 at 04:09:53PM +0200, Martin H?mberg wrote:
>>>
>>> If you consider this as a bug, then please fix it. If not, then it is
>>> worth mentioning on your website.
>>
>> agree this should be on some FAQ
>
> Howabout the following, which would show up in the API docs?

That sounds reasonably.

Ideally, the compiler should issue a warning, but liconfuse uses a void * for the svalue field, so any type errors are cast away, unfortunately. It would be better to use a union with proper pointer types for the simple value. Patches welcome :-)

        -martin

> diff --git a/src/confuse.h b/src/confuse.h
> index 69215b1..65b5b07 100644
> --- a/src/confuse.h
> +++ b/src/confuse.h
> @@ -384,6 +384,9 @@ extern const char __export confuse_author[];
>
> /** Initialize a "simple" integer option (see documentation for
>  * CFG_SIMPLE_STR for more information).
> + * Note that confuse uses long integers, so make sure that any pointer
> + * you provide for svalue points to a long int rather than a normal int.
> + * Otherwise, you will have strange problems on 64-bit architectures.
>  */
> #define CFG_SIMPLE_INT(name, svalue) \
>   __CFG_INT(name, 0, CFGF_NONE, svalue, 0)
>
> --
> ohnobinki
>
> Look out for missing apostrophes!
> _______________________________________________
> Confuse-devel mailing list
> [hidden email]
> http://lists.nongnu.org/mailman/listinfo/confuse-devel



_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Carlo Marcelo Arenas Belon
On Thu, Apr 29, 2010 at 06:31:19AM +0200, Martin Hedenfalk wrote:
> It would be better to use a union with proper pointer types for the
> simple value. Patches welcome :-)

Comments welcome ;), and at least gets read of all casts and lets the
compiler do the type checking as suggested.

Some known caveats :

* union initializer would require C99 like support in the compiler
* all non type specific checks are using the pointer type
* use of union type should be ABI compatible but not tested
* cfg_simple_t could be avoided if using instead cfg_value_t* but that
  would require more code changes and would be ABI incompatible

Carlo
---
From 97ae9e8d7d1771e0a2bb38bc7d719bfe431f7c60 Mon Sep 17 00:00:00 2001
From: Carlo Marcelo Arenas Belon <[hidden email]>
Date: Thu, 29 Apr 2010 01:48:31 -0700
Subject: [PATCH] simple: use union instead of void*

---
 src/confuse.c |   34 +++++++++++++++++-----------------
 src/confuse.h |   40 ++++++++++++++++++++++++++--------------
 2 files changed, 43 insertions(+), 31 deletions(-)

diff --git a/src/confuse.c b/src/confuse.c
index be1bf5e..60d77a5 100644
--- a/src/confuse.c
+++ b/src/confuse.c
@@ -210,8 +210,8 @@ DLLIMPORT signed long cfg_opt_getnint(cfg_opt_t *opt, unsigned int index)
     assert(opt && opt->type == CFGT_INT);
     if(opt->values && index < opt->nvalues)
         return opt->values[index]->number;
-    else if(opt->simple_value)
-        return *(signed long *)opt->simple_value;
+    else if(opt->simple_value.number)
+        return *opt->simple_value.number;
     else
         return 0;
 }
@@ -232,8 +232,8 @@ DLLIMPORT double cfg_opt_getnfloat(cfg_opt_t *opt, unsigned int index)
     assert(opt && opt->type == CFGT_FLOAT);
     if(opt->values && index < opt->nvalues)
         return opt->values[index]->fpnumber;
-    else if(opt->simple_value)
-        return *(double *)opt->simple_value;
+    else if(opt->simple_value.fpnumber)
+        return *opt->simple_value.fpnumber;
     else
         return 0;
 }
@@ -254,8 +254,8 @@ DLLIMPORT cfg_bool_t cfg_opt_getnbool(cfg_opt_t *opt, unsigned int index)
     assert(opt && opt->type == CFGT_BOOL);
     if(opt->values && index < opt->nvalues)
         return opt->values[index]->boolean;
-    else if(opt->simple_value)
-        return *(cfg_bool_t *)opt->simple_value;
+    else if(opt->simple_value.boolean)
+        return *opt->simple_value.boolean;
     else
         return cfg_false;
 }
@@ -276,8 +276,8 @@ DLLIMPORT char *cfg_opt_getnstr(cfg_opt_t *opt, unsigned int index)
     assert(opt && opt->type == CFGT_STR);
     if(opt->values && index < opt->nvalues)
         return opt->values[index]->string;
-    else if(opt->simple_value)
-        return *(char **)opt->simple_value;
+    else if(opt->simple_value.string)
+        return *opt->simple_value.string;
     else
         return 0;
 }
@@ -297,8 +297,8 @@ DLLIMPORT void *cfg_opt_getnptr(cfg_opt_t *opt, unsigned int index)
     assert(opt && opt->type == CFGT_PTR);
     if(opt->values && index < opt->nvalues)
         return opt->values[index]->ptr;
-    else if(opt->simple_value)
-        return *(void **)opt->simple_value;
+    else if(opt->simple_value.ptr)
+        return *opt->simple_value.ptr;
     else
         return 0;
 }
@@ -425,7 +425,7 @@ static void cfg_init_defaults(cfg_t *cfg)
     for(i = 0; cfg->opts[i].name; i++)
     {
         /* libConfuse doesn't handle default values for "simple" options */
-        if(cfg->opts[i].simple_value || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
+        if(cfg->opts[i].simple_value.ptr || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
             continue;
 
         if(cfg->opts[i].type != CFGT_SEC)
@@ -539,10 +539,10 @@ cfg_setopt(cfg_t *cfg, cfg_opt_t *opt, char *value)
 
     assert(cfg && opt);
 
-    if(opt->simple_value)
+    if(opt->simple_value.ptr)
     {
         assert(opt->type != CFGT_SEC);
-        val = (cfg_value_t *)opt->simple_value;
+        val = (cfg_value_t *)opt->simple_value.ptr;
     }
     else
     {
@@ -1238,8 +1238,8 @@ static cfg_value_t *cfg_opt_getval(cfg_opt_t *opt, unsigned int index)
 
     assert(index == 0 || is_set(CFGF_LIST, opt->flags));
 
-    if(opt->simple_value)
-        val = (cfg_value_t *)opt->simple_value;
+    if(opt->simple_value.ptr)
+        val = (cfg_value_t *)opt->simple_value.ptr;
     else
     {
         if(is_set(CFGF_RESET, opt->flags))
@@ -1493,9 +1493,9 @@ DLLIMPORT void cfg_opt_print_indent(cfg_opt_t *opt, FILE *fp, int indent)
         {
             cfg_indent(fp, indent);
             /* comment out the option if is not set */
-            if(opt->simple_value)
+            if(opt->simple_value.ptr)
             {
-                if(opt->type == CFGT_STR && *((char **)opt->simple_value) == 0)
+                if(opt->type == CFGT_STR && *opt->simple_value.string == 0)
                     fprintf(fp, "# ");
             }
             else
diff --git a/src/confuse.h b/src/confuse.h
index 69215b1..8b5746b 100644
--- a/src/confuse.h
+++ b/src/confuse.h
@@ -97,6 +97,7 @@ typedef enum cfg_type_t cfg_type_t;
 #define CFG_PARSE_ERROR 1
 
 typedef union cfg_value_t cfg_value_t;
+typedef union cfg_simple_t cfg_simple_t;
 typedef struct cfg_opt_t cfg_opt_t;
 typedef struct cfg_t cfg_t;
 typedef struct cfg_defvalue_t cfg_defvalue_t;
@@ -237,6 +238,17 @@ union cfg_value_t {
     void *ptr;              /**< user-defined value */
 };
 
+/** Data structure holding the pointer to a user provided variable
+ *  defined with CFG_SIMPLE_*
+ */
+union cfg_simple_t {
+    long int *number;
+    double *fpnumber;
+    cfg_bool_t *boolean;
+    char **string;
+    void **ptr;
+};
+
 /** Data structure holding the default value given by the
  *  initialization macros.
  */
@@ -263,7 +275,7 @@ struct cfg_opt_t {
     cfg_opt_t *subopts;     /**< Suboptions (only applies to sections) */
     cfg_defvalue_t def;     /**< Default value */
     cfg_func_t func;        /**< Function callback for CFGT_FUNC options */
-    void *simple_value;     /**< Pointer to user-specified variable to
+    cfg_simple_t simple_value;     /**< Pointer to user-specified variable to
                              * store simple values (created with the
                              * CFG_SIMPLE_* initializers) */
     cfg_callback_t parsecb; /**< Value parsing callback function */
@@ -277,9 +289,9 @@ extern const char __export confuse_version[];
 extern const char __export confuse_author[];
 
 #define __CFG_STR(name, def, flags, svalue, cb) \
-  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,svalue,cb,0,0,0}
+  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,{.string=svalue},cb,0,0,0}
 #define __CFG_STR_LIST(name, def, flags, svalue, cb) \
-  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
+  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.string=svalue},cb,0,0,0}
 
 /** Initialize a string option
  */
@@ -358,9 +370,9 @@ extern const char __export confuse_author[];
 
 
 #define __CFG_INT(name, def, flags, svalue, cb) \
-  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,svalue,cb,0,0,0}
+  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,{.number=svalue},cb,0,0,0}
 #define __CFG_INT_LIST(name, def, flags, svalue, cb) \
-  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
+  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.number=svalue},cb,0,0,0}
 
 /** Initialize an integer option
  */
@@ -391,9 +403,9 @@ extern const char __export confuse_author[];
 
 
 #define __CFG_FLOAT(name, def, flags, svalue, cb) \
-  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,svalue,cb,0,0,0}
+  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,{.fpnumber=svalue},cb,0,0,0}
 #define __CFG_FLOAT_LIST(name, def, flags, svalue, cb) \
-  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
+  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.fpnumber=svalue},cb,0,0,0}
 
 /** Initialize a floating point option
  */
@@ -424,9 +436,9 @@ extern const char __export confuse_author[];
 
 
 #define __CFG_BOOL(name, def, flags, svalue, cb) \
-  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,svalue,cb,0,0,0}
+  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,{.boolean=svalue},cb,0,0,0}
 #define __CFG_BOOL_LIST(name, def, flags, svalue, cb) \
-  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
+  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.boolean=svalue},cb,0,0,0}
 
 /** Initialize a boolean option
  */
@@ -468,7 +480,7 @@ extern const char __export confuse_author[];
  *
  */
 #define CFG_SEC(name, opts, flags) \
-  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,0,0,0,0,0}
+  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
 
 
 
@@ -479,13 +491,13 @@ extern const char __export confuse_author[];
  * @see cfg_func_t
  */
 #define CFG_FUNC(name, func) \
-  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,0,0,0,0,0}
+  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,{0},0,0,0,0}
 
 
 #define __CFG_PTR(name, def, flags, svalue, parsecb, freecb) \
-  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
+  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
 #define __CFG_PTR_LIST(name, def, flags, svalue, parsecb, freecb) \
-  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
+  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
 
 /** Initialize a user-defined option
  *
@@ -515,7 +527,7 @@ extern const char __export confuse_author[];
  * the option list.
  */
 #define CFG_END() \
-   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,0,0,0,0,0}
+   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
 
 
 
--
1.7.0.4



_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Martin Hedenfalk-4
Nice!

Martin, could you please test the patch by Carlo and verify that you indeed get a compiler warning if you pass an int pointer to CFG_SIMPLE_INT?

We should probably still add the comment about int vs long int though.

Thanks
        -martin

29 apr 2010 kl. 11.02 skrev Carlo Marcelo Arenas Belon:

> On Thu, Apr 29, 2010 at 06:31:19AM +0200, Martin Hedenfalk wrote:
>> It would be better to use a union with proper pointer types for the
>> simple value. Patches welcome :-)
>
> Comments welcome ;), and at least gets read of all casts and lets the
> compiler do the type checking as suggested.
>
> Some known caveats :
>
> * union initializer would require C99 like support in the compiler
> * all non type specific checks are using the pointer type
> * use of union type should be ABI compatible but not tested
> * cfg_simple_t could be avoided if using instead cfg_value_t* but that
>  would require more code changes and would be ABI incompatible
>
> Carlo
> ---
> From 97ae9e8d7d1771e0a2bb38bc7d719bfe431f7c60 Mon Sep 17 00:00:00 2001
> From: Carlo Marcelo Arenas Belon <[hidden email]>
> Date: Thu, 29 Apr 2010 01:48:31 -0700
> Subject: [PATCH] simple: use union instead of void*
>
> ---
> src/confuse.c |   34 +++++++++++++++++-----------------
> src/confuse.h |   40 ++++++++++++++++++++++++++--------------
> 2 files changed, 43 insertions(+), 31 deletions(-)
>
> diff --git a/src/confuse.c b/src/confuse.c
> index be1bf5e..60d77a5 100644
> --- a/src/confuse.c
> +++ b/src/confuse.c
> @@ -210,8 +210,8 @@ DLLIMPORT signed long cfg_opt_getnint(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_INT);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->number;
> -    else if(opt->simple_value)
> -        return *(signed long *)opt->simple_value;
> +    else if(opt->simple_value.number)
> +        return *opt->simple_value.number;
>     else
>         return 0;
> }
> @@ -232,8 +232,8 @@ DLLIMPORT double cfg_opt_getnfloat(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_FLOAT);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->fpnumber;
> -    else if(opt->simple_value)
> -        return *(double *)opt->simple_value;
> +    else if(opt->simple_value.fpnumber)
> +        return *opt->simple_value.fpnumber;
>     else
>         return 0;
> }
> @@ -254,8 +254,8 @@ DLLIMPORT cfg_bool_t cfg_opt_getnbool(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_BOOL);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->boolean;
> -    else if(opt->simple_value)
> -        return *(cfg_bool_t *)opt->simple_value;
> +    else if(opt->simple_value.boolean)
> +        return *opt->simple_value.boolean;
>     else
>         return cfg_false;
> }
> @@ -276,8 +276,8 @@ DLLIMPORT char *cfg_opt_getnstr(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_STR);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->string;
> -    else if(opt->simple_value)
> -        return *(char **)opt->simple_value;
> +    else if(opt->simple_value.string)
> +        return *opt->simple_value.string;
>     else
>         return 0;
> }
> @@ -297,8 +297,8 @@ DLLIMPORT void *cfg_opt_getnptr(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_PTR);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->ptr;
> -    else if(opt->simple_value)
> -        return *(void **)opt->simple_value;
> +    else if(opt->simple_value.ptr)
> +        return *opt->simple_value.ptr;
>     else
>         return 0;
> }
> @@ -425,7 +425,7 @@ static void cfg_init_defaults(cfg_t *cfg)
>     for(i = 0; cfg->opts[i].name; i++)
>     {
>         /* libConfuse doesn't handle default values for "simple" options */
> -        if(cfg->opts[i].simple_value || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
> +        if(cfg->opts[i].simple_value.ptr || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
>             continue;
>
>         if(cfg->opts[i].type != CFGT_SEC)
> @@ -539,10 +539,10 @@ cfg_setopt(cfg_t *cfg, cfg_opt_t *opt, char *value)
>
>     assert(cfg && opt);
>
> -    if(opt->simple_value)
> +    if(opt->simple_value.ptr)
>     {
>         assert(opt->type != CFGT_SEC);
> -        val = (cfg_value_t *)opt->simple_value;
> +        val = (cfg_value_t *)opt->simple_value.ptr;
>     }
>     else
>     {
> @@ -1238,8 +1238,8 @@ static cfg_value_t *cfg_opt_getval(cfg_opt_t *opt, unsigned int index)
>
>     assert(index == 0 || is_set(CFGF_LIST, opt->flags));
>
> -    if(opt->simple_value)
> -        val = (cfg_value_t *)opt->simple_value;
> +    if(opt->simple_value.ptr)
> +        val = (cfg_value_t *)opt->simple_value.ptr;
>     else
>     {
>         if(is_set(CFGF_RESET, opt->flags))
> @@ -1493,9 +1493,9 @@ DLLIMPORT void cfg_opt_print_indent(cfg_opt_t *opt, FILE *fp, int indent)
>         {
>             cfg_indent(fp, indent);
>             /* comment out the option if is not set */
> -            if(opt->simple_value)
> +            if(opt->simple_value.ptr)
>             {
> -                if(opt->type == CFGT_STR && *((char **)opt->simple_value) == 0)
> +                if(opt->type == CFGT_STR && *opt->simple_value.string == 0)
>                     fprintf(fp, "# ");
>             }
>             else
> diff --git a/src/confuse.h b/src/confuse.h
> index 69215b1..8b5746b 100644
> --- a/src/confuse.h
> +++ b/src/confuse.h
> @@ -97,6 +97,7 @@ typedef enum cfg_type_t cfg_type_t;
> #define CFG_PARSE_ERROR 1
>
> typedef union cfg_value_t cfg_value_t;
> +typedef union cfg_simple_t cfg_simple_t;
> typedef struct cfg_opt_t cfg_opt_t;
> typedef struct cfg_t cfg_t;
> typedef struct cfg_defvalue_t cfg_defvalue_t;
> @@ -237,6 +238,17 @@ union cfg_value_t {
>     void *ptr;              /**< user-defined value */
> };
>
> +/** Data structure holding the pointer to a user provided variable
> + *  defined with CFG_SIMPLE_*
> + */
> +union cfg_simple_t {
> +    long int *number;
> +    double *fpnumber;
> +    cfg_bool_t *boolean;
> +    char **string;
> +    void **ptr;
> +};
> +
> /** Data structure holding the default value given by the
>  *  initialization macros.
>  */
> @@ -263,7 +275,7 @@ struct cfg_opt_t {
>     cfg_opt_t *subopts;     /**< Suboptions (only applies to sections) */
>     cfg_defvalue_t def;     /**< Default value */
>     cfg_func_t func;        /**< Function callback for CFGT_FUNC options */
> -    void *simple_value;     /**< Pointer to user-specified variable to
> +    cfg_simple_t simple_value;     /**< Pointer to user-specified variable to
>                              * store simple values (created with the
>                              * CFG_SIMPLE_* initializers) */
>     cfg_callback_t parsecb; /**< Value parsing callback function */
> @@ -277,9 +289,9 @@ extern const char __export confuse_version[];
> extern const char __export confuse_author[];
>
> #define __CFG_STR(name, def, flags, svalue, cb) \
> -  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,{.string=svalue},cb,0,0,0}
> #define __CFG_STR_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.string=svalue},cb,0,0,0}
>
> /** Initialize a string option
>  */
> @@ -358,9 +370,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_INT(name, def, flags, svalue, cb) \
> -  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,{.number=svalue},cb,0,0,0}
> #define __CFG_INT_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.number=svalue},cb,0,0,0}
>
> /** Initialize an integer option
>  */
> @@ -391,9 +403,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_FLOAT(name, def, flags, svalue, cb) \
> -  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,{.fpnumber=svalue},cb,0,0,0}
> #define __CFG_FLOAT_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.fpnumber=svalue},cb,0,0,0}
>
> /** Initialize a floating point option
>  */
> @@ -424,9 +436,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_BOOL(name, def, flags, svalue, cb) \
> -  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,{.boolean=svalue},cb,0,0,0}
> #define __CFG_BOOL_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.boolean=svalue},cb,0,0,0}
>
> /** Initialize a boolean option
>  */
> @@ -468,7 +480,7 @@ extern const char __export confuse_author[];
>  *
>  */
> #define CFG_SEC(name, opts, flags) \
> -  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,0,0,0,0,0}
> +  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
>
>
>
> @@ -479,13 +491,13 @@ extern const char __export confuse_author[];
>  * @see cfg_func_t
>  */
> #define CFG_FUNC(name, func) \
> -  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,0,0,0,0,0}
> +  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,{0},0,0,0,0}
>
>
> #define __CFG_PTR(name, def, flags, svalue, parsecb, freecb) \
> -  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
> +  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
> #define __CFG_PTR_LIST(name, def, flags, svalue, parsecb, freecb) \
> -  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
> +  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
>
> /** Initialize a user-defined option
>  *
> @@ -515,7 +527,7 @@ extern const char __export confuse_author[];
>  * the option list.
>  */
> #define CFG_END() \
> -   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,0,0,0,0,0}
> +   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
>
>
>
> --
> 1.7.0.4
>



_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Carlo Marcelo Arenas Belon
On Thu, Apr 29, 2010 at 11:23:04AM +0200, Martin Hedenfalk wrote:
>
> could you please test the patch by Carlo and verify that you indeed get a compiler warning if you pass an int pointer to CFG_SIMPLE_INT?

I did indeed use Martin's bug.c example for testing and shows the
following warning when compiled :

$ gcc -Wall -I. -lconfuse -o bug bug.c
bug.c:7: warning: initialization from incompatible pointer type

> We should probably still add the comment about int vs long int though.

agree

Carlo


_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Martin Hömberg
On Friday 30 April 2010 11:14:08 Carlo Marcelo Arenas Belon wrote:
> On Thu, Apr 29, 2010 at 11:23:04AM +0200, Martin Hedenfalk wrote:
> > could you please test the patch by Carlo and verify that you indeed get a
> > compiler warning if you pass an int pointer to CFG_SIMPLE_INT?

Yes. Thank you for all the replies. I finally tried Carlo's patch with the
Intel compiler and it also produces now the corresponding warning:

bug.c(7): warning #144: a value of type "int *" cannot be used to initialize
an entity of type "long *"
        CFG_SIMPLE_INT("b", &a[0]),
        ^

I think this warning is sufficient to see that something might go wrong at this
place.


>
> I did indeed use Martin's bug.c example for testing and shows the
> following warning when compiled :
>
> $ gcc -Wall -I. -lconfuse -o bug bug.c
> bug.c:7: warning: initialization from incompatible pointer type
>
> > We should probably still add the comment about int vs long int though.
>
> agree
>
> Carlo


_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel
Reply | Threaded
Open this post in threaded view
|

Re: CFG_SIMPLE_INT on 64bit machine

Martin Hedenfalk-4
In reply to this post by Carlo Marcelo Arenas Belon
committed, thanks!

        -martin

29 apr 2010 kl. 11.02 skrev Carlo Marcelo Arenas Belon:

> On Thu, Apr 29, 2010 at 06:31:19AM +0200, Martin Hedenfalk wrote:
>> It would be better to use a union with proper pointer types for the
>> simple value. Patches welcome :-)
>
> Comments welcome ;), and at least gets read of all casts and lets the
> compiler do the type checking as suggested.
>
> Some known caveats :
>
> * union initializer would require C99 like support in the compiler
> * all non type specific checks are using the pointer type
> * use of union type should be ABI compatible but not tested
> * cfg_simple_t could be avoided if using instead cfg_value_t* but that
>  would require more code changes and would be ABI incompatible
>
> Carlo
> ---
> From 97ae9e8d7d1771e0a2bb38bc7d719bfe431f7c60 Mon Sep 17 00:00:00 2001
> From: Carlo Marcelo Arenas Belon <[hidden email]>
> Date: Thu, 29 Apr 2010 01:48:31 -0700
> Subject: [PATCH] simple: use union instead of void*
>
> ---
> src/confuse.c |   34 +++++++++++++++++-----------------
> src/confuse.h |   40 ++++++++++++++++++++++++++--------------
> 2 files changed, 43 insertions(+), 31 deletions(-)
>
> diff --git a/src/confuse.c b/src/confuse.c
> index be1bf5e..60d77a5 100644
> --- a/src/confuse.c
> +++ b/src/confuse.c
> @@ -210,8 +210,8 @@ DLLIMPORT signed long cfg_opt_getnint(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_INT);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->number;
> -    else if(opt->simple_value)
> -        return *(signed long *)opt->simple_value;
> +    else if(opt->simple_value.number)
> +        return *opt->simple_value.number;
>     else
>         return 0;
> }
> @@ -232,8 +232,8 @@ DLLIMPORT double cfg_opt_getnfloat(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_FLOAT);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->fpnumber;
> -    else if(opt->simple_value)
> -        return *(double *)opt->simple_value;
> +    else if(opt->simple_value.fpnumber)
> +        return *opt->simple_value.fpnumber;
>     else
>         return 0;
> }
> @@ -254,8 +254,8 @@ DLLIMPORT cfg_bool_t cfg_opt_getnbool(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_BOOL);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->boolean;
> -    else if(opt->simple_value)
> -        return *(cfg_bool_t *)opt->simple_value;
> +    else if(opt->simple_value.boolean)
> +        return *opt->simple_value.boolean;
>     else
>         return cfg_false;
> }
> @@ -276,8 +276,8 @@ DLLIMPORT char *cfg_opt_getnstr(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_STR);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->string;
> -    else if(opt->simple_value)
> -        return *(char **)opt->simple_value;
> +    else if(opt->simple_value.string)
> +        return *opt->simple_value.string;
>     else
>         return 0;
> }
> @@ -297,8 +297,8 @@ DLLIMPORT void *cfg_opt_getnptr(cfg_opt_t *opt, unsigned int index)
>     assert(opt && opt->type == CFGT_PTR);
>     if(opt->values && index < opt->nvalues)
>         return opt->values[index]->ptr;
> -    else if(opt->simple_value)
> -        return *(void **)opt->simple_value;
> +    else if(opt->simple_value.ptr)
> +        return *opt->simple_value.ptr;
>     else
>         return 0;
> }
> @@ -425,7 +425,7 @@ static void cfg_init_defaults(cfg_t *cfg)
>     for(i = 0; cfg->opts[i].name; i++)
>     {
>         /* libConfuse doesn't handle default values for "simple" options */
> -        if(cfg->opts[i].simple_value || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
> +        if(cfg->opts[i].simple_value.ptr || is_set(CFGF_NODEFAULT, cfg->opts[i].flags))
>             continue;
>
>         if(cfg->opts[i].type != CFGT_SEC)
> @@ -539,10 +539,10 @@ cfg_setopt(cfg_t *cfg, cfg_opt_t *opt, char *value)
>
>     assert(cfg && opt);
>
> -    if(opt->simple_value)
> +    if(opt->simple_value.ptr)
>     {
>         assert(opt->type != CFGT_SEC);
> -        val = (cfg_value_t *)opt->simple_value;
> +        val = (cfg_value_t *)opt->simple_value.ptr;
>     }
>     else
>     {
> @@ -1238,8 +1238,8 @@ static cfg_value_t *cfg_opt_getval(cfg_opt_t *opt, unsigned int index)
>
>     assert(index == 0 || is_set(CFGF_LIST, opt->flags));
>
> -    if(opt->simple_value)
> -        val = (cfg_value_t *)opt->simple_value;
> +    if(opt->simple_value.ptr)
> +        val = (cfg_value_t *)opt->simple_value.ptr;
>     else
>     {
>         if(is_set(CFGF_RESET, opt->flags))
> @@ -1493,9 +1493,9 @@ DLLIMPORT void cfg_opt_print_indent(cfg_opt_t *opt, FILE *fp, int indent)
>         {
>             cfg_indent(fp, indent);
>             /* comment out the option if is not set */
> -            if(opt->simple_value)
> +            if(opt->simple_value.ptr)
>             {
> -                if(opt->type == CFGT_STR && *((char **)opt->simple_value) == 0)
> +                if(opt->type == CFGT_STR && *opt->simple_value.string == 0)
>                     fprintf(fp, "# ");
>             }
>             else
> diff --git a/src/confuse.h b/src/confuse.h
> index 69215b1..8b5746b 100644
> --- a/src/confuse.h
> +++ b/src/confuse.h
> @@ -97,6 +97,7 @@ typedef enum cfg_type_t cfg_type_t;
> #define CFG_PARSE_ERROR 1
>
> typedef union cfg_value_t cfg_value_t;
> +typedef union cfg_simple_t cfg_simple_t;
> typedef struct cfg_opt_t cfg_opt_t;
> typedef struct cfg_t cfg_t;
> typedef struct cfg_defvalue_t cfg_defvalue_t;
> @@ -237,6 +238,17 @@ union cfg_value_t {
>     void *ptr;              /**< user-defined value */
> };
>
> +/** Data structure holding the pointer to a user provided variable
> + *  defined with CFG_SIMPLE_*
> + */
> +union cfg_simple_t {
> +    long int *number;
> +    double *fpnumber;
> +    cfg_bool_t *boolean;
> +    char **string;
> +    void **ptr;
> +};
> +
> /** Data structure holding the default value given by the
>  *  initialization macros.
>  */
> @@ -263,7 +275,7 @@ struct cfg_opt_t {
>     cfg_opt_t *subopts;     /**< Suboptions (only applies to sections) */
>     cfg_defvalue_t def;     /**< Default value */
>     cfg_func_t func;        /**< Function callback for CFGT_FUNC options */
> -    void *simple_value;     /**< Pointer to user-specified variable to
> +    cfg_simple_t simple_value;     /**< Pointer to user-specified variable to
>                              * store simple values (created with the
>                              * CFG_SIMPLE_* initializers) */
>     cfg_callback_t parsecb; /**< Value parsing callback function */
> @@ -277,9 +289,9 @@ extern const char __export confuse_version[];
> extern const char __export confuse_author[];
>
> #define __CFG_STR(name, def, flags, svalue, cb) \
> -  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_STR,0,0,flags,0,{0,0,cfg_false,def,0},0,{.string=svalue},cb,0,0,0}
> #define __CFG_STR_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_STR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.string=svalue},cb,0,0,0}
>
> /** Initialize a string option
>  */
> @@ -358,9 +370,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_INT(name, def, flags, svalue, cb) \
> -  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_INT,0,0,flags,0,{def,0,cfg_false,0,0},0,{.number=svalue},cb,0,0,0}
> #define __CFG_INT_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_INT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.number=svalue},cb,0,0,0}
>
> /** Initialize an integer option
>  */
> @@ -391,9 +403,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_FLOAT(name, def, flags, svalue, cb) \
> -  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_FLOAT,0,0,flags,0,{0,def,cfg_false,0,0},0,{.fpnumber=svalue},cb,0,0,0}
> #define __CFG_FLOAT_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_FLOAT,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.fpnumber=svalue},cb,0,0,0}
>
> /** Initialize a floating point option
>  */
> @@ -424,9 +436,9 @@ extern const char __export confuse_author[];
>
>
> #define __CFG_BOOL(name, def, flags, svalue, cb) \
> -  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,svalue,cb,0,0,0}
> +  {name,CFGT_BOOL,0,0,flags,0,{0,0,def,0,0},0,{.boolean=svalue},cb,0,0,0}
> #define __CFG_BOOL_LIST(name, def, flags, svalue, cb) \
> -  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,cb,0,0,0}
> +  {name,CFGT_BOOL,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.boolean=svalue},cb,0,0,0}
>
> /** Initialize a boolean option
>  */
> @@ -468,7 +480,7 @@ extern const char __export confuse_author[];
>  *
>  */
> #define CFG_SEC(name, opts, flags) \
> -  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,0,0,0,0,0}
> +  {name,CFGT_SEC,0,0,flags,opts,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
>
>
>
> @@ -479,13 +491,13 @@ extern const char __export confuse_author[];
>  * @see cfg_func_t
>  */
> #define CFG_FUNC(name, func) \
> -  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,0,0,0,0,0}
> +  {name,CFGT_FUNC,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},func,{0},0,0,0,0}
>
>
> #define __CFG_PTR(name, def, flags, svalue, parsecb, freecb) \
> -  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
> +  {name,CFGT_PTR,0,0,flags,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
> #define __CFG_PTR_LIST(name, def, flags, svalue, parsecb, freecb) \
> -  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,svalue,parsecb,0,0,freecb}
> +  {name,CFGT_PTR,0,0,flags | CFGF_LIST,0,{0,0,cfg_false,0,def},0,{.ptr=svalue},parsecb,0,0,freecb}
>
> /** Initialize a user-defined option
>  *
> @@ -515,7 +527,7 @@ extern const char __export confuse_author[];
>  * the option list.
>  */
> #define CFG_END() \
> -   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,0,0,0,0,0}
> +   {0,CFGT_NONE,0,0,CFGF_NONE,0,{0,0,cfg_false,0,0},0,{0},0,0,0,0}
>
>
>
> --
> 1.7.0.4
>


_______________________________________________
Confuse-devel mailing list
[hidden email]
http://lists.nongnu.org/mailman/listinfo/confuse-devel