diff tango/tango/text/locale/Parse.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tango/tango/text/locale/Parse.d	Fri Jan 11 17:57:40 2008 +0100
@@ -0,0 +1,303 @@
+/*******************************************************************************
+
+        copyright:      Copyright (c) 2005 John Chapman. All rights reserved
+
+        license:        BSD style: $(LICENSE)
+
+        version:        Initial release: 2005
+
+        author:         John Chapman
+
+******************************************************************************/
+
+module tango.text.locale.Parse;
+
+private import  tango.time.WallClock;
+
+private import  tango.core.Exception;
+
+private import  tango.text.locale.Core;
+
+private import  tango.time.chrono.Calendar;
+
+private struct DateTimeParseResult {
+
+  int year = -1;
+  int month = -1;
+  int day = -1;
+  int hour;
+  int minute;
+  int second;
+  double fraction;
+  int timeMark;
+  Calendar calendar;
+  TimeSpan timeZoneOffset;
+  Time parsedDate;
+
+}
+
+package Time parseTime(char[] s, DateTimeFormat dtf) {
+  DateTimeParseResult result;
+  if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, result))
+    throw new IllegalArgumentException("String was not a valid Time.");
+  return result.parsedDate;
+}
+
+package Time parseTimeExact(char[] s, char[] format, DateTimeFormat dtf) {
+  DateTimeParseResult result;
+  if (!tryParseExact(s, format, dtf, result))
+    throw new IllegalArgumentException("String was not a valid Time.");
+  return result.parsedDate;
+}
+
+package bool tryParseTime(char[] s, DateTimeFormat dtf, out Time result) {
+  result = Time.min;
+  DateTimeParseResult resultRecord;
+  if (!tryParseExactMultiple(s, dtf.getAllDateTimePatterns(), dtf, resultRecord))
+    return false;
+  result = resultRecord.parsedDate;
+  return true;
+}
+
+package bool tryParseTimeExact(char[] s, char[] format, DateTimeFormat dtf, out Time result) {
+  result = Time.min;
+  DateTimeParseResult resultRecord;
+  if (!tryParseExact(s, format, dtf, resultRecord))
+    return false;
+  result = resultRecord.parsedDate;
+  return true;
+}
+
+private bool tryParseExactMultiple(char[] s, char[][] formats, DateTimeFormat dtf, inout DateTimeParseResult result) {
+  foreach (char[] format; formats) {
+    if (tryParseExact(s, format, dtf, result))
+      return true;
+  }
+  return false;
+}
+
+private bool tryParseExact(char[] s, char[] pattern, DateTimeFormat dtf, inout DateTimeParseResult result) {
+
+  bool doParse() {
+
+    int parseDigits(char[] s, inout int pos, int max) {
+      int result = s[pos++] - '0';
+      while (max > 1 && pos < s.length && s[pos] >= '0' && s[pos] <= '9') {
+        result = result * 10 + s[pos++] - '0';
+        --max;
+      }
+      return result;
+    }
+
+    bool parseOne(char[] s, inout int pos, char[] value) {
+      if (s[pos .. pos + value.length] != value)
+        return false;
+      pos += value.length;
+      return true;
+    }
+
+    int parseMultiple(char[] s, inout int pos, char[][] values ...) {
+      int result = -1, max;
+      foreach (int i, char[] value; values) {
+        if (value.length == 0 || s.length - pos < value.length)
+          continue;
+
+        if (s[pos .. pos + value.length] == value) {
+          if (result == 0 || value.length > max) {
+            result = i + 1;
+            max = value.length;
+          }
+        }
+      }
+      pos += max;
+      return result;
+    }
+
+    TimeSpan parseTimeZoneOffset(char[] s, inout int pos) {
+      bool sign;
+      if (pos < s.length) {
+        if (s[pos] == '-') {
+          sign = true;
+          pos++;
+        }
+        else if (s[pos] == '+')
+          pos++;
+      }
+      int hour = parseDigits(s, pos, 2);
+      int minute;
+      if (pos < s.length && s[pos] == ':') {
+        pos++;
+        minute = parseDigits(s, pos, 2);
+      }
+      //Due to dmd bug, this doesn't compile
+      //TimeSpan result = TimeSpan.hours(hour) +  TimeSpan.minutes(minute);
+      TimeSpan result = TimeSpan(TimeSpan.TicksPerHour * hour +  TimeSpan.TicksPerMinute * minute);
+      if (sign)
+        result = -result;
+      return result;
+    }
+      
+    char[] stringOf(char c, int count = 1) {
+      char[] s = new char[count];
+      s[0 .. count] = c;
+      return s;
+    }
+
+    result.calendar = dtf.calendar;
+    result.year = result.month = result.day = -1;
+    result.hour = result.minute = result.second = 0;
+    result.fraction = 0.0;
+
+    int pos, i, count;
+    char c;
+
+    while (pos < pattern.length && i < s.length) {
+      c = pattern[pos++];
+
+      if (c == ' ') {
+        i++;
+        while (i < s.length && s[i] == ' ')
+          i++;
+        if (i >= s.length)
+          break;
+        continue;
+      }
+
+      count = 1;
+
+      switch (c) {
+        case 'd': case 'm': case 'M': case 'y':
+        case 'h': case 'H': case 's':
+        case 't': case 'z':
+          while (pos < pattern.length && pattern[pos] == c) {
+            pos++;
+            count++;
+          }
+          break;
+        case ':':
+          if (!parseOne(s, i, dtf.timeSeparator))
+            return false;
+          continue;
+        case '/':
+          if (!parseOne(s, i, dtf.dateSeparator))
+            return false;
+          continue;
+        case '\\':
+          if (pos < pattern.length) {
+            c = pattern[pos++];
+            if (s[i++] != c)
+              return false;
+          }
+          else
+            return false;
+          continue;
+        case '\'':
+          while (pos < pattern.length) {
+            c = pattern[pos++];
+            if (c == '\'')
+              break;
+            if (s[i++] != c)
+              return false;
+          }
+          continue;
+        default:
+          if (s[i++] != c)
+            return false;
+          continue;
+      }
+
+      switch (c) {
+        case 'd': // day
+          if (count == 1 || count == 2)
+            result.day = parseDigits(s, i, 2);
+          else if (count == 3)
+            result.day = parseMultiple(s, i, dtf.abbreviatedDayNames);
+          else
+            result.day = parseMultiple(s, i, dtf.dayNames);
+          if (result.day == -1)
+            return false;
+          break;
+        case 'M': // month
+          if (count == 1 || count == 2)
+            result.month = parseDigits(s, i, 2);
+          else if (count == 3)
+            result.month = parseMultiple(s, i, dtf.abbreviatedMonthNames);
+          else
+            result.month = parseMultiple(s, i, dtf.monthNames);
+          if (result.month == -1)
+            return false;
+          break;
+        case 'y': // year
+          if (count == 1 || count == 2)
+            result.year = parseDigits(s, i, 2);
+          else
+            result.year = parseDigits(s, i, 4);
+          if (result.year == -1)
+            return false;
+          break;
+        case 'h': // 12-hour clock
+        case 'H': // 24-hour clock
+          result.hour = parseDigits(s, i, 2);
+          break;
+        case 'm': // minute
+          result.minute = parseDigits(s, i, 2);
+          break;
+        case 's': // second
+          result.second = parseDigits(s, i, 2);
+          break;
+        case 't': // time mark
+          if (count == 1)
+            result.timeMark = parseMultiple(s, i, stringOf(dtf.amDesignator[0]), stringOf(dtf.pmDesignator[0]));
+          else
+            result.timeMark = parseMultiple(s, i, dtf.amDesignator, dtf.pmDesignator);
+          break;
+        case 'z':
+          result.timeZoneOffset = parseTimeZoneOffset(s, i);
+          break;
+        default:
+          break;
+      }
+    }
+
+    if (pos < pattern.length || i < s.length)
+      return false;
+
+    if (result.timeMark == 1) { // am
+      if (result.hour == 12)
+        result.hour = 0;
+    }
+    else if (result.timeMark == 2) { // pm
+      if (result.hour < 12)
+        result.hour += 12;
+    }
+
+    // If the input string didn't specify a date part, try to return something meaningful.
+    if (result.year == -1 || result.month == -1 || result.day == -1) {
+      Time now = WallClock.now;
+      if (result.month == -1 && result.day == -1) {
+        if (result.year == -1) {
+          result.year = result.calendar.getYear(now);
+          result.month = result.calendar.getMonth(now);
+          result.day = result.calendar.getDayOfMonth(now);
+        }
+        else
+          result.month = result.day = 1;
+      }
+      else {
+        if (result.year == -1)
+          result.year = result.calendar.getYear(now);
+        if (result.month == -1)
+          result.month = 1;
+        if (result.day == -1)
+          result.day = 1;
+      }
+    }
+    return true;
+  }
+
+  if (doParse()) {
+    result.parsedDate = result.calendar.toTime(result.year, result.month, result.day, result.hour, result.minute, result.second, 0);
+    return true;
+  }
+  return false;
+}