You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by mt...@apache.org on 2009/08/24 19:55:05 UTC

svn commit: r807319 - in /commons/sandbox/runtime/trunk/src/main/native: include/acr_ini.h include/acr_ring.h shared/ini.c test/sample.ini test/testsuite.c

Author: mturk
Date: Mon Aug 24 17:55:04 2009
New Revision: 807319

URL: http://svn.apache.org/viewvc?rev=807319&view=rev
Log:
Rewrite ini to use APR ring macros

Added:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h   (with props)
Modified:
    commons/sandbox/runtime/trunk/src/main/native/include/acr_ini.h
    commons/sandbox/runtime/trunk/src/main/native/shared/ini.c
    commons/sandbox/runtime/trunk/src/main/native/test/sample.ini
    commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c

Modified: commons/sandbox/runtime/trunk/src/main/native/include/acr_ini.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_ini.h?rev=807319&r1=807318&r2=807319&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_ini.h (original)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_ini.h Mon Aug 24 17:55:04 2009
@@ -18,6 +18,7 @@
 #define _ACR_INI_H
 
 #include "acr.h"
+#include "acr_ring.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -31,68 +32,189 @@
  *
  */
 
-typedef struct ini_node_t ini_node_t;
-
-struct ini_node_t {
-    ini_node_t  *next;
-    ini_node_t **last;
-    char        *key;
-    char        *val;
+typedef struct acr_ini_attr_t    acr_ini_attr_t;
+typedef struct acr_ini_node_t    acr_ini_node_t;
+typedef struct acr_ini_t         acr_ini_t;
+
+struct acr_ini_attr_t {
+    ACR_RING_ENTRY(acr_ini_attr_t) link;
+    const char *key;
+    char       *val;
+    char        buf[1];         /* Key storage              */
 };
 
-typedef struct ini_section_t ini_section_t;
-
-struct ini_section_t {
-    ini_section_t  *next;
-    ini_section_t **last;
-    char           *name;
-    char           *attr;
-    ini_node_t     *nodes;
-    ini_section_t  *child;
-    ini_section_t  *parent;
+struct acr_ini_node_t {
+    ACR_RING_ENTRY(acr_ini_node_t)              link;
+    ACR_RING_HEAD(ini_attrs_t, acr_ini_attr_t)  attr_ring;
+    ACR_RING_HEAD(ini_child_t, acr_ini_node_t)  node_ring;
+    acr_ini_node_t  *parent;    /* Is this a child node     */
+    char            *name;      /* Name of this section     */
+    char            *attr;      /* Node's attributes        */
+    char             data[1];   /* Key storage              */
 };
 
 /**
- * Free the memory used by ini table.
- * @param root Root ini section.
+ * Create new ini table
+ * @param env Current JNI environment.
  */
-ACR_DECLARE(void) ACR_IniTableFree(ini_section_t *root);
+ACR_DECLARE(acr_ini_t *) ACR_IniNew(JNIEnv *env);
 
 /**
- * Load the Microsoft ini style configuration file.
+ * Free the memory used by ini table.
  * @param env Current JNI environment.
- * @param fname INI file to load.
+ * @param ini Ini table to free.
  */
-ACR_DECLARE(ini_section_t *) ACR_IniLoadIni(JNIEnv *env, const char *fname);
+ACR_DECLARE(void) ACR_IniFree(JNIEnv *env, acr_ini_t *ini);
 
 /**
- * Load the Java properties style configuration file.
+ * Get root node from ini table.
+ * @param ini Ini table to use.
+ * @return Root node,
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeRoot(acr_ini_t *ini);
+
+/**
+ * Get node parent.
+ * @param node Node from which to return the parent.
+ * @return Parent node.
+ * @note If this is root node returned value is pointer to itself.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeParent(acr_ini_node_t *node);
+
+/**
+ * Set current node.
+ * @param ini Ini table for which to set the current node.
+ * @param node Node to use as new current node.
+ * @note If node is NULL, the table root node is used as current.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniSetCurrent(acr_ini_t *ini,
+                                                acr_ini_node_t *node);
+
+/**
+ * Set parent of the node as current node.
+ * @param ini Ini table for which to set the parent.
+ * @param node Node which parent is used as new current node.
+ * @note If node is NULL, the table root node is used as current.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniSetParentAsCurrent(acr_ini_t *ini,
+                                                        acr_ini_node_t *node);
+
+/**
+ * Find the node from the current table node by name.
+ * @param ini Ini table for which to get the node.
+ * @param name Node name to find.
+ * @note Node is searched in table's current node.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeGet(JNIEnv *env, acr_ini_t *ini,
+                                             const char *name);
+/**
+ * Add the node to the current table node if not added alreay.
+ * @param ini Ini table for which to get the node.
+ * @param name Node name to add.
+ * @note Node is added to the table's current node.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeAdd(JNIEnv *env, acr_ini_t *ini,
+                                             const char *name,
+                                             const char *attr);
+/**
+ * Add the node to the current table node if not added alreay
+ * and set this node as table current node.
+ * @param ini Ini table for which to get the node.
+ * @param name Node name to add or set as current.
+ * @note Node is added to the table's current node.
+ */
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeSet(JNIEnv *env, acr_ini_t *ini,
+                                             const char *name,
+                                             const char *attr);
+
+/**
+ * Add attr to the existing node attribute.
+ * @param node Node for which to add addribute.
+ * @param attr String to add.
+ * @note New attribute is constructed using strcat to previous value.
+ * If the attr param is NULL, the previous attribute is deleted and
+ * its memory is freed.
+ */
+ACR_DECLARE(int) ACR_IniNodeAddAttr(JNIEnv *env, acr_ini_node_t *node,
+                                    const char *attr);
+
+/**
+ * Replace the existing node attribute.
+ * @param node Node for which to add addribute.
+ * @param attr New string attribute.
+ * @note If the attr param is NULL, the previous attribute is deleted and
+ * its memory is freed.
+ */
+ACR_DECLARE(int) ACR_IniNodeSetAttr(JNIEnv *env, acr_ini_node_t *node,
+                                    const char *attr);
+
+/**
+ * Add new key value attribute to the node.
+ * @param node Node for which to add addribute.
+ * @param key New attribute key.
+ * @param val New attribute value.
+ */
+ACR_DECLARE(acr_ini_attr_t *) ACR_IniNodeAttrAdd(JNIEnv *env,
+                                                 acr_ini_node_t *node,
+                                                 const char *key,
+                                                 const char *val);
+/**
+ * Add new key value attribute to the node if not added already
+ * @param node Node for which to add addribute.
+ * @param key Attribute key.
+ * @param val New attribute value.
+ * @note if the attribute with the given key already exists for the
+ * node it's value is replaced with the val parameter.
+ */
+ACR_DECLARE(acr_ini_attr_t *) ACR_IniNodeAttrSet(JNIEnv *env,
+                                                 acr_ini_node_t *node,
+                                                 const char *key,
+                                                 const char *val);
+
+/**
+ * Add value to the existing attribute value.
+ * @param attr Attribute for which to add value.
+ * @param val String to add.
+ * @note New attribute's value is constructed using strcat to previous value.
+ * If the val param is NULL, the previous attribute value is deleted and
+ * its memory is freed.
+ */
+ACR_DECLARE(int) ACR_IniAttrAddVal(JNIEnv *env, acr_ini_attr_t *attr,
+                                  const char *val);
+/**
+ * Replace the existing node attribute value.
+ * @param attr Attribute for which to set the value.
+ * @param val New attribute's value.
+ * @note If the val param is NULL, the previous attribute is deleted and
+ * its memory is freed.
+ */
+ACR_DECLARE(int) ACR_IniAttrSetVal(JNIEnv *env, acr_ini_attr_t *attr,
+                                  const char *val);
+
+
+/**
+ * Load the Microsoft ini style configuration file.
  * @param env Current JNI environment.
- * @param fname Properties file to load.
- * @param allowdup If nonzero duplicate keys are allowed
+ * @param fname INI file to load.
  */
-ACR_DECLARE(ini_section_t *) ACR_IniLoadProperties(JNIEnv *env,
-                                                   const char *fname,
-                                                   int allowdups);
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadIni(JNIEnv *env, const char *fname);
 
 /**
  * Load the Java properties style configuration file.
  * @param env Current JNI environment.
  * @param fname Properties file to load.
- * @param section separator character.
  * @param allowdup If nonzero duplicate keys are allowed
  */
-ACR_DECLARE(ini_section_t *) ACR_IniLoadPropertiesTree(JNIEnv *env,
-                                                       const char *fname,
-                                                       int separator,
-                                                       int allowdups);
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadProperties(JNIEnv *env,
+                                               const char *fname,
+                                               int allowdups);
 
 /**
  * Load the Apache Httpd style configuration file.
  * @param env Current JNI environment.
  * @param fname Conf file to load.
  */
-ACR_DECLARE(ini_section_t *) ACR_IniLoadConf(JNIEnv *env, const char *fname);
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadConf(JNIEnv *env, const char *fname);
 
 
 #ifdef __cplusplus

Added: commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h?rev=807319&view=auto
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h (added)
+++ commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h Mon Aug 24 17:55:04 2009
@@ -0,0 +1,403 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * This code draws heavily from the 4.4BSD <sys/queue.h> macros
+ * and Dean Gaudet's "splim/ring.h".
+ * <http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/queue.h>
+ * <http://www.arctic.org/~dean/splim/>
+ *
+ * We'd use Dean's code directly if we could guarantee the
+ * availability of inline functions.
+ */
+
+#ifndef _ACR_RING_H
+#define _ACR_RING_H
+
+/**
+ * @file acr_ring.h
+ * @brief ACR Rings
+ */
+
+/**
+ * @defgroup acr_ring Ring Macro Implementations
+ * @ingroup ACR 
+ * A ring is a kind of doubly-linked list that can be manipulated
+ * without knowing where its head is.
+ * @{
+ */
+
+/**
+ * The Ring Element
+ *
+ * A ring element struct is linked to the other elements in the ring
+ * through its ring entry field, e.g.
+ * <pre>
+ *      struct my_element_t {
+ *          ACR_RING_ENTRY(my_element_t) link;
+ *          int foo;
+ *          char *bar;
+ *      };
+ * </pre>
+ *
+ * An element struct may be put on more than one ring if it has more
+ * than one ACR_RING_ENTRY field. Each ACR_RING_ENTRY has a corresponding
+ * ACR_RING_HEAD declaration.
+ *
+ * @warning For strict C standards compliance you should put the ACR_RING_ENTRY
+ * first in the element struct unless the head is always part of a larger
+ * object with enough earlier fields to accommodate the offsetof() used
+ * to compute the ring sentinel below. You can usually ignore this caveat.
+ */
+#define ACR_RING_ENTRY(elem)                                            \
+    struct {                                                            \
+        struct elem * volatile next;                                    \
+        struct elem * volatile prev;                                    \
+    }
+
+/**
+ * The Ring Head
+ *
+ * Each ring is managed via its head, which is a struct declared like this:
+ * <pre>
+ *      ACR_RING_HEAD(my_ring_t, my_element_t);
+ *      struct my_ring_t ring, *ringp;
+ * </pre>
+ *
+ * This struct looks just like the element link struct so that we can
+ * be sure that the typecasting games will work as expected.
+ *
+ * The first element in the ring is next after the head, and the last
+ * element is just before the head.
+ */
+#define ACR_RING_HEAD(head, elem)                                       \
+    struct head {                                                       \
+        struct elem *next;                                              \
+        struct elem *prev;                                              \
+    }
+
+/**
+ * The Ring Sentinel
+ *
+ * This is the magic pointer value that occurs before the first and
+ * after the last elements in the ring, computed from the address of
+ * the ring's head.  The head itself isn't an element, but in order to
+ * get rid of all the special cases when dealing with the ends of the
+ * ring, we play typecasting games to make it look like one.
+ *
+ * Here is a diagram to illustrate the arrangements of the next and
+ * prev pointers of each element in a single ring. Note that they point
+ * to the start of each element, not to the ACR_RING_ENTRY structure.
+ *
+ * <pre>
+ *     +->+------+<-+  +->+------+<-+  +->+------+<-+
+ *     |  |struct|  |  |  |struct|  |  |  |struct|  |
+ *    /   | elem |   \/   | elem |   \/   | elem |  \
+ * ...    |      |   /\   |      |   /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     | entry|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |        | etc. |        | etc. |
+ *        :      :        :      :        :      :
+ * </pre>
+ *
+ * The ACR_RING_HEAD is nothing but a bare ACR_RING_ENTRY. The prev
+ * and next pointers in the first and last elements don't actually
+ * point to the head, they point to a phantom place called the
+ * sentinel. Its value is such that last->next->next == first because
+ * the offset from the sentinel to the head's next pointer is the same
+ * as the offset from the start of an element to its next pointer.
+ * This also works in the opposite direction.
+ *
+ * <pre>
+ *        last                            first
+ *     +->+------+<-+  +->sentinel<-+  +->+------+<-+
+ *     |  |struct|  |  |            |  |  |struct|  |
+ *    /   | elem |   \/              \/   | elem |  \
+ * ...    |      |   /\              /\   |      |   ...
+ *        +------+  |  |  +------+  |  |  +------+
+ *   ...--|prev  |  |  +--|ring  |  |  +--|prev  |
+ *        |  next|--+     |  head|--+     |  next|--...
+ *        +------+        +------+        +------+
+ *        | etc. |                        | etc. |
+ *        :      :                        :      :
+ * </pre>
+ *
+ * Note that the offset mentioned above is different for each kind of
+ * ring that the element may be on, and each kind of ring has a unique
+ * name for its ACR_RING_ENTRY in each element, and has its own type
+ * for its ACR_RING_HEAD.
+ *
+ * Note also that if the offset is non-zero (which is required if an
+ * element has more than one ACR_RING_ENTRY), the unreality of the
+ * sentinel may have bad implications on very perverse implementations
+ * of C -- see the warning in ACR_RING_ENTRY.
+ *
+ * @param hp   The head of the ring
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_SENTINEL(hp, elem, link)                               \
+    (struct elem *)((char *)(&(hp)->next) - ACR_OFFSETOF(struct elem, link))
+
+/**
+ * The first element of the ring
+ * @param hp   The head of the ring
+ */
+#define ACR_RING_FIRST(hp)      (hp)->next
+/**
+ * The last element of the ring
+ * @param hp   The head of the ring
+ */
+#define ACR_RING_LAST(hp)       (hp)->prev
+/**
+ * The next element in the ring
+ * @param ep   The current element
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_NEXT(ep, link) (ep)->link.next
+/**
+ * The previous element in the ring
+ * @param ep   The current element
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_PREV(ep, link) (ep)->link.prev
+
+
+/**
+ * Initialize a ring
+ * @param hp   The head of the ring
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_INIT(hp, elem, link) do {                              \
+        ACR_RING_FIRST((hp)) = ACR_RING_SENTINEL((hp), elem, link);     \
+        ACR_RING_LAST((hp))  = ACR_RING_SENTINEL((hp), elem, link);     \
+    } while (0)
+
+/**
+ * Determine if a ring is empty
+ * @param hp   The head of the ring
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ * @return true or false
+ */
+#define ACR_RING_EMPTY(hp, elem, link)                                  \
+    (ACR_RING_FIRST((hp)) == ACR_RING_SENTINEL((hp), elem, link))
+
+/**
+ * Initialize a singleton element
+ * @param ep   The element
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_ELEM_INIT(ep, link) do {                               \
+        ACR_RING_NEXT((ep), link) = (ep);                               \
+        ACR_RING_PREV((ep), link) = (ep);                               \
+    } while (0)
+
+
+/**
+ * Splice the sequence ep1..epN into the ring before element lep
+ *   (..lep.. becomes ..ep1..epN..lep..)
+ * @warning This doesn't work for splicing before the first element or on
+ *   empty rings... see ACR_RING_SPLICE_HEAD for one that does
+ * @param lep  Element in the ring to splice before
+ * @param ep1  First element in the sequence to splice in
+ * @param epN  Last element in the sequence to splice in
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do {                \
+        ACR_RING_NEXT((epN), link) = (lep);                             \
+        ACR_RING_PREV((ep1), link) = ACR_RING_PREV((lep), link);        \
+        ACR_RING_NEXT(ACR_RING_PREV((lep), link), link) = (ep1);        \
+        ACR_RING_PREV((lep), link) = (epN);                             \
+    } while (0)
+
+/**
+ * Splice the sequence ep1..epN into the ring after element lep
+ *   (..lep.. becomes ..lep..ep1..epN..)
+ * @warning This doesn't work for splicing after the last element or on
+ *   empty rings... see ACR_RING_SPLICE_TAIL for one that does
+ * @param lep  Element in the ring to splice after
+ * @param ep1  First element in the sequence to splice in
+ * @param epN  Last element in the sequence to splice in
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_SPLICE_AFTER(lep, ep1, epN, link) do {                 \
+        ACR_RING_PREV((ep1), link) = (lep);                             \
+        ACR_RING_NEXT((epN), link) = ACR_RING_NEXT((lep), link);        \
+        ACR_RING_PREV(ACR_RING_NEXT((lep), link), link) = (epN);        \
+        ACR_RING_NEXT((lep), link) = (ep1);                             \
+    } while (0)
+
+/**
+ * Insert the element nep into the ring before element lep
+ *   (..lep.. becomes ..nep..lep..)
+ * @warning This doesn't work for inserting before the first element or on
+ *   empty rings... see ACR_RING_INSERT_HEAD for one that does
+ * @param lep  Element in the ring to insert before
+ * @param nep  Element to insert
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_INSERT_BEFORE(lep, nep, link)                          \
+        ACR_RING_SPLICE_BEFORE((lep), (nep), (nep), link)
+
+/**
+ * Insert the element nep into the ring after element lep
+ *   (..lep.. becomes ..lep..nep..)
+ * @warning This doesn't work for inserting after the last element or on
+ *   empty rings... see ACR_RING_INSERT_TAIL for one that does
+ * @param lep  Element in the ring to insert after
+ * @param nep  Element to insert
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_INSERT_AFTER(lep, nep, link)                           \
+        ACR_RING_SPLICE_AFTER((lep), (nep), (nep), link)
+
+
+/**
+ * Splice the sequence ep1..epN into the ring before the first element
+ *   (..hp.. becomes ..hp..ep1..epN..)
+ * @param hp   Head of the ring
+ * @param ep1  First element in the sequence to splice in
+ * @param epN  Last element in the sequence to splice in
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_SPLICE_HEAD(hp, ep1, epN, elem, link)                  \
+        ACR_RING_SPLICE_AFTER(ACR_RING_SENTINEL((hp), elem, link),      \
+                             (ep1), (epN), link)
+
+/**
+ * Splice the sequence ep1..epN into the ring after the last element
+ *   (..hp.. becomes ..ep1..epN..hp..)
+ * @param hp   Head of the ring
+ * @param ep1  First element in the sequence to splice in
+ * @param epN  Last element in the sequence to splice in
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_SPLICE_TAIL(hp, ep1, epN, elem, link)                  \
+        ACR_RING_SPLICE_BEFORE(ACR_RING_SENTINEL((hp), elem, link),     \
+                             (ep1), (epN), link)
+
+/**
+ * Insert the element nep into the ring before the first element
+ *   (..hp.. becomes ..hp..nep..)
+ * @param hp   Head of the ring
+ * @param nep  Element to insert
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_INSERT_HEAD(hp, nep, elem, link)                       \
+        ACR_RING_SPLICE_HEAD((hp), (nep), (nep), elem, link)
+
+/**
+ * Insert the element nep into the ring after the last element
+ *   (..hp.. becomes ..nep..hp..)
+ * @param hp   Head of the ring
+ * @param nep  Element to insert
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_INSERT_TAIL(hp, nep, elem, link)                       \
+        ACR_RING_SPLICE_TAIL((hp), (nep), (nep), elem, link)
+
+/**
+ * Concatenate ring h2 onto the end of ring h1, leaving h2 empty.
+ * @param h1   Head of the ring to concatenate onto
+ * @param h2   Head of the ring to concatenate
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_CONCAT(h1, h2, elem, link) do {                        \
+        if (!ACR_RING_EMPTY((h2), elem, link)) {                        \
+            ACR_RING_SPLICE_BEFORE(ACR_RING_SENTINEL((h1), elem, link), \
+                                  ACR_RING_FIRST((h2)),                 \
+                                  ACR_RING_LAST((h2)), link);           \
+            ACR_RING_INIT((h2), elem, link);                            \
+        }                                                               \
+    } while (0)
+
+/**
+ * Prepend ring h2 onto the beginning of ring h1, leaving h2 empty.
+ * @param h1   Head of the ring to prepend onto
+ * @param h2   Head of the ring to prepend
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_PREPEND(h1, h2, elem, link) do {                       \
+        if (!ACR_RING_EMPTY((h2), elem, link)) {                        \
+            ACR_RING_SPLICE_AFTER(ACR_RING_SENTINEL((h1), elem, link),  \
+                                  ACR_RING_FIRST((h2)),                 \
+                                  ACR_RING_LAST((h2)), link);           \
+            ACR_RING_INIT((h2), elem, link);                            \
+        }                                                               \
+    } while (0)
+
+/**
+ * Unsplice a sequence of elements from a ring
+ * @warning The unspliced sequence is left with dangling pointers at either end
+ * @param ep1  First element in the sequence to unsplice
+ * @param epN  Last element in the sequence to unsplice
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_UNSPLICE(ep1, epN, link) do {                          \
+        ACR_RING_NEXT(ACR_RING_PREV((ep1), link), link) =               \
+                     ACR_RING_NEXT((epN), link);                        \
+        ACR_RING_PREV(ACR_RING_NEXT((epN), link), link) =               \
+                     ACR_RING_PREV((ep1), link);                        \
+    } while (0)
+
+/**
+ * Remove a single element from a ring
+ * @warning The unspliced element is left with dangling pointers at either end
+ * @param ep   Element to remove
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_REMOVE(ep, link)                                       \
+    ACR_RING_UNSPLICE((ep), (ep), link)
+
+/**
+ * Iterate over a ring
+ * @param ep The current element
+ * @param head The head of the ring
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_FOREACH(ep, head, elem, link)                          \
+    for (ep = ACR_RING_FIRST(head);                                     \
+         ep != ACR_RING_SENTINEL(head, elem, link);                     \
+         ep = ACR_RING_NEXT(ep, link))
+
+/**
+ * Iterate over a ring safe against removal of the current element
+ * @param ep1 The current element
+ * @param ep2 Iteration cursor
+ * @param head The head of the ring
+ * @param elem The name of the element struct
+ * @param link The name of the ACR_RING_ENTRY in the element struct
+ */
+#define ACR_RING_FOREACH_SAFE(ep1, ep2, head, elem, link)               \
+    for (ep1 = ACR_RING_FIRST(head), ep2 = ACR_RING_NEXT(ep1, link);    \
+         ep1 != ACR_RING_SENTINEL(head, elem, link);                    \
+         ep1 = ep2, ep2 = ACR_RING_NEXT(ep1, link))
+
+/** @} */ 
+
+#endif /* !_ACR_RING_H */
+

Propchange: commons/sandbox/runtime/trunk/src/main/native/include/acr_ring.h
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/sandbox/runtime/trunk/src/main/native/shared/ini.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/shared/ini.c?rev=807319&r1=807318&r2=807319&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/shared/ini.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/shared/ini.c Mon Aug 24 17:55:04 2009
@@ -23,6 +23,7 @@
 #include "acr_private.h"
 #include "acr_arch.h"
 #include "acr_error.h"
+#include "acr_memory.h"
 #include "acr_string.h"
 #include "acr_tables.h"
 #include "acr_ini.h"
@@ -31,105 +32,287 @@
  * Configuration functions
  */
 
+struct acr_ini_t {
+    acr_ini_node_t root;
+    acr_ini_node_t *cur;
+};
+
+
 #if defined(WIN32)
 #define STD_FOPEN_RDFLAGS     "rt"
 #else
 #define STD_FOPEN_RDFLAGS     "r"
 #endif
 
-static void ini_section_free(ini_section_t *ini)
+static acr_ini_node_t *ini_node_create(JNIEnv *_E, size_t nlen)
+{
+    acr_ini_node_t *ini;
+
+    ini = ACR_Calloc(_E, THROW_NMARK, sizeof(acr_ini_node_t) + nlen);
+    if (!ini)
+        return NULL;
+
+    ACR_RING_ELEM_INIT(ini, link);
+    ACR_RING_INIT(&ini->attr_ring, acr_ini_attr_t, link);
+    ACR_RING_INIT(&ini->node_ring, acr_ini_node_t, link);
+    if (nlen)
+        ini->name = &ini->data[0];
+    return ini;
+}
+
+static void ini_node_free(acr_ini_node_t *node, int clear)
 {
-    ini_section_t *p;
+    acr_ini_attr_t *ap;
+    acr_ini_attr_t *ac;
+    acr_ini_node_t *np;
+    acr_ini_node_t *nc;
+
+    ACR_RING_FOREACH_SAFE(nc, np, &node->node_ring, acr_ini_node_t, link) {
+        ACR_RING_REMOVE(nc, link);
+        ini_node_free(nc, 0);
+    }
+
+    ACR_RING_FOREACH_SAFE(ac, ap, &node->attr_ring, acr_ini_attr_t, link) {
+        ACR_RING_REMOVE(ac, link);
+        x_free(ac->val);
+        x_free(ac);
+    }
+    x_free(node->attr);
+    node->attr = NULL;
+    if (!clear) {
+        x_free(node);
+    }
+}
+
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeGet(JNIEnv *_E, acr_ini_t *ini,
+                                             const char *name)
+{
+    acr_ini_node_t *np;
+
+    if (!name)
+        return &ini->root;
+    for (np  = ACR_RING_FIRST(&(ini->cur->node_ring));
+         np != ACR_RING_SENTINEL(&(ini->cur->node_ring), acr_ini_node_t, link);
+         np  = ACR_RING_NEXT(np, link)) {
+        if (name && np->name && !strcasecmp(name, np->name))
+            return np;
+        else if (name == NULL && np->name == NULL)
+            return np;
+
+    }
+    return NULL;
+}
 
-    while ((p = ini)) {
-        ini_node_t *n;
-        while ((n = ini->nodes)) {
-            ini->nodes = n->next;
-            x_free(n->key);
-            x_free(n->val);
-            x_free(n);
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeSet(JNIEnv *_E, acr_ini_t *ini,
+                                             const char *name,
+                                             const char *attr)
+{
+    acr_ini_node_t *np;
+
+    if (!name) {
+        return NULL;
+    }
+    for (np  = ACR_RING_FIRST(&(ini->cur->node_ring));
+         np != ACR_RING_SENTINEL(&(ini->cur->node_ring), acr_ini_node_t, link);
+         np  = ACR_RING_NEXT(np, link)) {
+        if (np->name && !strcasecmp(name, np->name)) {
+            ini->cur = np;
+            return np;
         }
-        if (ini->child) {
-            /* Recursevly delete child sections
-             */
-            ini_section_free(ini->child);
+    }
+    np = ini_node_create(_E, strlen(name));
+    if (!np)
+        return NULL;
+    strcpy(np->data, name);
+    np->attr = ACR_StrdupA(_E, THROW_NMARK, attr);
+    np->parent = ini->cur;
+    ACR_RING_INSERT_TAIL(&(ini->cur->node_ring), np, acr_ini_node_t, link);
+    ini->cur = np;
+
+    return np;
+}
+
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeAdd(JNIEnv *_E, acr_ini_t *ini,
+                                             const char *name,
+                                             const char *attr)
+{
+    acr_ini_node_t *np;
+
+    if (!name) {
+        return NULL;
+    }
+    for (np  = ACR_RING_FIRST(&(ini->cur->node_ring));
+         np != ACR_RING_SENTINEL(&(ini->cur->node_ring), acr_ini_node_t, link);
+         np  = ACR_RING_NEXT(np, link)) {
+        if (np->name && !strcasecmp(name, np->name))
+            return np;
+    }
+    np = ini_node_create(_E, strlen(name));
+    if (!np)
+        return NULL;
+    strcpy(np->data, name);
+    np->attr = ACR_StrdupA(_E, THROW_NMARK, attr);
+    np->parent = ini->cur;
+    ACR_RING_INSERT_TAIL(&(ini->cur->node_ring), np, acr_ini_node_t, link);
+
+    return np;
+}
+
+ACR_DECLARE(acr_ini_attr_t *) ACR_IniNodeAttrSet(JNIEnv *_E, acr_ini_node_t *node,
+                                const char *key, const char *val)
+{
+    acr_ini_attr_t *ap;
+
+    if (!key) {
+        return NULL;
+    }
+    for (ap  = ACR_RING_FIRST(&(node->attr_ring));
+         ap != ACR_RING_SENTINEL(&(node->attr_ring), acr_ini_attr_t, link);
+         ap = ACR_RING_NEXT(ap, link)) {
+        if (!strcasecmp(key, ap->key)) {
+            x_free(ap->val);
+            ap->val = ACR_StrdupA(_E, THROW_NMARK, val);
+            return ap;
         }
-        ini = p->next;
-        x_free(p->name);
-        x_free(p->attr);
-        x_free(p);
     }
+    ap = ACR_Calloc(_E, THROW_NMARK, sizeof(acr_ini_attr_t) + strlen(key));
+    if (!ap)
+        return NULL;
+    strcpy(ap->buf, key);
+    ap->val = ACR_StrdupA(_E, THROW_NMARK, val);
+    ap->key = &ap->buf[0];
+    ACR_RING_ELEM_INIT(ap, link);
+    ACR_RING_INSERT_TAIL(&(node->attr_ring), ap, acr_ini_attr_t, link);
+
+    return ap;
 }
 
-static ini_section_t *ini_section_new(ini_section_t *top)
+ACR_DECLARE(acr_ini_attr_t *) ACR_IniNodeAttrAdd(JNIEnv *_E, acr_ini_node_t *node,
+                                const char *key, const char *val)
 {
-    ini_section_t *ini = x_calloc(sizeof(ini_section_t));
-    if (top) {
-        *top->last = ini;
-         top->last = &ini->next;
+    acr_ini_attr_t *ap;
+
+    if (!key) {
+        return NULL;
     }
-    else
-        ini->last = &ini->next;
-    ini->parent = top;
-    return ini;
+    ap = ACR_Calloc(_E, THROW_NMARK, sizeof(acr_ini_attr_t) + strlen(key));
+    if (!ap)
+        return NULL;
+    strcpy(ap->buf, key);
+    ap->val = ACR_StrdupA(_E, THROW_NMARK, val);
+    ap->key = &ap->buf[0];
+    ACR_RING_ELEM_INIT(ap, link);
+    ACR_RING_INSERT_TAIL(&(node->attr_ring), ap, acr_ini_attr_t, link);
+
+    return ap;
 }
 
-static ini_section_t *ini_child_new(ini_section_t *parent)
+ACR_DECLARE(int) ACR_IniAttrAddVal(JNIEnv *_E, acr_ini_attr_t *attr,
+                                  const char *val)
 {
-    ini_section_t *top = parent->child;
-    ini_section_t *ini = x_calloc(sizeof(ini_section_t));
-    if (top) {
-        *top->last = ini;
-         top->last = &ini->next;
-    }
-    else {
-        ini->last     = &ini->next;
-        parent->child = ini;
+    if (!val) {
+        /* Nothing to add */
+        return 0;
     }
-    ini->parent = parent;
-    return ini;
+    attr->val = ACR_StrcatA(_E, THROW_NMARK, attr->val, val);
+    if (!attr->val)
+        return ACR_GET_OS_ERROR();
+    else
+        return 0;
 }
 
-static ini_node_t *ini_node_new(ini_section_t *ini)
+ACR_DECLARE(int) ACR_IniAttrSetVal(JNIEnv *_E, acr_ini_attr_t *attr,
+                                   const char *val)
 {
-    ini_node_t *node = x_calloc(sizeof(ini_node_t));
-    if (ini->nodes) {
-        *ini->nodes->last = node;
-        ini->nodes->last  = &node->next;
+    x_free(attr->val);
+    attr->val = NULL;
+    if (!val) {
+        /* Nothing to add */
+        return 0;
     }
-    else {
-        node->last = &node->next;
-        ini->nodes = node;
+    attr->val = ACR_StrdupA(_E, THROW_NMARK, val);
+    if (!attr->val)
+        return ACR_GET_OS_ERROR();
+    else
+        return 0;
+}
+
+ACR_DECLARE(int) ACR_IniNodeAddAttr(JNIEnv *_E, acr_ini_node_t *node,
+                                    const char *attr)
+{
+    if (!attr) {
+        /* Nothing to add */
+        return 0;
     }
-    return node;
+    node->attr = ACR_StrcatA(_E, THROW_NMARK, node->attr, attr);
+    if (!node->attr)
+        return ACR_GET_OS_ERROR();
+    else
+        return 0;
+
 }
 
-static ini_section_t *ini_section_get(ini_section_t *ini, const char *name)
+ACR_DECLARE(int) ACR_IniNodeSetAttr(JNIEnv *_E, acr_ini_node_t *node,
+                                    const char *attr)
 {
-    ini_section_t *p;
-    if (!ini)
-        return NULL;
-    for (p = ini; p; p = p->next) {
-        if (name && p->name && !strcasecmp(p->name, name))
-            return p;
-        else if (name == NULL && p->name == NULL)
-            return p;
+    x_free(node->attr);
+    node->attr = NULL;
+    if (!attr) {
+        /* Nothing to set */
+        return 0;
     }
-    return NULL;
+    node->attr = ACR_StrdupA(_E, THROW_NMARK, attr);
+    if (!node->attr)
+        return ACR_GET_OS_ERROR();
+    else
+        return 0;
 }
 
-static ini_node_t *ini_node_get(ini_section_t *ini, const char *key)
+ACR_DECLARE(acr_ini_t *) ACR_IniNew(JNIEnv *_E)
 {
-    ini_node_t *n;
+    acr_ini_t *ini;
+
+    ini = ACR_Calloc(_E, THROW_NMARK, sizeof(acr_ini_t));
     if (!ini)
         return NULL;
-    for (n = ini->nodes; n; n = n->next) {
-        if (key && n->key && !strcasecmp(n->key, key))
-            return n;
-        else if (key == NULL && n->key == NULL)
-            return n;
-    }
-    return NULL;
+    ini->cur = &ini->root;
+    ini->cur->parent = ini->cur;
+    ACR_RING_ELEM_INIT(ini->cur, link);
+    ACR_RING_INIT(&ini->cur->attr_ring, acr_ini_attr_t, link);
+    ACR_RING_INIT(&ini->cur->node_ring, acr_ini_node_t, link);
+    
+    return ini;
+}
+
+ACR_DECLARE(void) ACR_IniFree(JNIEnv *_E, acr_ini_t *ini)
+{
+    ini_node_free(&ini->root, 1);
+    ACR_Free(_E, THROW_NMARK, ini);
+}
+
+ACR_DECLARE(acr_ini_node_t *) ACR_IniNodeRoot(acr_ini_t *ini)
+{
+    return &ini->root;
+}
+
+ACR_DECLARE(acr_ini_node_t *) ACR_IniSetCurrent(acr_ini_t *ini,
+                                                acr_ini_node_t *node)
+{
+    if (node)
+        ini->cur = node;
+    else
+        ini->cur = &ini->root;
+    return ini->cur;
+}
+
+ACR_DECLARE(acr_ini_node_t *) ACR_IniSetParentAsCurrent(acr_ini_t *ini,
+                                                      acr_ini_node_t *node)
+{
+    if (node->parent)
+        ini->cur = node->parent;
+    else
+        ini->cur = &ini->root;
+    return ini->cur;
 }
 
 static char *rtrim(char *s)
@@ -258,23 +441,18 @@
     return s;
 }
 
-ACR_DECLARE(void) ACR_IniTableFree(ini_section_t *root)
-{
-    ini_section_free(root);
-}
-
 /*
  * TODO:
  * Use replacement file stdio api once when finished
  * so we can use ucs2 file names and portable fgets.
  * fopen, fgets and fclose need ACR replacement functions.
  */
-ACR_DECLARE(ini_section_t *) ACR_IniLoadIni(JNIEnv *_E, const char *fname)
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadIni(JNIEnv *_E, const char *fname)
 {
     FILE *fp;
-    ini_section_t *top  = NULL;
-    ini_section_t *ini  = NULL;
-    ini_node_t    *node = NULL;
+    acr_ini_t *ini  = NULL;
+    acr_ini_node_t *cur  = NULL;
+    acr_ini_attr_t *attr = NULL;
     char buffer[ACR_PBUFF_SIZ];
     int counter  = 0;
     int nextline = 0;
@@ -284,7 +462,9 @@
         ACR_THROW_IO_ERRNO();
         return NULL;
     }
-    ini = top = ini_section_new(NULL);
+    ini = ACR_IniNew(_E);    
+    cur = ACR_IniNodeRoot(ini);
+    ACR_IniNodeSetAttr(_E, cur, fname);
     while (fgets(buffer, ACR_PBUFF_SIZ, fp)) {
         char *section;
         char *line;
@@ -302,15 +482,15 @@
         }
         if (nextline) {
             nextline = 0;
-            if (!node || *line == '\0')
+            if (!attr || *line == '\0')
                 continue;
-            node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, line);
-            if (node->val[strlen(node->val) - 1] == '\\') {
-                node->val[strlen(node->val) - 1] = '\0';
+            if (line[strlen(line) - 1] == '\\') {
+                line[strlen(line) - 1] = '\0';
                 nextline = 1;
             }
+            ACR_IniAttrAddVal(_E, attr, line);
             if (!nextline) {
-                node->val = expand_envars(node->val);
+                attr->val = expand_envars(attr->val);
             }
             continue;
         }
@@ -327,10 +507,13 @@
             }
             *ends = '\0';
             section = strtrim(line);
-            if (!(ini = ini_section_get(top, section))) {
-                ini = ini_section_new(top);
-                ini->name = ACR_StrdupA(_E, THROW_NMARK, section);
+            if (!*section) {
+                /* Skip empty section names */
+                sprintf(buffer, "Empty section name at line %d", counter);
+                ACR_ThrowExceptionA(_E, THROW_NMARK, ACR_EX_EINVAL, buffer);
+                goto cleanup;
             }
+            cur = ACR_IniNodeAdd(_E, ini, section, NULL);
             continue;
         }
         else {
@@ -354,210 +537,41 @@
                 nextline = 0;
                 continue;
             }
-            node = ini_node_new(ini);
-            node->key = ACR_StrdupA(_E, THROW_NMARK, line);
-            node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-            if (node->val && !nextline) {
-                node->val = expand_envars(node->val);
+            attr = ACR_IniNodeAttrAdd(_E, cur, line, val);
+            if (attr->val && !nextline) {
+                attr->val = expand_envars(attr->val);
             }
         }
     }
     fclose(fp);
-    return top;
+    return ini;
 
 cleanup:
     fclose(fp);
-    ini_section_free(top);
+    ACR_IniFree(_E, ini);
     return NULL;
 }
 
-ACR_DECLARE(ini_section_t *) ACR_IniLoadPropertiesTree(JNIEnv *_E,
-                                                       const char *fname,
-                                                       int separator,
-                                                       int allowdups)
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadProperties(JNIEnv *_E,
+                                               const char *fname,
+                                               int allowdups)
 {
     FILE *fp;
-    ini_section_t *top  = NULL;
-    ini_section_t *ini  = NULL;
-    ini_node_t    *node = NULL;
+    acr_ini_t *ini  = NULL;
+    acr_ini_node_t *node = NULL;
+    acr_ini_attr_t *attr = NULL;
     char buffer[ACR_PBUFF_SIZ];
     int counter  = 0;
     int nextline = 0;
-    char seps[5] = { '.', ' ', '=', ':', '\0'};
     size_t slen;
 
     if (!(fp = fopen(fname, STD_FOPEN_RDFLAGS))) {
         ACR_THROW_IO_ERRNO();
         return NULL;
     }
-    if (separator > 0)
-        seps[0] = separator;
-    ini = top = ini_section_new(NULL);
-    while (fgets(buffer, ACR_PBUFF_SIZ, fp)) {
-        char *section;
-        char *line;
-        char *ssep;
-        char *equ;
-        char *key;
-        char *val = NULL;
-        /* Always right trim the readed line */
-        counter++;
-        line = rtrim(buffer);
-        if (nextline) {
-            nextline = 0;
-            /* Java props are left trimmed
-             */
-            line = ltrim(line);
-            if (!node || *line == '\0')
-                continue;
-            node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, line);
-            slen = strlen(node->val);
-            if (node->val[slen - 1] == '\\') {
-                node->val[slen - 1] = '\0';
-                nextline = 1;
-            }
-            if (!nextline) {
-                node->val = expand_envars(node->val);
-            }
-            continue;
-        }
-        line = ltrim(buffer);
-        /* Skip comments and empty lines */
-        if (*line == '\0' || *line == '#' || *line == '!')
-            continue;
-        ssep = strpbrk_q(line, seps);
-        if (ssep && *ssep == seps[0]) {
-            char *sub;
-            *(ssep++) = '\0';
-            /* Get root subsection */
-            section = strunesc(line);            
-            if (!(ini = ini_section_get(top, section))) {
-                ini = ini_section_new(top);
-                ini->name = ACR_StrdupA(_E, THROW_NMARK, section);
-            }
-            while ((sub = strpbrk_q(ssep, seps))) {
-                ini_section_t *sec  = ini;
-                /* Check for '=' char */
-                if (*sub != seps[0]) {
-                    /* We have found a '.' after '='
-                     * The dot is part of value. bail out
-                     */
-                    break;
-                }
-                *(sub++) = '\0';
-                section = strunesc(ssep);
-                if (!(ini = ini_section_get(sec, section))) {
-                    ini = ini_child_new(sec);
-                    ini->name = ACR_StrdupA(_E, THROW_NMARK, section);
-                }
-                ssep = sub;
-            }
-            if (*ssep == '=' || *ssep == ':')
-                ssep++;
-            if ((equ = strpbrk_q(ssep, " :="))) {
-                *equ++ = '\0';
-                val = strtrim_p(equ);
-                slen = strlen(val);
-                if (slen && val[slen - 1] == '\\') {
-                    val[slen - 1] = '\0';
-                    nextline = 1;
-                }
-                if (!*val)
-                    val = NULL;
-            }
-            key = strunesc(strtrim(ssep));
-            if (!*key) {
-                /* Skip entries without keys **/
-                nextline = 0;
-                continue;
-            }
-            if (allowdups) {
-                node = ini_node_new(ini);
-                node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-                node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-            }
-            else {
-                if (!(node = ini_node_get(ini, key))) {
-                    node = ini_node_new(ini);
-                    node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-                }
-                if (val && *val) {
-                    if (node->val) {
-                        node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, ", ");
-                        node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, val);
-                    }
-                    else
-                        node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-                }
-            }
-            if (node->val && !nextline) {
-                node->val = expand_envars(node->val);
-            }
-        }
-        else {
-            if ((equ = strpbrk_q(line, " :="))) {
-                *equ++ = '\0';
-                val = strtrim_p(equ);
-                slen = strlen(val);
-                if (slen && val[slen - 1] == '\\') {
-                    val[slen - 1] = '\0';
-                    nextline = 1;
-                }
-                if (!*val)
-                    val = NULL;
-            }
-            key  = strunesc(strtrim(line));
-            if (!*key) {
-                /* Skip entries without keys **/
-                nextline = 0;
-                continue;
-            }
-            if (allowdups) {
-                node = ini_node_new(top);
-                node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-                node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-            }
-            else {
-                if (!(node = ini_node_get(top, key))) {
-                    node = ini_node_new(top);
-                    node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-                }
-                if (val && *val) {
-                    if (node->val) {
-                        node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, ", ");
-                        node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, val);
-                    }
-                    else
-                        node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-                }
-            }
-            if (node->val && !nextline) {
-                node->val = expand_envars(node->val);
-            }
-        }
-    }
-    fclose(fp);
-    return top;
-
-}
-
-ACR_DECLARE(ini_section_t *) ACR_IniLoadProperties(JNIEnv *_E,
-                                                   const char *fname,
-                                                   int allowdups)
-{
-    FILE *fp;
-    ini_section_t *ini  = NULL;
-    ini_node_t    *node = NULL;
-    char buffer[ACR_PBUFF_SIZ];
-    int counter  = 0;
-    int nextline = 0;
-    size_t slen;
-
-    if (!(fp = fopen(fname, STD_FOPEN_RDFLAGS))) {
-        ACR_THROW_IO_ERRNO();
-        return NULL;
-    }
-    ini = ini_section_new(NULL);
+    ini = ACR_IniNew(_E);
+    node = ACR_IniNodeRoot(ini);
+    ACR_IniNodeSetAttr(_E, node, fname);
     while (fgets(buffer, ACR_PBUFF_SIZ, fp)) {
         char *val = NULL;
         char *key;
@@ -571,16 +585,16 @@
             /* Java props are left trimmed
              */
             line = ltrim(line);
-            if (!node || *line == '\0')
+            if (!attr || *line == '\0')
                 continue;
-            node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, line);
-            slen = strlen(node->val);
-            if (node->val[slen - 1] == '\\') {
-                node->val[slen - 1] = '\0';
+            slen = strlen(line);
+            if (line[slen - 1] == '\\') {
+                line[slen - 1] = '\0';
                 nextline = 1;
             }
+            ACR_IniAttrAddVal(_E, attr, line);
             if (!nextline) {
-                node->val = expand_envars(node->val);
+                attr->val = expand_envars(attr->val);
             }
             continue;
         }
@@ -607,32 +621,25 @@
         }
         key = strunesc(line); 
         if (allowdups) {
-            node = ini_node_new(ini);
-            node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-            node->val = ACR_StrdupA(_E, THROW_NMARK, val);
+            attr = ACR_IniNodeAttrAdd(_E, node, key, val);
         }
         else {
-            if (!(node = ini_node_get(ini, key))) {
-                node = ini_node_new(ini);
-                node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-            }
-            x_free(node->val);
-            node->val = ACR_StrdupA(_E, THROW_NMARK, val);
+            attr = ACR_IniNodeAttrSet(_E, node, key, val);
         }
-        if (node->val && !nextline) {
-            node->val = expand_envars(node->val);
+        if (attr->val && !nextline) {
+            attr->val = expand_envars(attr->val);
         }
     }
     fclose(fp);
     return ini;
 }
 
-ACR_DECLARE(ini_section_t *) ACR_IniLoadConf(JNIEnv *_E, const char *fname)
+ACR_DECLARE(acr_ini_t *) ACR_IniLoadConf(JNIEnv *_E, const char *fname)
 {
     FILE *fp;
-    ini_section_t *top  = NULL;
-    ini_section_t *ini  = NULL;
-    ini_node_t    *node = NULL;
+    acr_ini_t *ini  = NULL;
+    acr_ini_node_t *cur  = NULL;
+    acr_ini_attr_t *attr = NULL;
     char buffer[ACR_PBUFF_SIZ];
     int counter  = 0;
     int nextline = 0;
@@ -642,7 +649,9 @@
         ACR_THROW_IO_ERRNO();
         return NULL;
     }
-    ini = top = ini_section_new(NULL);
+    ini = ACR_IniNew(NULL);
+    cur = ACR_IniNodeRoot(ini);
+    ACR_IniNodeSetAttr(_E, cur, fname);
     while (fgets(buffer, ACR_PBUFF_SIZ, fp)) {
         char *section;
         char *line;
@@ -657,16 +666,16 @@
             /* Java props are left trimmed
              */
             line = ltrim(line);
-            if (!node || *line == '\0')
+            if (!attr || *line == '\0')
                 continue;
-            node->val = ACR_StrcatA(_E, THROW_NMARK, node->val, line);
-            slen = strlen(node->val);
-            if (node->val[slen - 1] == '\\') {
-                node->val[slen - 1] = '\0';
+            slen = strlen(line);
+            if (line[slen - 1] == '\\') {
+                line[slen - 1] = '\0';
                 nextline = 1;
             }
+            ACR_IniAttrAddVal(_E, attr, line);
             if (!nextline) {
-                node->val = expand_envars(node->val);
+                attr->val = expand_envars(attr->val);
             }
             continue;
         }
@@ -685,25 +694,24 @@
             }
             *ends = '\0';
             section = strunesc(strtrim(line + 2));
-            if (!ini->name || strcasecmp(section, ini->name)) {
+            if (!cur->name || strcasecmp(section, cur->name)) {
                 sprintf(buffer, "Found </%s> while expecting </%s> at line %d",
-                                section, ini->name ? ini->name : "(null)",
+                                section, cur->name ? cur->name : "(null)",
                                 counter);
                 ACR_ThrowExceptionA(_E, THROW_NMARK, ACR_EX_EINVAL, buffer);
+                fprintf(stderr, "%s\n", buffer);
                 goto cleanup;
             }
-            ini = ini->parent;
-            if (!ini)
-                ini = top;
+            cur = ACR_IniSetParentAsCurrent(ini, cur);
         }
         else if (*line == '<') {
             /* New section
              */
-            ini_section_t *sec;
             char *ends = strpbrk_q(++line, ">");
             if (!ends) {
                 sprintf(buffer, "Unterminated section at line %d", counter);
                 ACR_ThrowExceptionA(_E, THROW_NMARK, ACR_EX_EINVAL, buffer);
+                fprintf(stderr, "%s\n", buffer);
                 goto cleanup;
             }
             *ends = '\0';
@@ -715,12 +723,7 @@
                     val = NULL;
             }
             section = strunesc(section);
-            if (!(sec = ini_section_get(ini, section))) {
-                sec = ini_child_new(ini);
-                sec->name = ACR_StrdupA(_E, THROW_NMARK, section);
-                sec->attr = ACR_StrdupA(_E, THROW_NMARK, val);
-            }
-            ini = sec;
+            cur = ACR_IniNodeSet(_E, ini, section, val);
         }
         else {
             if ((equ = strpbrk_q(line, " ="))) {
@@ -740,20 +743,18 @@
                 nextline = 0;
                 continue;
             }
-            node = ini_node_new(ini);
-            node->key = ACR_StrdupA(_E, THROW_NMARK, key);
-            node->val = ACR_StrdupA(_E, THROW_NMARK, val);
-            if (node->val && !nextline) {
-                node->val = expand_envars(node->val);
+            attr = ACR_IniNodeAttrAdd(_E, cur, key, val);
+            if (attr->val && !nextline) {
+                attr->val = expand_envars(attr->val);
             }
         }
     }
     fclose(fp);
-    return top;
+    return ini;
 
 cleanup:
     fclose(fp);
-    ini_section_free(top);
+    ACR_IniFree(_E, ini);
     return NULL;
 }
 

Modified: commons/sandbox/runtime/trunk/src/main/native/test/sample.ini
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/test/sample.ini?rev=807319&r1=807318&r2=807319&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/test/sample.ini (original)
+++ commons/sandbox/runtime/trunk/src/main/native/test/sample.ini Mon Aug 24 17:55:04 2009
@@ -20,12 +20,12 @@
 
 [second section]
 #sections don't need to have any nodes
-[]
+[empty]
 ; this is comment
 # this is comment as well
     ; comment is first non space character
 
-empty = section names are allowed
+empty = section names are not allowed
 =
 ==
 ===

Modified: commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c
URL: http://svn.apache.org/viewvc/commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c?rev=807319&r1=807318&r2=807319&view=diff
==============================================================================
--- commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c (original)
+++ commons/sandbox/runtime/trunk/src/main/native/test/testsuite.c Mon Aug 24 17:55:04 2009
@@ -37,6 +37,7 @@
 #include "acr_env.h"
 #include "acr_io.h"
 #include "acr_dso.h"
+#include "acr_ring.h"
 #include "acr_ini.h"
 #include "acr_version.h"
 
@@ -247,77 +248,47 @@
     return 0;
 }
 
-static int test_msini(int argc, const char *const argv[])
+static void dump_ini_attr(acr_ini_node_t *node, int level)
 {
-    ini_section_t *ini;
-    ini_section_t *top;
-    if (argc < 1)
-        return 1;
-
-    ini = ACR_IniLoadIni(NULL, argv[0]);
-    fprintf(stdout, "Using INI `%s\'\n", argv[0]);
-    top = ini;
-    while (ini) {
-        ini_node_t *node = ini->nodes;
-        if (!ini->name)
-            fprintf(stdout, "Root Section has NULL 'name' member\n");
-        else
-            fprintf(stdout, "Section [%s]\n", ini->name);
-        while (node) {
-            fprintf(stdout, "  %s -> %s\n", node->key, node->val);
-            node = node->next;
-        }
-        ini = ini->next;
+    acr_ini_attr_t *ap;
+    ACR_RING_FOREACH(ap, &node->attr_ring, acr_ini_attr_t, link) {
+        fprintf(stdout, "%*s%s -> %s\n", level, "", ap->key, ap->val);
     }
-    ACR_IniTableFree(top);
-
-    return 0;
 }
 
-static void dump_ini_section(ini_section_t *ini, int level)
+static void dump_ini_node(acr_ini_node_t *node, int level)
 {
-    while (ini) {
-        ini_node_t *node = ini->nodes;
-        fprintf(stdout, "%*sSection [%s]%s\n", level, "", ini->name,
-                ini->attr ? ini->attr : "");
-        while (node) {
-            fprintf(stdout, "%*s%s -> %s\n", level + 2, "", node->key, node->val);
-            node = node->next;
-        }
-        if (ini->child) {
-            dump_ini_section(ini->child, level + 2);
-        }
-        ini = ini->next;
+    acr_ini_node_t *np;
+
+   fprintf(stdout, "%*sSection [%s]  %s\n", level, "", node->name,
+           node->attr ? node->attr : "");
+   dump_ini_attr(node, level + 2);
+    ACR_RING_FOREACH(np, &node->node_ring, acr_ini_node_t, link) {
+        dump_ini_node(np, level + 2);
     }
 
 }
 
-static int test_props(int argc, const char *const argv[])
+static int test_msini(int argc, const char *const argv[])
 {
-    ini_section_t *ini;
-    ini_section_t *top;
-    int allowdups = 0;
-
-    if (argv[0][0] == '+') {
-        allowdups = 1;
-        --argc;
-        ++argv;
-    }
+    acr_ini_t *top;
     if (argc < 1)
         return 1;
-    ini = ACR_IniLoadProperties(NULL, argv[0], allowdups);
-    fprintf(stdout, "Using Property `%s\'\n", argv[0]);
-    top = ini;
-    dump_ini_section(ini, 0);
-    ACR_IniTableFree(top);
 
+    top = ACR_IniLoadIni(NULL, argv[0]);
+
+    if (top) {
+        dump_ini_node(ACR_IniNodeRoot(top), 0); 
+        ACR_IniFree(NULL, top);
+    }
+    printf("Ms INI   OK\n");
     return 0;
 }
 
-static int test_ptree(int argc, const char *const argv[])
+
+static int test_props(int argc, const char *const argv[])
 {
-    ini_section_t *ini;
-    ini_section_t *top;
+    acr_ini_t *ini;
     int allowdups = 0;
 
     if (argv[0][0] == '+') {
@@ -327,29 +298,65 @@
     }
     if (argc < 1)
         return 1;
-
-    ini = ACR_IniLoadPropertiesTree(NULL, argv[0], '.', allowdups);
+    ini = ACR_IniLoadProperties(NULL, argv[0], allowdups);
     fprintf(stdout, "Using Property `%s\'\n", argv[0]);
-    top = ini;
-    dump_ini_section(ini, 0);
-    ACR_IniTableFree(top);
+
+    dump_ini_node(ACR_IniNodeRoot(ini), 0); 
+    ACR_IniFree(NULL, ini);
 
     return 0;
 }
 
 static int test_conf(int argc, const char *const argv[])
 {
-    ini_section_t *ini;
-    ini_section_t *top;
+    acr_ini_t *top;
     if (argc < 1)
         return 1;
 
-    ini = ACR_IniLoadConf(NULL, argv[0]);
-    fprintf(stdout, "Using Conf `%s\'\n", argv[0]);
-    top = ini;
-    dump_ini_section(ini, 0);
-    ACR_IniTableFree(top);
+    top = ACR_IniLoadConf(NULL, argv[0]);
+    printf("Loaded OK %p\n", top);
 
+    if (top) {
+        dump_ini_node(ACR_IniNodeRoot(top), 0); 
+        ACR_IniFree(NULL, top);
+    }
+    printf("Conf   OK\n");
+    return 0;
+}
+
+static int test_ring(int argc, const char *const argv[])
+{
+    acr_ini_t *top;
+
+    acr_ini_node_t *ini;
+    acr_ini_node_t *is1;
+    acr_ini_node_t *is2;
+    acr_ini_node_t *p;
+
+    top = ACR_IniNew(NULL);
+    
+    ini = ACR_IniNodeSet(NULL, top, "node1", NULL);
+    ACR_IniSetCurrent(top, ini);
+    is1 = ACR_IniNodeSet(NULL, top, "node2", NULL);
+    is2 = ACR_IniNodeSet(NULL, top, "node3", NULL);
+
+    for (p  = ACR_RING_FIRST(&(ini->node_ring));
+         p != ACR_RING_SENTINEL(&(ini->node_ring), acr_ini_node_t, link);
+         p = ACR_RING_NEXT(p, link)) {
+        printf("INI %s\n", p->name);
+    }
+    for (p  = ACR_RING_FIRST(&(is1->node_ring));
+         p != ACR_RING_SENTINEL(&(is1->node_ring), acr_ini_node_t, link);
+         p = ACR_RING_NEXT(p, link)) {
+        printf("IS1 %s\n", p->name);
+    }
+    for (p  = ACR_RING_FIRST(&(is2->node_ring));
+         p != ACR_RING_SENTINEL(&(is2->node_ring), acr_ini_node_t, link);
+         p = ACR_RING_NEXT(p, link)) {
+        printf("IS2 %s\n", p->name);
+    }
+    ACR_IniFree(NULL, top);
+    fprintf(stdout, "ring test:         OK\n");
     return 0;
 }
 
@@ -418,12 +425,12 @@
         else if (!strcasecmp(run_test, "props")) {
             rv = test_props(argc, argv);
         }
-        else if (!strcasecmp(run_test, "ptree")) {
-            rv = test_ptree(argc, argv);
-        }
         else if (!strcasecmp(run_test, "conf")) {
             rv = test_conf(argc, argv);
         }
+        else if (!strcasecmp(run_test, "ring")) {
+            rv = test_ring(argc, argv);
+        }
     }
 
 cleanup: