* RecordCache.cs: Reduce some extraneous nesting.
[mono.git] / mcs / class / System.Data / System.Data.Common / DbConnectionStringBuilder.cs
index d9b8446483ccd7ccc036f8584cf042418f96475e..65ae0ca516a0dff54e43153c2b0fe9cbd334bc2d 100644 (file)
@@ -31,9 +31,9 @@ using System;
 using System.Text;
 using System.Reflection;
 using System.Collections;
-using System.ComponentModel;
 using System.Collections.Generic;
-
+using System.Collections.ObjectModel;
+using System.ComponentModel;
 using System.Data;
 using System.Data.Common;
 
@@ -44,6 +44,7 @@ namespace System.Data.Common
         {
                 #region Fields
                 Dictionary<string, object> _dictionary = null;
+               bool useOdbcRules;
                 #endregion Fields
 
                 #region Constructors
@@ -52,14 +53,17 @@ namespace System.Data.Common
                         Init ();
                 }
 
-                public DbConnectionStringBuilder (bool useFirstKeyValue)
+                public DbConnectionStringBuilder (bool useOdbcRules)
                 {
-                        throw new NotImplementedException ();
+                       // TODO: if true, quote values using curly braces instead of double-quotes
+                       //       the default is false
+                        //this.useOdbcRules = useOdbcRules; 
+                       throw new NotImplementedException ();
                 }
 
                 private void Init ()
                 {
-                        _dictionary = new Dictionary<string, object> ();
+                        _dictionary = new Dictionary <string, object> (StringComparer.InvariantCultureIgnoreCase);
                 }
 
                 #endregion // Constructors
@@ -82,23 +86,131 @@ namespace System.Data.Common
                         {
                                 IDictionary<string, object> dictionary = (IDictionary <string, object>) _dictionary;
                                 string conn = "";
+                               string parm = "";
                                 foreach (string key in dictionary.Keys) {
-                                        conn += key + "=" + dictionary [key].ToString () + ";";
+                                       string val = dictionary [key].ToString ();              
+                                       bool dquoteFound = (val.IndexOf ("\"") > -1);
+                                       bool squoteFound = (val.IndexOf ("\'") > -1);
+                                       bool semicolonFound = (val.IndexOf (";") > -1);
+                                       bool equalFound = (val.IndexOf ("=") > -1);
+                                       bool braceFound = (val.IndexOf ("{") > -1 || val.IndexOf ("}") > -1);
+                                       if (dquoteFound && squoteFound)
+                                               parm = "\"" + val.Replace ("\"", "\"\"") + "\"";
+                                       else if (squoteFound || braceFound || equalFound || semicolonFound)
+                                               parm = "\"" + val + "\"";
+                                       else if (dquoteFound)
+                                               parm = "\'" + val + "\'";
+                                       else
+                                               parm = val;
+                                               
+                                        conn += key + "=" + parm + ";";
                                 }
                                 conn = conn.TrimEnd (';');
                                 return conn;
                         }
                         set { 
+                               Clear ();
                                if (value == null)
-                                       throw new ArgumentNullException ("ConnectionString cannot be null");
-                               
-                               string [] parameters = value.Split (new char [] {';'});
-                               foreach (string args in parameters) {
-                                       string [] arg = args.Split (new char [] {'='}, 2);
-                                       if (arg.Length == 2) {
-                                               string key = arg [0].Trim ().ToUpper ();
-                                               string val = arg [1].Trim ();
-                                               this [key] = val;
+                                       return;
+                               if (value.Trim ().Length == 0)
+                                       return;
+
+                               string connectionString = value + ";";
+                       
+                               bool inQuote = false;
+                               bool inDQuote = false;
+                               bool inName = true;
+                               int inParen = 0;
+                               int inBraces = 0;
+
+                               string name = String.Empty;
+                               string val = String.Empty;
+                               StringBuilder sb = new StringBuilder ();
+
+                               for (int i = 0; i < connectionString.Length; i += 1) {
+                                       char c = connectionString [i];
+                                       char peek;
+                                       if (i == connectionString.Length - 1)
+                                               peek = '\0';
+                                       else
+                                               peek = connectionString [i + 1];
+
+                                       switch (c) {
+                                       case '\'':
+                                               if (inDQuote)
+                                                       sb.Append (c);
+                                               else if (peek.Equals (c)) {
+                                                       sb.Append (c);
+                                                       i += 1;
+                                               }
+                                               else
+                                                       inQuote = !inQuote;
+                                               break;
+                                       case '"':
+                                               if (inQuote)
+                                                       sb.Append (c);
+                                               else if (peek.Equals (c)) {
+                                                       sb.Append (c);
+                                                       i += 1;
+                                               }
+                                               else
+                                                       inDQuote = !inDQuote;
+                                               break;
+                                       case '(':
+                                               inParen++;
+                                               sb.Append (c);
+                                               break;
+                                       case ')':
+                                               inParen--;
+                                               sb.Append (c);
+                                               break;
+                                       case '{':
+                                               inBraces++;
+                                               sb.Append (c);
+                                               break;
+                                       case '}':
+                                               inBraces--;
+                                               sb.Append (c);
+                                               break;
+                                       case ';':
+                                               if (inDQuote || inQuote)
+                                                       sb.Append (c);
+                                               else {
+                                                       if (name != String.Empty && name != null) {
+                                                               val = sb.ToString ();
+                                                               name = name.ToLower ().Trim ();
+                                                               this [name] = val;
+                                                       }
+                                                       else if (sb.Length != 0)
+                                                               throw new ArgumentException ("Format of initialization string does not conform to specifications");
+                                                       inName = true;
+                                                       name = String.Empty;
+                                                       value = String.Empty;
+                                                       sb = new StringBuilder ();
+                                               }
+                                               break;
+                                       case '=':
+                                               if (inDQuote || inQuote || !inName || inParen > 0 || inBraces > 0)
+                                                       sb.Append (c);
+                                               else if (peek.Equals (c)) {
+                                                       sb.Append (c);
+                                                       i += 1;
+                                               }
+                                               else {
+                                                       name = sb.ToString ();
+                                                       sb = new StringBuilder ();
+                                                       inName = false;
+                                               }
+                                               break;
+                                       case ' ':
+                                               if (inQuote || inDQuote)
+                                                       sb.Append (c);
+                                               else if (sb.Length > 0 && !peek.Equals (';'))
+                                                       sb.Append (c);
+                                               break;
+                                       default:
+                                               sb.Append (c);
+                                               break;
                                        }
                                }
                        }
@@ -130,7 +242,7 @@ namespace System.Data.Common
                                 if (ContainsKey (keyword))
                                         return _dictionary [keyword];
                                 else
-                                        throw new ArgumentException ();
+                                        throw new ArgumentException ("Keyword does not exist");
                         }
                         set { Add (keyword, value); }
                 }
@@ -138,7 +250,12 @@ namespace System.Data.Common
                [Browsable (false)]
                 public virtual ICollection Keys
                 {
-                        get { return _dictionary.Keys; }
+                        get { 
+                               string [] keys = new string [_dictionary.Keys.Count];
+                               ((ICollection<string>) _dictionary.Keys).CopyTo (keys, 0);
+                               ReadOnlyCollection<string> keyColl = new ReadOnlyCollection<string> (keys);
+                               return keyColl; 
+                       }
                 }
 
                 bool ICollection.IsSynchronized
@@ -160,7 +277,12 @@ namespace System.Data.Common
                [Browsable (false)]
                 public virtual ICollection Values
                 {
-                        get { return _dictionary.Values; }
+                        get { 
+                               object [] values = new object [_dictionary.Values.Count];
+                               ((ICollection<object>) _dictionary.Values).CopyTo (values, 0);
+                               ReadOnlyCollection<object> valuesColl = new ReadOnlyCollection<object> (values);
+                               return valuesColl; 
+                       }
                 }
 
                 #endregion // Properties
@@ -171,6 +293,10 @@ namespace System.Data.Common
 
                 public void Add (string keyword, object value)
                 {
+                       if (keyword == null || keyword.Trim () == "")
+                               throw new ArgumentException ("Keyword should not be emtpy");
+                       if (value == null)
+                               throw new ArgumentException ("Value should not be null");
                         if (ContainsKey (keyword)) {
                                 _dictionary [keyword] = value;
                         } else {
@@ -179,11 +305,15 @@ namespace System.Data.Common
 
                 }
 
-               [MonoTODO]
-               public static void AppendKeyValuePair(StringBuilder builder, string keyword, string value,
-                                                     bool useOdbcRules)
+               [MonoLimitation("useOdbcRules set to true is not supported")]
+               public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value,
+                                                      bool useOdbcRules)
                {
-                       throw new NotImplementedException ();
+                       if (useOdbcRules == false) {
+                               AppendKeyValuePair (builder, keyword, value);
+                       } else {
+                               throw new NotImplementedException ();
+                       }
                }
 
                 public static void AppendKeyValuePair (StringBuilder builder, string keyword, string value)
@@ -205,6 +335,8 @@ namespace System.Data.Common
 
                 public virtual bool ContainsKey (string keyword)
                 {
+                       if (keyword == null)
+                               throw new ArgumentNullException ("Invalid argument", keyword);
                         return _dictionary.ContainsKey (keyword);
                 }
 
@@ -222,18 +354,19 @@ namespace System.Data.Common
                                                 }
                                         }
                                 }
-                        } catch (ArgumentException e) {
+                        } catch (ArgumentException) {
                                 ret = false;
                         }
                         return ret;
                 }
 
                [MonoTODO]
-               protected virtual void GetProperties(Hashtable propertyDescriptors)
+               protected virtual void GetProperties (Hashtable propertyDescriptors)
                {
                        throw new NotImplementedException ();
                }
 
+               [MonoTODO]
                protected internal void ClearPropertyDescriptors ()
                {
                        throw new NotImplementedException ();