? .PropertyDictionary.cs.swp
? dateliterals.patch
? Tasks/ExecTask.old_cs
? Tasks/ExternalProgramBase.old_cs
Index: DirectoryScanner.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core/DirectoryScanner.cs,v
retrieving revision 1.26
diff -u -r1.26 DirectoryScanner.cs
--- DirectoryScanner.cs	28 Jan 2004 19:47:37 -0000	1.26
+++ DirectoryScanner.cs	22 Feb 2004 22:31:49 -0000
@@ -332,7 +332,7 @@
                 searchDirectory = new DirectoryInfo(Path.Combine(
                     BaseDirectory.FullName, s)).FullName;
             }
-            
+
             string modifiedNAntPattern = originalNAntPattern.Substring(indexOfLastDirectorySeparator + 1);
             bool caseInsensitiveFS = !IsCaseSensitiveFileSystem(searchDirectory);
             
Index: ExpressionEvalBase.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core/ExpressionEvalBase.cs,v
retrieving revision 1.14
diff -u -r1.14 ExpressionEvalBase.cs
--- ExpressionEvalBase.cs	22 Feb 2004 18:41:55 -0000	1.14
+++ ExpressionEvalBase.cs	22 Feb 2004 22:31:50 -0000
@@ -23,6 +23,7 @@
 using System.Globalization;
 using System.Reflection;
 using System.Text;
+using System.Text.RegularExpressions;
 
 namespace NAnt.Core {
     public abstract class ExpressionEvalBase {
@@ -443,6 +444,20 @@
                 }
             }
 
+            if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.SquareBracketLiteral) {
+                ExpressionTokenizer.Position p0 = _tokenizer.CurrentPosition;
+                string s = _tokenizer.TokenText;
+                ExpressionTokenizer.Position p1 = _tokenizer.CurrentPosition;
+                _tokenizer.GetNextToken();
+
+                object v = null;
+
+                if (!SyntaxCheckOnly()) {
+                    v = GetSquareBracketLiteralValue(s, p0, p1);
+                }
+                return v;
+            }
+
             if (_tokenizer.CurrentToken == ExpressionTokenizer.TokenType.Minus) {
                 _tokenizer.GetNextToken();
 
@@ -616,19 +631,180 @@
             return UnexpectedToken();
         }
 
-        protected ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0) {
+
+        private static DateTime DateTimeFromRegexMatch(Match m) {
+            int yyyy = Convert.ToInt32(m.Groups[1].Value);
+            int mm = Convert.ToInt32(m.Groups[2].Value);
+            int dd = Convert.ToInt32(m.Groups[3].Value);
+            int hh = 0;
+            int mi = 0;
+            int ss = 0;
+            int ms = 0;
+
+            if (m.Groups.Count > 4) {
+                hh = Convert.ToInt32(m.Groups[4].Value);
+            }
+            if (m.Groups.Count > 5) {
+                mi = Convert.ToInt32(m.Groups[5].Value);
+            }
+            if (m.Groups.Count > 6) {
+                ss = Convert.ToInt32(m.Groups[6].Value);
+            }
+            if (m.Groups.Count > 7) {
+                ms = Convert.ToInt32(m.Groups[7].Value);
+            }
+
+            DateTime retVal = new DateTime(yyyy, mm, dd, hh, mi, ss, ms);
+            return retVal;
+        }
+
+        private static TimeSpan TimeSpanFromRegexMatch(Match m) {
+            int hh = Convert.ToInt32(m.Groups[1].Value);
+            int mi = Convert.ToInt32(m.Groups[2].Value);
+            int ss = Convert.ToInt32(m.Groups[3].Value);
+            int ms = 0;
+
+            if (m.Groups.Count > 4) {
+                ms = Convert.ToInt32(m.Groups[4].Value);
+            }
+            
+            TimeSpan retVal = new TimeSpan(0, hh, mi, ss, ms);
+            return retVal;
+        }
+
+        private static TimeSpan TimeSpanFromLongRegexMatch(Match m) {
+            int dd = Convert.ToInt32(m.Groups[1].Value);
+            int hh = Convert.ToInt32(m.Groups[2].Value);
+            int mi = Convert.ToInt32(m.Groups[3].Value);
+            int ss = Convert.ToInt32(m.Groups[4].Value);
+            int ms = 0;
+
+            if (m.Groups.Count > 5) {
+                ms = Convert.ToInt32(m.Groups[5].Value);
+            }
+            
+            TimeSpan retVal = new TimeSpan(dd, hh, mi, ss, ms);
+            return retVal;
+        }
+
+        private static Regex dateRegex1 = new Regex(@"^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)\.(\d+)$", RegexOptions.Compiled);
+        private static Regex dateRegex2 = new Regex(@"^(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)$", RegexOptions.Compiled);
+        private static Regex dateRegex3 = new Regex(@"^(\d+)-(\d+)-(\d+) (\d+):(\d+)$", RegexOptions.Compiled);
+        private static Regex dateRegex4 = new Regex(@"^(\d+)-(\d+)-(\d+)$", RegexOptions.Compiled);
+        
+        private static Regex timespanRegex1 = new Regex(@"^(\d+):(\d+):(\d+)\.(\d{3})$", RegexOptions.Compiled);
+        private static Regex timespanRegex2 = new Regex(@"^(\d+):(\d+):(\d+)$", RegexOptions.Compiled);
+        
+        private static Regex timespanRegex3 = new Regex(@"^(\d+):(\d+):(\d+):(\d+)\.(\d+)$", RegexOptions.Compiled);
+        private static Regex timespanRegex4 = new Regex(@"^(\d+):(\d+):(\d+):(\d+)$", RegexOptions.Compiled);
+
+        private static object ConvertStringToTimeSpan(string literal) {
+            Match m;
+            m = timespanRegex1.Match(literal);
+            if (m.Success) {
+                return TimeSpanFromRegexMatch(m);
+            }
+
+            m = timespanRegex2.Match(literal);
+            if (m.Success) {
+                return TimeSpanFromRegexMatch(m);
+            }
+            
+            m = timespanRegex3.Match(literal);
+            if (m.Success) {
+                return TimeSpanFromLongRegexMatch(m);
+            }
+            
+            m = timespanRegex4.Match(literal);
+            if (m.Success) {
+                return TimeSpanFromLongRegexMatch(m);
+            }
+
+            return null;
+        }
+
+        private static object ConvertStringToDateTime(string literal) {
+            Match m;
+
+            m = dateRegex1.Match(literal);
+            if (m.Success) {
+                return DateTimeFromRegexMatch(m);
+            }
+
+            m = dateRegex2.Match(literal);
+            if (m.Success) {
+                return DateTimeFromRegexMatch(m);
+            }
+
+            m = dateRegex3.Match(literal);
+            if (m.Success) {
+                return DateTimeFromRegexMatch(m);
+            }
+
+            m = dateRegex4.Match(literal);
+            if (m.Success) {
+                return DateTimeFromRegexMatch(m);
+            }
+
+            return null;
+        }
+        
+        private static string ConvertDateTimeToString(DateTime dt) {
+            StringBuilder sb = new StringBuilder();
+            sb.AppendFormat("{0,4}-{1,2:00}-{2,2:00}", dt.Year, dt.Month, dt.Day);
+
+            if (dt.Hour != 0 || dt.Minute != 0 || dt.Second != 0 || dt.Millisecond != 0) {
+                sb.AppendFormat(" {0,2:00}:{1,2:00}:{2,2:00}", dt.Hour, dt.Minute, dt.Second);
+                if (dt.Millisecond != 0) {
+                    sb.AppendFormat(".{0,3:000}", dt.Millisecond % 1000);
+                }
+            }
+
+            return sb.ToString();
+        }
+
+        private static string ConvertTimeSpanToString(TimeSpan ts) {
+            StringBuilder sb = new StringBuilder();
+            
+            if ((int)ts.TotalDays > 0) {
+                sb.AppendFormat("{0}:", (int)ts.TotalDays);
+            }
+
+            int seconds = (int)ts.TotalSeconds % 86400;
+            sb.AppendFormat("{0,2:00}:{1,2:00}:{2,2:00}", seconds / 3600, (seconds % 3600) / 60, seconds % 60);
+            if (ts.TotalMilliseconds != 0) {
+                sb.AppendFormat(".{0,3:000}", ts.TotalMilliseconds % 1000);
+            }
+            return sb.ToString();
+        }
+
+        public static object GetSquareBracketLiteralValue(string literal, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1) {
+            object o = ConvertStringToDateTime(literal);
+            if (o != null)
+                return o;
+            
+            o = ConvertStringToTimeSpan(literal);
+            if (o != null)
+                return o;
+
+            throw BuildParseError(string.Format(CultureInfo.InvariantCulture, 
+                        "Unknown literal value: '{0}'.", 
+                        literal), p0, p1);
+        }
+
+        protected internal static ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0) {
             return new ExpressionParseException(desc, p0.CharIndex);
         }
         
-        protected ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1) {
+        protected internal static ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1) {
             return new ExpressionParseException(desc, p0.CharIndex, p1.CharIndex);
         }
         
-        protected ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1, Exception ex) {
+        protected internal static ExpressionParseException BuildParseError(string desc, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1, Exception ex) {
             return new ExpressionParseException(desc, p0.CharIndex, p1.CharIndex, ex);
         }
 
-        protected object SafeConvert(Type returnType, object source, string description, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1) {
+        protected internal static object SafeConvert(Type returnType, object source, string description, ExpressionTokenizer.Position p0, ExpressionTokenizer.Position p1) {
             try {
                 //
                 // TODO - Convert.ChangeType() is very liberal. It allows you to convert "true" to Double (1.0).
@@ -664,6 +840,12 @@
                     if (returnType != typeof(string) && returnType != typeof(DateTime)) {
                         // DateTime can only be converted to string or DateTime
                         disallow = true;
+                    } else {
+                        if (returnType == typeof(string)) {
+                            return ConvertDateTimeToString((DateTime)source);
+                        } else {
+                            return source;
+                        }
                     }
                 }
 
@@ -671,14 +853,51 @@
                     if (!(source is DateTime || source is string)) {
                         // only string and DateTime can be converted to DateTime
                         disallow = true;
+                    } else {
+                        if (source is DateTime)
+                            return source;
+
+                        object v = ConvertStringToDateTime((string)source);
+                        if (v == null) {
+
+                            throw BuildParseError(string.Format(CultureInfo.InvariantCulture, 
+                                        "Cannot convert {0} to '{1}' (invalid date format).", 
+                                        description, GetSimpleTypeName(returnType)), p0, p1);
+                        }
+                        return v;
                     }
                 }
 
-                // Horrible hack to work around this mono bug:
-                // http://bugs.ximian.com/show_bug.cgi?id=53919
-                // Be sure to remove once that bug is fixed.
-                if (returnType == typeof(TimeSpan) && source.GetType() == typeof(TimeSpan)) {
-                    return (TimeSpan) source;
+                if (source.GetType() == typeof(TimeSpan)) {
+                    if (returnType != typeof(string) && returnType != typeof(TimeSpan)) {
+                        // TimeSpan can only be converted to string or TimeSpan
+                        disallow = true;
+                    } else {
+                        if (returnType == typeof(string)) {
+                            return ConvertTimeSpanToString((TimeSpan)source);
+                        } else {
+                            return source;
+                        }
+                    }
+                }
+
+                if (returnType == typeof(TimeSpan)) {
+                    if (!(source is TimeSpan || source is string)) {
+                        // only string and TimeSpan can be converted to TimeSpan
+                        disallow = true;
+                    } else {
+                        if (source is TimeSpan)
+                            return source;
+
+                        object v = ConvertStringToTimeSpan((string)source);
+                        if (v == null) {
+
+                            throw BuildParseError(string.Format(CultureInfo.InvariantCulture, 
+                                        "Cannot convert {0} to '{1}' (invalid timespan format).", 
+                                        description, GetSimpleTypeName(returnType)), p0, p1);
+                        }
+                        return v;
+                    }
                 }
 
                 if (returnType == typeof(string)) {
@@ -707,7 +926,7 @@
             }
         }
 
-        protected string GetSimpleTypeName(Type t) {
+        protected internal static string GetSimpleTypeName(Type t) {
             if (t == typeof(int)) {
                 return "integer";
             } else if (t == typeof(double)) {
Index: ExpressionTokenizer.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core/ExpressionTokenizer.cs,v
retrieving revision 1.3
diff -u -r1.3 ExpressionTokenizer.cs
--- ExpressionTokenizer.cs	28 Dec 2003 21:42:44 -0000	1.3
+++ ExpressionTokenizer.cs	22 Feb 2004 22:31:50 -0000
@@ -50,6 +50,7 @@
             Number,
             String,
             Keyword,
+            SquareBracketLiteral,
             EQ,
             NE,
             LT,
@@ -168,6 +169,24 @@
                     return ;
                 }
 
+                if (ch == '[')
+                {
+                    StringBuilder sb = new StringBuilder();
+                    int ch2;
+
+                    ReadChar();
+                    while ((ch2 = ReadChar()) != -1) {
+                        if (ch2 == ']') {
+                            break;
+                        }
+                        sb.Append((char)ch2);
+                    };
+
+                    _tokenType = TokenType.SquareBracketLiteral;
+                    _tokenText = sb.ToString();
+                    return ;
+                }
+
                 if (Char.IsDigit(ch)) {
                     _tokenType = TokenType.Number;
                     string s = "";
Index: PropertyDictionary.cs
===================================================================
RCS file: /cvsroot/nant/nant/src/NAnt.Core/PropertyDictionary.cs,v
retrieving revision 1.22
diff -u -r1.22 PropertyDictionary.cs
--- PropertyDictionary.cs	25 Jan 2004 09:54:17 -0000	1.22
+++ PropertyDictionary.cs	22 Feb 2004 22:31:51 -0000
@@ -350,7 +350,14 @@
                             tokenizer.SingleCharacterMode = false;
                             tokenizer.GetNextToken();
 
-                            string val = Convert.ToString(eval.Evaluate(tokenizer), CultureInfo.InvariantCulture);
+                            ExpressionTokenizer.Position p0 = tokenizer.CurrentPosition;
+                            object evalResult = eval.Evaluate(tokenizer);
+                            ExpressionTokenizer.Position p1 = tokenizer.CurrentPosition;
+
+                            string val = (string)ExpressionEvaluator.SafeConvert(
+                                    typeof(string), 
+                                    evalResult,
+                                    "expression result", p0, p1);
                             output.Append(val);
                             tokenizer.IgnoreWhitespace = false;
 
