OSSP CVS Repository

ossp - Check-in [4892]
Not logged in
[Honeypot]  [Browse]  [Home]  [Login]  [Reports
[Search]  [Ticket]  [Timeline
  [Patchset]  [Tagging/Branching

Check-in Number: 4892
Date: 2004-Dec-04 13:48:40 (local)
2004-Dec-04 12:48:40 (UTC)
User:rse
Branch:
Comment: Plug remaining memory leaks by introducing the usual LOAN/GIFT/COPY argument passing semantics to cfg_node_{set,get} and using this to directly pass the allocated tokens from the scanner through the parser into the node tree.
Tickets:
Inspections:
Files:
ossp-pkg/cfg/ChangeLog      1.27 -> 1.28     6 inserted, 0 deleted
ossp-pkg/cfg/cfg.h      1.15 -> 1.16     21 inserted, 15 deleted
ossp-pkg/cfg/cfg_main.c      1.13 -> 1.14     8 inserted, 1 deleted
ossp-pkg/cfg/cfg_node.c      1.22 -> 1.23     75 inserted, 30 deleted
ossp-pkg/cfg/cfg_node.h      added-> 1.11
ossp-pkg/cfg/cfg_syn_parse.y      added-> 1.11
ossp-pkg/cfg/perl/cfg.xs      1.6 -> 1.7     2 inserted, 2 deleted

ossp-pkg/cfg/ChangeLog 1.27 -> 1.28

--- ChangeLog    2004/11/29 07:09:33     1.27
+++ ChangeLog    2004/12/04 12:48:40     1.28
@@ -10,6 +10,12 @@
 
  Changes between 0.9.5 and 0.9.6 (27-Nov-2004 to xx-Dec-2004):
 
+   *) Plug remaining memory leaks by introducing the usual
+      LOAN/GIFT/COPY argument passing semantics to cfg_node_{set,get}
+      and using this to directly pass the allocated tokens from the
+      scanner through the parser into the node tree.
+      [Ralf S. Engelschall <rse@engelschall.com>]
+
    *) Fix optional DMalloc build support.
       [Ralf S. Engelschall <rse@engelschall.com>]
 


ossp-pkg/cfg/cfg.h 1.15 -> 1.16

--- cfg.h        2004/11/20 14:52:56     1.15
+++ cfg.h        2004/12/04 12:48:40     1.16
@@ -63,21 +63,27 @@
 } cfg_node_type_t;
 
 /* list of node attributes */
-typedef enum {
-    CFG_NODE_ATTR_PARENT,     /* RW: (cfg_node_t *)    pointer to parent node */
-    CFG_NODE_ATTR_LBROTH,     /* RW: (cfg_node_t *)    pointer to left brother node */
-    CFG_NODE_ATTR_RBROTH,     /* RW: (cfg_node_t *)    pointer to right brother node */
-    CFG_NODE_ATTR_CHILD1,     /* RW: (cfg_node_t *)    pointer to first child node */
-    CFG_NODE_ATTR_CHILDL,     /* RO: (cfg_node_t *)    pointer to last child */
-    CFG_NODE_ATTR_CHILDS,     /* RO: (int)             number of child nodes */
-    CFG_NODE_ATTR_NODES,      /* RO: (int)             number of total nodes (recursive) */
-    CFG_NODE_ATTR_DEPTH,      /* RO: (int)             number of nodes back to root node */
-    CFG_NODE_ATTR_SRCNAME,    /* RW: (char *)          pointer to the source name */
-    CFG_NODE_ATTR_SRCPOS,     /* RW: (int)             position offset into source */
-    CFG_NODE_ATTR_TYPE,       /* RW: (cfg_node_type_t) type of node */
-    CFG_NODE_ATTR_TOKEN,      /* RW: (char *)          pointer to the node token string */
-    CFG_NODE_ATTR_DATA        /* RW: (cfg_data_t *)    pointer to the node annotation data */
-} cfg_node_attr_t;
+typedef int cfg_node_attr_t;
+enum {
+    /* attribute selection */
+    CFG_NODE_ATTR_PARENT  = (1 <<  0), /* RW: (cfg_node_t *)    pointer to parent node */
+    CFG_NODE_ATTR_LBROTH  = (1 <<  1), /* RW: (cfg_node_t *)    pointer to left brother node */
+    CFG_NODE_ATTR_RBROTH  = (1 <<  2), /* RW: (cfg_node_t *)    pointer to right brother node */
+    CFG_NODE_ATTR_CHILD1  = (1 <<  3), /* RW: (cfg_node_t *)    pointer to first child node */
+    CFG_NODE_ATTR_CHILDL  = (1 <<  4), /* RO: (cfg_node_t *)    pointer to last child */
+    CFG_NODE_ATTR_CHILDS  = (1 <<  5), /* RO: (int)             number of child nodes */
+    CFG_NODE_ATTR_NODES   = (1 <<  6), /* RO: (int)             number of total nodes (recursive) */
+    CFG_NODE_ATTR_DEPTH   = (1 <<  7), /* RO: (int)             number of nodes back to root node */
+    CFG_NODE_ATTR_SRCNAME = (1 <<  8), /* RW: (char *)          pointer to the source name */
+    CFG_NODE_ATTR_SRCPOS  = (1 <<  9), /* RW: (int)             position offset into source */
+    CFG_NODE_ATTR_TYPE    = (1 << 10), /* RW: (cfg_node_type_t) type of node */
+    CFG_NODE_ATTR_TOKEN   = (1 << 11), /* RW: (char *)          pointer to the node token string */
+    CFG_NODE_ATTR_DATA    = (1 << 12), /* RW: (cfg_data_t *)    pointer to the node annotation data */
+    /* attribute passing semantics */
+    CFG_ATTR_LOAN         = (1 << 13), /* loan attribute on set/get: source still owns orginal data */
+    CFG_ATTR_GIFT         = (1 << 14), /* gift attribute on set/get: target then  owns orginal data */
+    CFG_ATTR_COPY         = (1 << 15)  /* copy attribute on set/get: target then  owns copied  data */
+};
 
 /* list of data types */
 typedef enum {


ossp-pkg/cfg/cfg_main.c 1.13 -> 1.14

--- cfg_main.c   2004/11/29 07:09:33     1.13
+++ cfg_main.c   2004/12/04 12:48:40     1.14
@@ -73,11 +73,18 @@
     return CFG_OK;
 }
 
+static cfg_rc_t cfg_destroy_node(cfg_t *cfg, cfg_node_t *node, void *ctx)
+{
+    cfg_node_destroy(cfg, node);
+    return CFG_OK;
+}
+
 cfg_rc_t cfg_destroy(cfg_t *cfg)
 {
     if (cfg == NULL)
         return CFG_ERR_ARG;
-    /* FIXME: on each node, free token string first */
+    if (cfg->root != NULL)
+        cfg_node_apply(cfg, cfg->root, NULL, NULL, cfg_destroy_node, NULL);
     cfg_grid_destroy(cfg->grid_nodes);
     cfg_grid_destroy(cfg->grid_tokens);
     free(cfg);


ossp-pkg/cfg/cfg_node.c 1.22 -> 1.23

--- cfg_node.c   2004/11/29 07:09:33     1.22
+++ cfg_node.c   2004/12/04 12:48:40     1.23
@@ -57,6 +57,7 @@
         return rc;
 
     /* initialize node attributes */
+    n->owner    = 0;
     n->parent   = NULL;
     n->rbroth   = NULL;
     n->child1   = NULL;
@@ -81,10 +82,11 @@
         return CFG_ERR_ARG;
 
     /* destroy memory */
-    if (node->token != NULL)
+    if ((node->owner & CFG_NODE_ATTR_TOKEN) && node->token != NULL)
         free(node->token);
-    if (node->srcname != NULL)
+    if ((node->owner & CFG_NODE_ATTR_SRCNAME) && node->srcname != NULL)
         free(node->srcname);
+    cfg_data_kill(&node->data);
     cfg_grid_free(cfg->grid_nodes, node);
 
     return CFG_OK;
@@ -109,14 +111,23 @@
         return rc;
 
     /* clone node attributes */
+    n->owner    = node->owner;
     n->parent   = node->parent;
     n->rbroth   = node->rbroth;
     n->child1   = node->child1;
     n->type     = node->type;
-    n->token    = (node->token != NULL ? strdup(node->token) : NULL);
-    cfg_data_copy(&node->data, &n->data);
-    n->srcname  = (node->srcname != NULL ? strdup(node->srcname) : NULL);
     n->srcpos   = node->srcpos;
+    if (node->owner & CFG_NODE_ATTR_TOKEN)
+        n->token = (node->token != NULL ? strdup(node->token) : NULL);
+    else
+        n->token = node->token;
+    if (node->owner & CFG_NODE_ATTR_SRCNAME)
+        n->srcname = (node->srcname != NULL ? strdup(node->srcname) : NULL);
+    else
+        n->srcname = node->srcname;
+    cfg_data_copy(&node->data, &n->data);
+
+    /* store result */
     *node2 = n;
 
     return CFG_OK;
@@ -138,7 +149,7 @@
 
     /* dispatch into individual attribute handling */
     va_start(ap, attr);
-    switch (attr) {
+    switch (attr & ~(CFG_ATTR_LOAN|CFG_ATTR_GIFT|CFG_ATTR_COPY)) {
         case CFG_NODE_ATTR_PARENT: {
             node->parent = (cfg_node_t *)va_arg(ap, cfg_node_t *);
             break;
@@ -171,22 +182,28 @@
             break;
         }
         case CFG_NODE_ATTR_TOKEN: {
-            if (node->token != NULL)
+            char *value = (char *)va_arg(ap, char *);
+            if (attr & CFG_ATTR_COPY)
+                value = strdup(value);
+            if (node->owner & CFG_NODE_ATTR_TOKEN && node->token != NULL)
                 free(node->token);
-            node->token = (char *)va_arg(ap, char *);
-            if (node->token != NULL)
-                node->token = strdup(node->token);
+            node->token = value;
+            if (attr & (CFG_ATTR_COPY|CFG_ATTR_GIFT))
+                node->owner |= CFG_NODE_ATTR_TOKEN;
             break;
         }
         case CFG_NODE_ATTR_DATA: {
             return CFG_ERR_USE;
         }
         case CFG_NODE_ATTR_SRCNAME: {
-            if (node->srcname != NULL)
+            char *value = (char *)va_arg(ap, char *);
+            if (attr & CFG_ATTR_COPY)
+                value = strdup(value);
+            if (node->owner & CFG_NODE_ATTR_SRCNAME && node->srcname != NULL)
                 free(node->srcname);
-            node->srcname = (char *)va_arg(ap, char *);
-            if (node->srcname != NULL)
-                node->srcname = strdup(node->srcname);
+            node->srcname = value;
+            if (attr & (CFG_ATTR_COPY|CFG_ATTR_GIFT))
+                node->owner |= CFG_NODE_ATTR_SRCNAME;
             break;
         }
         case CFG_NODE_ATTR_SRCPOS: {
@@ -220,6 +237,7 @@
     return n;
 }
 
+/* get a node attribute */
 cfg_rc_t
 cfg_node_get(
     cfg_t *cfg,
@@ -327,6 +345,10 @@
             if (token == NULL)
                 return CFG_ERR_ARG;
             *token = node->token;
+            if (attr & CFG_ATTR_COPY)
+                *token = strdup(*token);
+            if (attr & CFG_ATTR_GIFT)
+                node->token = NULL;
             break;
         }
         case CFG_NODE_ATTR_DATA: {
@@ -341,6 +363,10 @@
             if (name == NULL)
                 return CFG_ERR_ARG;
             *name = node->srcname;
+            if (attr & CFG_ATTR_COPY)
+                *name = strdup(*name);
+            if (attr & CFG_ATTR_GIFT)
+                node->srcname = NULL;
             break;
         }
         case CFG_NODE_ATTR_SRCPOS: {
@@ -721,26 +747,45 @@
     void *cb_ctx_cb)
 {
     cfg_rc_t rc;
+    cfg_node_t *child1;
+    cfg_node_t *rbroth;
 
     /* argument sanity checking */
     if (cfg == NULL)
         return CFG_ERR_ARG;
-    if (node != NULL) {
-        if ((rc = cb_fct_cmp(cfg, node, cb_ctx_cmp)) == CFG_OK)
-            cb_fct_cb(cfg, node, cb_ctx_cb);
-        if (rc != CFG_ERR_NDE)
+
+    /* short-circuit processing */
+    if (node == NULL)
+        return CFG_OK;
+
+    /* remember traversing informations from child and brother
+       (important in case the callbacks destroy it) */
+    child1 = node->child1;
+    rbroth = node->rbroth;
+
+    /* check whether the node matches */
+    if (cb_fct_cmp != NULL)
+        rc = cb_fct_cmp(cfg, node, cb_ctx_cmp);
+    else
+        rc = CFG_OK;
+
+    /* if node matched, apply optional callback on node */
+    if (rc == CFG_OK && cb_fct_cb != NULL)
+        if ((rc = cb_fct_cb(cfg, node, cb_ctx_cb)) != CFG_OK)
             return rc;
-        if (node->child1 != NULL)
-            if ((rc = cfg_node_apply(cfg, node->child1,
-                                     cb_fct_cmp, cb_ctx_cmp,
-                                     cb_fct_cb, cb_ctx_cb)) != CFG_OK)
-                return rc;
-        if (node->rbroth != NULL)
-            if ((rc = cfg_node_apply(cfg, node->rbroth,
-                                     cb_fct_cmp, cb_ctx_cmp,
-                                     cb_fct_cb, cb_ctx_cb)) != CFG_OK)
-                return rc;
-    }
+
+    /* recursively apply on child and brother nodes */
+    if (child1 != NULL)
+        if ((rc = cfg_node_apply(cfg, child1,
+                                 cb_fct_cmp, cb_ctx_cmp,
+                                 cb_fct_cb,  cb_ctx_cb)) != CFG_OK)
+            return rc;
+    if (rbroth != NULL)
+        if ((rc = cfg_node_apply(cfg, rbroth,
+                                 cb_fct_cmp, cb_ctx_cmp,
+                                 cb_fct_cb,  cb_ctx_cb)) != CFG_OK)
+            return rc;
+
     return CFG_OK;
 }
 
@@ -804,7 +849,7 @@
     return CFG_OK;
 }
 
-/* unlink a nodes from others */
+/* unlink a node from others */
 cfg_rc_t
 cfg_node_unlink(
     cfg_t *cfg,


ossp-pkg/cfg/cfg_node.h -> 1.11

*** /dev/null    Mon Apr 29 17:44:00 2024
--- -    Mon Apr 29 17:44:56 2024
***************
*** 0 ****
--- 1,59 ----
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
+ **  Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
+ **  Copyright (c) 2002-2004 Cable & Wireless (http://www.cw.com/)
+ **
+ **  This file is part of OSSP cfg, a configuration parsing
+ **  library which can be found at http://www.ossp.org/pkg/lib/cfg/.
+ **
+ **  Permission to use, copy, modify, and distribute this software for
+ **  any purpose with or without fee is hereby granted, provided that
+ **  the above copyright notice and this permission notice appear in all
+ **  copies.
+ **
+ **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ **  SUCH DAMAGE.
+ **
+ **  cfg_node.h: configuration nodes (internals)
+ */
+ 
+ #ifndef __CFG_NODE_H__
+ #define __CFG_NODE_H__
+ 
+ #include "cfg.h"
+ #include "cfg_data.h"
+ 
+ struct cfg_node_st {
+     /* attribute ownership */
+     unsigned long   owner;   /* attribute ownership bit field */
+ 
+     /* node linkage */
+     cfg_node_t     *parent;  /* pointer to parent node */
+     cfg_node_t     *rbroth;  /* pointer to right brother node */
+     cfg_node_t     *child1;  /* pointer to first child node */
+ 
+     /* node contents */
+     cfg_node_type_t type;    /* type of node */
+     char           *token;   /* pointer to corresponding token string */
+ 
+     /* node annotation */
+     cfg_data_t      data;    /* annotational data */
+ 
+     /* node source location */
+     char           *srcname; /* name of original source configuration */
+     int             srcpos;  /* offset into original source configuration */
+ };
+ 
+ #endif /* __CFG_NODE_H__ */
+ 


ossp-pkg/cfg/cfg_syn_parse.y -> 1.11

*** /dev/null    Mon Apr 29 17:44:00 2024
--- -    Mon Apr 29 17:44:56 2024
***************
*** 0 ****
--- 1,170 ----
+ %{
+ /*
+ **  OSSP cfg - Configuration Parsing
+ **  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
+ **  Copyright (c) 2002-2004 The OSSP Project (http://www.ossp.org/)
+ **  Copyright (c) 2002-2004 Cable & Wireless (http://www.cw.com/)
+ **
+ **  This file is part of OSSP cfg, a configuration parsing
+ **  library which can be found at http://www.ossp.org/pkg/lib/cfg/.
+ **
+ **  Permission to use, copy, modify, and distribute this software for
+ **  any purpose with or without fee is hereby granted, provided that
+ **  the above copyright notice and this permission notice appear in all
+ **  copies.
+ **
+ **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ **  SUCH DAMAGE.
+ **
+ **  cfg_syn_parse.y: context free grammar specification for GNU Bison
+ **
+ **  ATTENTION: This requires GNU Bison 1.875 or newer!
+ */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ 
+ #include "cfg.h"
+ #include "cfg_global.h"
+ #include "cfg_syn.h"
+ 
+ /* make sure yyparse() accepts a context pointer and
+    passes through its inlined scanner context to yylex() */
+ #define CTX           ((cfg_syn_ctx_t *)ctx)
+ #define YYPARSE_PARAM ctx
+ #define YYLEX_PARAM   CTX->yyscan
+ 
+ /* provide an explicit prototype for the yylex() function but use
+    "void *" instead of correct type because at this point in the
+    generation process we have the types still not available */
+ extern int yylex(/*YYSTYPE*/ void *lvalp,
+                  /*YYLTYPE*/ void *llocp, cfg_syn_ctx_t *ctx);
+ 
+ /* generate verbose error messages and remember them inside the context */
+ #undef  yyerror
+ #define yyerror(msg) \
+     cfg_syn_error(CTX, CFG_ERR_SYN, &yylloc, "%s", msg)
+ 
+ /* scanner state transition */
+ extern void cfg_syn_scan_push(cfg_syn_ctx_t *, const char *state);
+ extern void cfg_syn_scan_pop (cfg_syn_ctx_t *);
+ 
+ %}
+ 
+ /* parser options */
+ %error-verbose
+ %pure_parser
+ %locations
+ %defines
+ 
+ /* the YYSTYPE: parser token value */
+ %union {
+     char         *cpString;
+     cfg_node_t   *npNode;
+ }
+ 
+ /* assign YYSTYPE elements to parser rules */
+ %type  <npNode>   sequence
+ %type  <npNode>   directives
+ %type  <npNode>   directive
+ %type  <npNode>   tokens
+ %type  <npNode>   token
+ %type  <npNode>   string
+ 
+ /* list of scanner tokens */
+ %token            T_SEP
+ %token            T_OPEN
+ %token            T_CLOSE
+ %token <cpString> T_STRING
+ 
+ /* operator association */
+ %right T_SEP
+ %right T_OPEN
+ %right T_CLOSE
+ 
+ /* grammar start rule
+    (technically redundant but explicit to be sure) */
+ %start configuration
+ 
+ %%
+ 
+ configuration
+     : sequence {
+         CTX->node = $1;
+       }
+     ;
+ 
+ sequence
+     : directives {
+         cfg_node_t *n;
+         cfg_node_create(CTX->cfg, &n);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_SEQ);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_CHILD1, $1);
+         $$ = n;
+       }
+     ;
+ 
+ directives
+     : /* empty */ {
+         $$ = NULL;
+       }
+     | directive {
+         $$ = $1;
+       }
+     | directive T_SEP directives {
+         cfg_node_set(CTX->cfg, $1, CFG_NODE_ATTR_RBROTH, $3);
+         $$ = $1;
+       }
+     ;
+ 
+ directive
+     : tokens {
+         cfg_node_t *n;
+         cfg_node_create(CTX->cfg, &n);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_DIR);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_CHILD1, $1);
+         $$ = n;
+       }
+     ;
+ 
+ tokens
+     : token {
+         $$ = $1;
+       }
+     | token tokens {
+         cfg_node_set(CTX->cfg, $1, CFG_NODE_ATTR_RBROTH, $2);
+         $$ = $1;
+       }
+     ;
+ 
+ token
+     : T_OPEN sequence T_CLOSE {
+         $$ = $2;
+       }
+     | string {
+         $$ = $1;
+       }
+     ;
+ 
+ string
+     : T_STRING {
+         cfg_node_t *n;
+         cfg_node_create(CTX->cfg, &n);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_TYPE, CFG_NODE_TYPE_ARG);
+         cfg_node_set(CTX->cfg, n, CFG_NODE_ATTR_TOKEN|CFG_ATTR_GIFT, $1);
+         $$ = n;
+       }
+     ;
+ 
+ %%
+ 


ossp-pkg/cfg/perl/cfg.xs 1.6 -> 1.7

--- cfg.xs       2004/11/20 14:52:57     1.6
+++ cfg.xs       2004/12/04 12:48:42     1.7
@@ -283,7 +283,7 @@
             cfg_node_attr_t attr
             char *va_arg1
         CODE:
-            RETVAL = cfg_node_set(cfg, node, attr, va_arg1);
+            RETVAL = cfg_node_set(cfg, node, attr|CFG_ATTR_COPY, va_arg1);
         OUTPUT:
             RETVAL
     CASE: ((cfg_node_attr_t)SvIV(ST(2)) == CFG_NODE_ATTR_TYPE)
@@ -357,7 +357,7 @@
             cfg_node_attr_t attr
             char *&va_arg1 = NO_INIT
         CODE:
-            RETVAL = cfg_node_get(cfg, node, attr, &va_arg1);
+            RETVAL = cfg_node_get(cfg, node, attr|CFG_ATTR_COPY, &va_arg1);
         OUTPUT:
             va_arg1
             RETVAL

CVSTrac 2.0.1