/[Apache-SVN]/jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java
ViewVC logotype

Diff of /jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

--- jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java	2005/07/27 14:07:04	225521
+++ jakarta/commons/proper/configuration/trunk/src/java/org/apache/commons/configuration/PropertiesConfiguration.java	2005/07/27 14:12:59	225522
@@ -29,6 +29,7 @@ import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.commons.lang.ArrayUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang.StringUtils;
 
@@ -42,14 +43,24 @@ import org.apache.commons.lang.StringUti
  * added and later saved. include statements are (obviously) not supported
  * if you don't construct a PropertyConfiguration from a file.
  *
- * <p>The properties file syntax is explained here:
+ * <p>The properties file syntax is explained here, basically it follows
+ * the syntax of the stream parsed by {@link java.util.Properties#load} and
+ * adds several useful extensions:
  *
  * <ul>
  *  <li>
- *   Each property has the syntax <code>key = value</code>
+ *   Each property has the syntax <code>key &lt;separator> value</code>. The
+ *   separators accepted are <code>'='</code>, <code>':'</code> and any white
+ *   space character. Examples:
+ * <pre>
+ *  key1 = value1
+ *  key2 : value2
+ *  key3   value3</pre>
  *  </li>
  *  <li>
- *   The <i>key</i> may use any character but the equal sign '='.
+ *   The <i>key</i> may use any character, separators must be escaped:
+ * <pre>
+ *  key\:foo = bar</pre>
  *  </li>
  *  <li>
  *   <i>value</i> may be separated on different lines if a backslash
@@ -108,7 +119,7 @@ import org.apache.commons.lang.StringUti
  *      tokens_on_multiple_lines = second token
  *
  *      # commas may be escaped in tokens
- *      commas.excaped = Hi\, what'up?
+ *      commas.escaped = Hi\, what'up?
  *
  *      # properties can reference other properties
  *      base.prop = /base
@@ -116,7 +127,8 @@ import org.apache.commons.lang.StringUti
  *      second.prop = ${first.prop}/second
  * </pre>
  *
- * @author <a href="mailto:e.bourg@cross-systems.com">Emmanuel Bourg</a>
+ * @see java.util.Properties#load
+ *
  * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
  * @author <a href="mailto:daveb@miceda-data">Dave Bryson</a>
@@ -130,10 +142,17 @@ import org.apache.commons.lang.StringUti
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
  * @author <a href="mailto:epugh@upstate.com">Eric Pugh</a>
  * @author <a href="mailto:oliver.heger@t-online.de">Oliver Heger</a>
+ * @author <a href="mailto:ebourg@apache.org">Emmanuel Bourg</a>
  * @version $Id$
  */
 public class PropertiesConfiguration extends AbstractFileConfiguration
 {
+    /** The list of possible key/value separators */
+    private static final char[] SEPARATORS = new char[] { '=', ':' };
+
+    /** The white space characters used as key/value separators. */
+    private static final char[] WHITE_SPACE = new char[] { ' ', '\t', '\f' };
+
     /**
      * This is the name of the property that can point to other
      * properties file for including other properties files.
@@ -286,34 +305,32 @@ public class PropertiesConfiguration ext
                     break; // EOF
                 }
 
-                int equalSign = line.indexOf('=');
-                if (equalSign > 0)
-                {
-                    String key = line.substring(0, equalSign).trim();
-                    String value = line.substring(equalSign + 1).trim();
-
-                    // Though some software (e.g. autoconf) may produce
-                    // empty values like foo=\n, emulate the behavior of
-                    // java.util.Properties by setting the value to the
-                    // empty string.
+                // parse the line
+                String[] property = parseProperty(line);
+                String key = property[0];
+                String value = property[1];
+
+                // Though some software (e.g. autoconf) may produce
+                // empty values like foo=\n, emulate the behavior of
+                // java.util.Properties by setting the value to the
+                // empty string.
 
-                    if (StringUtils.isNotEmpty(getInclude())
-                        && key.equalsIgnoreCase(getInclude()))
+                if (StringUtils.isNotEmpty(getInclude()) && key.equalsIgnoreCase(getInclude()))
+                {
+                    if (getIncludesAllowed())
                     {
-                        if (getIncludesAllowed())
+                        String [] files = StringUtils.split(value, getDelimiter());
+                        for (int i = 0; i < files.length; i++)
                         {
-                            String [] files = StringUtils.split(value, getDelimiter());
-                            for (int i = 0; i < files.length; i++)
-                            {
-                                load(ConfigurationUtils.locate(getBasePath(), files[i].trim()));
-                            }
+                            load(ConfigurationUtils.locate(getBasePath(), files[i].trim()));
                         }
                     }
-                    else
-                    {
-                        addProperty(key, unescapeJava(value, getDelimiter()));
-                    }
                 }
+                else
+                {
+                    addProperty(key, unescapeJava(value, getDelimiter()));
+                }
+
             }
         }
         catch (IOException ioe)
@@ -498,7 +515,7 @@ public class PropertiesConfiguration ext
          */
         public void writeProperty(String key, Object value) throws IOException
         {
-            write(key);
+            write(escapeKey(key));
             write(" = ");
             if (value != null)
             {
@@ -534,6 +551,33 @@ public class PropertiesConfiguration ext
         {
             write("# " + comment + "\n");
         }
+
+        /**
+         * Escape the separators in the key.
+         */
+        private String escapeKey(String key)
+        {
+            StringBuffer newkey = new StringBuffer();
+
+            for (int i = 0; i < key.length(); i++)
+            {
+                char c = key.charAt(i);
+
+                if (ArrayUtils.contains(SEPARATORS, c) || ArrayUtils.contains(WHITE_SPACE, c))
+                {
+                    // escape the separator
+                    newkey.append('\\');
+                    newkey.append(c);
+                }
+                else
+                {
+                    newkey.append(c);
+                }
+            }
+
+            return newkey.toString();
+        }
+
     } // class PropertiesWriter
 
     /**
@@ -646,4 +690,102 @@ public class PropertiesConfiguration ext
         return out.toString();
     }
 
+    /**
+     * Parse a property line and return the key and the value in an array.
+     */
+    private String[] parseProperty(String line)
+    {
+        // sorry for this spaghetti code, please replace it as soon as
+        // possible with a regexp when the Java 1.3 requirement is dropped
+
+        String[] result = new String[2];
+        StringBuffer key = new StringBuffer();
+        StringBuffer value = new StringBuffer();
+
+        // state of the automaton:
+        // 0: key parsing
+        // 1: antislash found while parsing the key
+        // 2: separator crossing
+        // 3: value parsing
+        int state = 0;
+
+        for (int pos = 0; pos < line.length(); pos++)
+        {
+            char c = line.charAt(pos);
+
+            switch (state)
+            {
+                case 0:
+                    if (c == '\\')
+                    {
+                        state = 1;
+                    }
+                    else if (ArrayUtils.contains(WHITE_SPACE, c))
+                    {
+                        // switch to the separator crossing state
+                        state = 2;
+                    }
+                    else if (ArrayUtils.contains(SEPARATORS, c))
+                    {
+                        // switch to the value parsing state
+                        state = 3;
+                    }
+                    else
+                    {
+                        key.append(c);
+                    }
+
+                    break;
+
+                case 1:
+                    if (ArrayUtils.contains(SEPARATORS, c) || ArrayUtils.contains(WHITE_SPACE, c))
+                    {
+                        // this is an escaped separator or white space
+                        key.append(c);
+                    }
+                    else
+                    {
+                        // another escaped character, the '\' is preserved
+                        key.append('\\');
+                        key.append(c);
+                    }
+
+                    // return to the key parsing state
+                    state = 0;
+
+                    break;
+
+                case 2:
+                    if (ArrayUtils.contains(WHITE_SPACE, c))
+                    {
+                        // do nothing, eat all white spaces
+                    }
+                    else if (ArrayUtils.contains(SEPARATORS, c))
+                    {
+                        // switch to the value parsing state
+                        state = 3;
+                    }
+                    else
+                    {
+                        // any other character indicates we encoutered the beginning of the value
+                        value.append(c);
+
+                        // switch to the value parsing state
+                        state = 3;
+                    }
+
+                    break;
+
+                case 3:
+                    value.append(c);
+                    break;
+            }
+        }
+
+        result[0] = key.toString().trim();
+        result[1] = value.toString().trim();
+
+        return result;
+    }
+
 }

 

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26