]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/datetimefmt.cpp
set icons bundle, not single icon, for frames loaded from XRC
[wxWidgets.git] / src / common / datetimefmt.cpp
index 2bd9b8b0c569ee8e7ad854efaa6acb3e31f78eda..91d64529812854cee56afa35f1837809d67531ae 100644 (file)
@@ -92,42 +92,6 @@ static const int MIN_PER_HOUR = 60;
 namespace
 {
 
-#ifdef HAVE_STRPTIME
-
-#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL)
-    // configure detected that we had strptime() but not its declaration,
-    // provide it ourselves
-    extern "C" char *strptime(const char *, const char *, struct tm *);
-#endif
-
-// strptime() wrapper: call strptime() for the string starting at the given
-// iterator and fill output tm struct with the results and modify input to
-// point to the end of the string consumed by strptime() if successful,
-// otherwise return false and don't modify anything
-bool
-CallStrptime(const wxString& str,
-             wxString::const_iterator& p,
-             const char *fmt,
-             tm *tm)
-{
-    // convert from iterator to char pointer: this is simple as wxCStrData
-    // already supports this
-    const char * const start = str.c_str() + (p - str.begin());
-
-    const char * const end = strptime(start, fmt, tm);
-    if ( !end )
-        return false;
-
-    // convert back from char pointer to iterator: unfortunately we have no way
-    // to do it efficiently currently so create a temporary string just to
-    // compute the number of characters between start and end
-    p += wxString(start, end - start).length();
-
-    return true;
-}
-
-#endif // HAVE_STRPTIME
-
 enum
 {
     DateLang_English = 1,
@@ -237,11 +201,12 @@ GetWeekDayFromName(const wxString& name, int flags, int lang)
 // scans all digits (but no more than len) and returns the resulting number
 bool GetNumericToken(size_t len,
                      wxString::const_iterator& p,
+                     const wxString::const_iterator& end,
                      unsigned long *number)
 {
     size_t n = 1;
     wxString s;
-    while ( wxIsdigit(*p) )
+    while ( p != end && wxIsdigit(*p) )
     {
         s += *p++;
 
@@ -253,10 +218,12 @@ bool GetNumericToken(size_t len,
 }
 
 // scans all alphabetic characters and returns the resulting string
-wxString GetAlphaToken(wxString::const_iterator& p)
+wxString
+GetAlphaToken(wxString::const_iterator& p,
+              const wxString::const_iterator& end)
 {
     wxString s;
-    while ( wxIsalpha(*p) )
+    while ( p != end && wxIsalpha(*p) )
     {
         s += *p++;
     }
@@ -278,15 +245,13 @@ ParseFormatAt(wxString::const_iterator& p,
               // FIXME-VC6: using wxString() instead of wxEmptyString in the
               //            line below results in error C2062: type 'class
               //            wxString (__cdecl *)(void)' unexpected
-              const wxString& fmtAlt = wxEmptyString,
-              const wxString& fmtAlt2 = wxString())
+              const wxString& fmtAlt = wxEmptyString)
 {
     const wxString str(p, end);
     wxString::const_iterator endParse;
     wxDateTime dt;
     if ( dt.ParseFormat(str, fmt, &endParse) ||
-            (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) ||
-                (!fmtAlt2.empty() && dt.ParseFormat(str, fmtAlt2, &endParse)) )
+            (!fmtAlt.empty() && dt.ParseFormat(str, fmtAlt, &endParse)) )
     {
         p += endParse - str.begin();
     }
@@ -898,174 +863,14 @@ wxDateTime::ParseRfc822Date(const wxString& date, wxString::const_iterator *end)
     return true;
 }
 
-#ifdef __WINDOWS__
-
-// returns the string containing strftime() format used for short dates in the
-// current locale or an empty string
-static wxString GetLocaleDateFormat()
-{
-    wxString fmtWX;
-
-    // there is no setlocale() under Windows CE, so just always query the
-    // system there
-#ifndef __WXWINCE__
-    if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 )
-#endif
-    {
-        // The locale was programatically set to non-C. We assume that this was
-        // done using wxLocale, in which case thread's current locale is also
-        // set to correct LCID value and we can use GetLocaleInfo to determine
-        // the correct formatting string:
-#ifdef __WXWINCE__
-        LCID lcid = LOCALE_USER_DEFAULT;
-#else
-        LCID lcid = GetThreadLocale();
-#endif
-        // according to MSDN 80 chars is max allowed for short date format
-        wxChar fmt[81];
-        if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) )
-        {
-            wxChar chLast = _T('\0');
-            size_t lastCount = 0;
-            for ( const wxChar *p = fmt; /* NUL handled inside */; p++ )
-            {
-                if ( *p == chLast )
-                {
-                    lastCount++;
-                    continue;
-                }
-
-                switch ( *p )
-                {
-                    // these characters come in groups, start counting them
-                    case _T('d'):
-                    case _T('M'):
-                    case _T('y'):
-                    case _T('g'):
-                        chLast = *p;
-                        lastCount = 1;
-                        break;
-
-                    default:
-                        // first deal with any special characters we have had
-                        if ( lastCount )
-                        {
-                            switch ( chLast )
-                            {
-                                case _T('d'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // d
-                                        case 2: // dd
-                                            // these two are the same as we
-                                            // don't distinguish between 1 and
-                                            // 2 digits for days
-                                            fmtWX += _T("%d");
-                                            break;
-
-                                        case 3: // ddd
-                                            fmtWX += _T("%a");
-                                            break;
-
-                                        case 4: // dddd
-                                            fmtWX += _T("%A");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("too many 'd's") );
-                                    }
-                                    break;
-
-                                case _T('M'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // M
-                                        case 2: // MM
-                                            // as for 'd' and 'dd' above
-                                            fmtWX += _T("%m");
-                                            break;
-
-                                        case 3:
-                                            fmtWX += _T("%b");
-                                            break;
-
-                                        case 4:
-                                            fmtWX += _T("%B");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("too many 'M's") );
-                                    }
-                                    break;
-
-                                case _T('y'):
-                                    switch ( lastCount )
-                                    {
-                                        case 1: // y
-                                        case 2: // yy
-                                            fmtWX += _T("%y");
-                                            break;
-
-                                        case 4: // yyyy
-                                            fmtWX += _T("%Y");
-                                            break;
-
-                                        default:
-                                            wxFAIL_MSG( _T("wrong number of 'y's") );
-                                    }
-                                    break;
-
-                                case _T('g'):
-                                    // strftime() doesn't have era string,
-                                    // ignore this format
-                                    wxASSERT_MSG( lastCount <= 2,
-                                                  _T("too many 'g's") );
-                                    break;
-
-                                default:
-                                    wxFAIL_MSG( _T("unreachable") );
-                            }
-
-                            chLast = _T('\0');
-                            lastCount = 0;
-                        }
-
-                        // not a special character so must be just a separator,
-                        // treat as is
-                        if ( *p != _T('\0') )
-                        {
-                            if ( *p == _T('%') )
-                            {
-                                // this one needs to be escaped
-                                fmtWX += _T('%');
-                            }
-
-                            fmtWX += *p;
-                        }
-                }
-
-                if ( *p == _T('\0') )
-                    break;
-            }
-        }
-        //else: GetLocaleInfo() failed, leave fmtDate value unchanged and
-        //      try our luck with the default formats
-    }
-    //else: default C locale, default formats should work
-
-    return fmtWX;
-}
-
-#endif // __WINDOWS__
-
 bool
 wxDateTime::ParseFormat(const wxString& date,
                         const wxString& format,
                         const wxDateTime& dateDef,
-                        wxString::const_iterator *end)
+                        wxString::const_iterator *endParse)
 {
     wxCHECK_MSG( !format.empty(), false, "format can't be empty" );
-    wxCHECK_MSG( end, false, "end iterator pointer must be specified" );
+    wxCHECK_MSG( endParse, false, "end iterator pointer must be specified" );
 
     wxString str;
     unsigned long num;
@@ -1096,6 +901,7 @@ wxDateTime::ParseFormat(const wxString& date,
     int year = 0;
 
     wxString::const_iterator input = date.begin();
+    const wxString::const_iterator end = date.end();
     for ( wxString::const_iterator fmt = format.begin(); fmt != format.end(); ++fmt )
     {
         if ( *fmt != _T('%') )
@@ -1104,7 +910,7 @@ wxDateTime::ParseFormat(const wxString& date,
             {
                 // a white space in the format string matches 0 or more white
                 // spaces in the input
-                while ( wxIsspace(*input) )
+                while ( input != end && wxIsspace(*input) )
                 {
                     input++;
                 }
@@ -1113,7 +919,7 @@ wxDateTime::ParseFormat(const wxString& date,
             {
                 // any other character (not whitespace, not '%') must be
                 // matched by itself in the input
-                if ( *input++ != *fmt )
+                if ( input == end || *input++ != *fmt )
                 {
                     // no match
                     return false;
@@ -1166,7 +972,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 {
                     wday = GetWeekDayFromName
                            (
-                            GetAlphaToken(input),
+                            GetAlphaToken(input, end),
                             *fmt == 'a' ? Name_Abbr : Name_Full,
                             DateLang_Local
                            );
@@ -1184,7 +990,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 {
                     mon = GetMonthFromName
                           (
-                            GetAlphaToken(input),
+                            GetAlphaToken(input, end),
                             *fmt == 'b' ? Name_Abbr : Name_Full,
                             DateLang_Local
                           );
@@ -1199,49 +1005,38 @@ wxDateTime::ParseFormat(const wxString& date,
 
             case _T('c'):       // locale default date and time  representation
                 {
-#ifdef HAVE_STRPTIME
-                    struct tm tm;
+                    wxDateTime dt;
 
-                    // try using strptime() -- it may fail even if the input is
-                    // correct but the date is out of range, so we will fall back
-                    // to our generic code anyhow
-                    if ( CallStrptime(date, input, "%c", &tm) )
-                    {
-                        hour = tm.tm_hour;
-                        min = tm.tm_min;
-                        sec = tm.tm_sec;
+                    const wxString
+                        fmtDateTime = wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT);
+                    if ( !fmtDateTime.empty() )
+                        dt = ParseFormatAt(input, end, fmtDateTime);
 
-                        year = 1900 + tm.tm_year;
-                        mon = (Month)tm.tm_mon;
-                        mday = tm.tm_mday;
+                    if ( !dt.IsValid() )
+                    {
+                        // also try the format which corresponds to ctime()
+                        // output (i.e. the "C" locale default)
+                        dt = ParseFormatAt(input, end, wxS("%a %b %d %H:%M:%S %Y"));
                     }
-                    else // strptime() failed; try generic heuristic code
-#endif // HAVE_STRPTIME
+
+                    if ( !dt.IsValid() )
                     {
+                        // and finally also the two generic date/time formats
+                        dt = ParseFormatAt(input, end, wxS("%x %X"), wxS("%X %x"));
+                    }
 
-                        // try the format which corresponds to ctime() output
-                        // first, then the generic date/time formats
-                        const wxDateTime dt = ParseFormatAt
-                                              (
-                                                input,
-                                                date.end(),
-                                                wxS("%a %b %d %H:%M:%S %Y"),
-                                                wxS("%x %X"),
-                                                wxS("%X %x")
-                                              );
-                        if ( !dt.IsValid() )
-                            return false;
+                    if ( !dt.IsValid() )
+                        return false;
 
-                        Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
 
-                        hour = tm.hour;
-                        min = tm.min;
-                        sec = tm.sec;
+                    hour = tm.hour;
+                    min = tm.min;
+                    sec = tm.sec;
 
-                        year = tm.year;
-                        mon = tm.mon;
-                        mday = tm.mday;
-                    }
+                    year = tm.year;
+                    mon = tm.mon;
+                    mday = tm.mday;
 
                     haveDay = haveMon = haveYear =
                     haveHour = haveMin = haveSec = true;
@@ -1249,7 +1044,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('d'):       // day of a month (01-31)
-                if ( !GetNumericToken(width, input, &num) ||
+                if ( !GetNumericToken(width, input, end, &num) ||
                         (num > 31) || (num < 1) )
                 {
                     // no match
@@ -1263,7 +1058,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('H'):       // hour in 24h format (00-23)
-                if ( !GetNumericToken(width, input, &num) || (num > 23) )
+                if ( !GetNumericToken(width, input, end, &num) || (num > 23) )
                 {
                     // no match
                     return false;
@@ -1274,7 +1069,8 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('I'):       // hour in 12h format (01-12)
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 12) )
                 {
                     // no match
                     return false;
@@ -1286,7 +1082,8 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('j'):       // day of the year
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 366) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 366) )
                 {
                     // no match
                     return false;
@@ -1297,7 +1094,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('l'):       // milliseconds (0-999)
-                if ( !GetNumericToken(width, input, &num) )
+                if ( !GetNumericToken(width, input, end, &num) )
                     return false;
 
                 haveMsec = true;
@@ -1305,7 +1102,8 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('m'):       // month as a number (01-12)
-                if ( !GetNumericToken(width, input, &num) || !num || (num > 12) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        !num || (num > 12) )
                 {
                     // no match
                     return false;
@@ -1316,7 +1114,8 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('M'):       // minute as a decimal number (00-59)
-                if ( !GetNumericToken(width, input, &num) || (num > 59) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 59) )
                 {
                     // no match
                     return false;
@@ -1328,7 +1127,7 @@ wxDateTime::ParseFormat(const wxString& date,
 
             case _T('p'):       // AM or PM string
                 {
-                    wxString am, pm, token = GetAlphaToken(input);
+                    wxString am, pm, token = GetAlphaToken(input, end);
 
                     // some locales have empty AM/PM tokens and thus when formatting
                     // dates with the %p specifier nothing is generated; when trying to
@@ -1355,13 +1154,13 @@ wxDateTime::ParseFormat(const wxString& date,
             case _T('r'):       // time as %I:%M:%S %p
                 {
                     wxDateTime dt;
-                    if ( !dt.ParseFormat(wxString(input, date.end()),
+                    if ( !dt.ParseFormat(wxString(input, end),
                                          wxS("%I:%M:%S %p"), &input) )
                         return false;
 
                     haveHour = haveMin = haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
@@ -1371,21 +1170,22 @@ wxDateTime::ParseFormat(const wxString& date,
             case _T('R'):       // time as %H:%M
                 {
                     const wxDateTime
-                        dt = ParseFormatAt(input, date.end(), wxS("%H:%M"));
+                        dt = ParseFormatAt(input, end, wxS("%H:%M"));
                     if ( !dt.IsValid() )
                         return false;
 
                     haveHour =
                     haveMin = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                 }
                 break;
 
             case _T('S'):       // second as a decimal number (00-61)
-                if ( !GetNumericToken(width, input, &num) || (num > 61) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 61) )
                 {
                     // no match
                     return false;
@@ -1398,7 +1198,7 @@ wxDateTime::ParseFormat(const wxString& date,
             case _T('T'):       // time as %H:%M:%S
                 {
                     const wxDateTime
-                        dt = ParseFormatAt(input, date.end(), wxS("%H:%M:%S"));
+                        dt = ParseFormatAt(input, end, wxS("%H:%M:%S"));
                     if ( !dt.IsValid() )
                         return false;
 
@@ -1406,7 +1206,7 @@ wxDateTime::ParseFormat(const wxString& date,
                     haveMin =
                     haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
@@ -1414,7 +1214,8 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('w'):       // weekday as a number (0-6), Sunday = 0
-                if ( !GetNumericToken(width, input, &num) || (wday > 6) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (wday > 6) )
                 {
                     // no match
                     return false;
@@ -1425,57 +1226,41 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('x'):       // locale default date representation
-#ifdef HAVE_STRPTIME
-                // try using strptime() -- it may fail even if the input is
-                // correct but the date is out of range, so we will fall back
-                // to our generic code anyhow
-                {
-                    struct tm tm;
-
-                    if ( CallStrptime(date, input, "%x", &tm) )
-                    {
-                        haveDay = haveMon = haveYear = true;
-
-                        year = 1900 + tm.tm_year;
-                        mon = (Month)tm.tm_mon;
-                        mday = tm.tm_mday;
-
-                        break;
-                    }
-                }
-#endif // HAVE_STRPTIME
-
                 {
-                    wxString fmtDate,
-                             fmtDateAlt;
+                    wxString
+                        fmtDate = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT),
+                        fmtDateAlt = wxLocale::GetInfo(wxLOCALE_LONG_DATE_FMT);
 
-#ifdef __WINDOWS__
-                    // The above doesn't work for all locales, try to query
-                    // Windows for the right way of formatting the date:
-                    fmtDate = GetLocaleDateFormat();
                     if ( fmtDate.empty() )
-#endif // __WINDOWS__
                     {
                         if ( IsWestEuropeanCountry(GetCountry()) ||
                              GetCountry() == Russia )
                         {
-                            fmtDate = _T("%d/%m/%y");
-                            fmtDateAlt = _T("%m/%d/%y");
-                        }
+                            fmtDate = wxS("%d/%m/%Y");
+                            fmtDateAlt = wxS("%m/%d/%Y");
+                         }
                         else // assume USA
                         {
-                            fmtDate = _T("%m/%d/%y");
-                            fmtDateAlt = _T("%d/%m/%y");
+                            fmtDate = wxS("%m/%d/%Y");
+                            fmtDateAlt = wxS("%d/%m/%Y");
                         }
                     }
 
-                    const wxDateTime
-                        dt = ParseFormatAt(input, date.end(),
-                                           fmtDate, fmtDateAlt);
+                    wxDateTime
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
+
                     if ( !dt.IsValid() )
-                        return false;
+                    {
+                        // try with short years too
+                        fmtDate.Replace("%Y","%y");
+                        fmtDateAlt.Replace("%Y","%y");
+                        dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
 
-                    Tm tm = dt.GetTm();
+                        if ( !dt.IsValid() )
+                            return false;
+                    }
+
+                    const Tm tm = dt.GetTm();
 
                     haveDay =
                     haveMon =
@@ -1489,29 +1274,21 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('X'):       // locale default time representation
-#ifdef HAVE_STRPTIME
                 {
-                    // use strptime() to do it for us (FIXME !Unicode friendly)
-                    struct tm tm;
-                    if ( !CallStrptime(date, input, "%X", &tm) )
-                        return false;
+                    wxString fmtTime = wxLocale::GetInfo(wxLOCALE_TIME_FMT),
+                             fmtTimeAlt;
 
-                    haveHour = haveMin = haveSec = true;
+                    if ( fmtTime.empty() )
+                    {
+                        // try to parse what follows as "%H:%M:%S" and, if this
+                        // fails, as "%I:%M:%S %p" - this should catch the most
+                        // common cases
+                        fmtTime = "%T";
+                        fmtTimeAlt = "%r";
+                    }
 
-                    hour = tm.tm_hour;
-                    min = tm.tm_min;
-                    sec = tm.tm_sec;
-                }
-#else // !HAVE_STRPTIME
-                // TODO under Win32 we can query the LOCALE_ITIME system
-                //      setting which says whether the default time format is
-                //      24 or 12 hour
-                {
-                    // try to parse what follows as "%H:%M:%S" and, if this
-                    // fails, as "%I:%M:%S %p" - this should catch the most
-                    // common cases
                     const wxDateTime
-                        dt = ParseFormatAt(input, date.end(), "%T", "%r");
+                        dt = ParseFormatAt(input, end, fmtTime, fmtTimeAlt);
                     if ( !dt.IsValid() )
                         return false;
 
@@ -1519,16 +1296,16 @@ wxDateTime::ParseFormat(const wxString& date,
                     haveMin =
                     haveSec = true;
 
-                    Tm tm = dt.GetTm();
+                    const Tm tm = dt.GetTm();
                     hour = tm.hour;
                     min = tm.min;
                     sec = tm.sec;
                 }
-#endif // HAVE_STRPTIME/!HAVE_STRPTIME
                 break;
 
             case _T('y'):       // year without century (00-99)
-                if ( !GetNumericToken(width, input, &num) || (num > 99) )
+                if ( !GetNumericToken(width, input, end, &num) ||
+                        (num > 99) )
                 {
                     // no match
                     return false;
@@ -1542,7 +1319,7 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('Y'):       // year with century
-                if ( !GetNumericToken(width, input, &num) )
+                if ( !GetNumericToken(width, input, end, &num) )
                 {
                     // no match
                     return false;
@@ -1553,7 +1330,9 @@ wxDateTime::ParseFormat(const wxString& date,
                 break;
 
             case _T('Z'):       // timezone name
-                wxFAIL_MSG(_T("TODO"));
+                // FIXME: currently we just ignore everything that looks like a
+                //        time zone here
+                GetAlphaToken(input, end);
                 break;
 
             case _T('%'):       // a percent sign
@@ -1659,7 +1438,7 @@ wxDateTime::ParseFormat(const wxString& date,
     if ( haveWDay && GetWeekDay() != wday )
         return false;
 
-    *end = input;
+    *endParse = input;
 
     return true;
 }
@@ -1745,11 +1524,15 @@ wxDateTime::ParseDate(const wxString& date, wxString::const_iterator *end)
         { wxTRANSLATE("tomorrow"),          1 },
     };
 
+    const size_t lenRest = date.end() - p;
     for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ )
     {
         const wxString dateStr = wxGetTranslation(literalDates[n].str);
         size_t len = dateStr.length();
 
+        if ( len > lenRest )
+            continue;
+
         const wxString::const_iterator pEnd = p + len;
         if ( wxString(p, pEnd).CmpNoCase(dateStr) == 0 )
         {