Added wxLOCALE_DATE/TIME_FMT support to wxLocale::GetInfo().

- Implement for POSIX and Win32, TODO for OS X
- Use this instead of ad hoc code in wxDateTime::ParseFormat()
- Remove HAVE_STRPTIME, we don't need nor use strptime() any more


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@59914 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin 2009-03-29 17:15:43 +00:00
parent 04ce16a870
commit 89a7e1ff98
12 changed files with 616 additions and 964 deletions

235
configure vendored
View File

@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in Id: configure.in 59561 2009-03-15 16:07:56Z KO .
# From configure.in Id: configure.in 59905 2009-03-28 19:10:05Z VZ .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for wxWidgets 2.9.0.
#
@ -43806,239 +43806,6 @@ _ACEOF
fi
if test "$wxUSE_DATETIME" = "yes"; then
{ echo "$as_me:$LINENO: checking for strptime" >&5
echo $ECHO_N "checking for strptime... $ECHO_C" >&6; }
if test "${ac_cv_func_strptime+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
/* Define strptime to an innocuous variant, in case <limits.h> declares strptime.
For example, HP-UX 11i <limits.h> declares gettimeofday. */
#define strptime innocuous_strptime
/* System header to define __stub macros and hopefully few prototypes,
which can conflict with char strptime (); below.
Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
<limits.h> exists even on freestanding compilers. */
#ifdef __STDC__
# include <limits.h>
#else
# include <assert.h>
#endif
#undef strptime
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char strptime ();
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
#if defined __stub_strptime || defined __stub___strptime
choke me
#endif
int
main ()
{
return strptime ();
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext &&
$as_test_x conftest$ac_exeext; then
ac_cv_func_strptime=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_cv_func_strptime=no
fi
rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
conftest$ac_exeext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $ac_cv_func_strptime" >&5
echo "${ECHO_T}$ac_cv_func_strptime" >&6; }
if test "$ac_cv_func_strptime" = "yes"; then
{ echo "$as_me:$LINENO: checking for strptime declaration" >&5
echo $ECHO_N "checking for strptime declaration... $ECHO_C" >&6; }
if test "${wx_cv_func_strptime_decl+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
ac_ext=cpp
ac_cpp='$CXXCPP $CPPFLAGS'
ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <time.h>
int
main ()
{
struct tm t;
strptime("foo", "bar", &t);
;
return 0;
}
_ACEOF
rm -f conftest.$ac_objext
if { (ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_compile") 2>conftest.er1
ac_status=$?
grep -v '^ *+' conftest.er1 >conftest.err
rm -f conftest.er1
cat conftest.err >&5
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && {
test -z "$ac_cxx_werror_flag" ||
test ! -s conftest.err
} && test -s conftest.$ac_objext; then
wx_cv_func_strptime_decl=yes
else
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
wx_cv_func_strptime_decl=no
fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
{ echo "$as_me:$LINENO: result: $wx_cv_func_strptime_decl" >&5
echo "${ECHO_T}$wx_cv_func_strptime_decl" >&6; }
fi
if test "$wx_cv_func_strptime_decl" = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_STRPTIME_DECL 1
_ACEOF
else
wx_strptime_decl="extern char *strptime(const char *, const char *, struct tm *);"
fi
if test "$ac_cv_func_strptime" = "yes"; then
{ echo "$as_me:$LINENO: checking whether strptime() fails on invalid strings" >&5
echo $ECHO_N "checking whether strptime() fails on invalid strings... $ECHO_C" >&6; }
if test "${wx_cv_func_strptime_ok+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
wx_cv_func_strptime_ok=no
else
cat >conftest.$ac_ext <<_ACEOF
#include <stdlib.h>
#include <time.h>
#include "confdefs.h"
$wx_strptime_decl
int main()
{
struct tm t;
return !!strptime("", "%x", &t);
}
_ACEOF
rm -f conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_try") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
wx_cv_func_strptime_ok=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
wx_cv_func_strptime_ok=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi
{ echo "$as_me:$LINENO: result: $wx_cv_func_strptime_ok" >&5
echo "${ECHO_T}$wx_cv_func_strptime_ok" >&6; }
if test "$wx_cv_func_strptime_ok" = "yes"; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_STRPTIME 1
_ACEOF
fi
fi
{ echo "$as_me:$LINENO: checking for timezone variable in <time.h>" >&5
echo $ECHO_N "checking for timezone variable in <time.h>... $ECHO_C" >&6; }
if test "${wx_cv_var_timezone+set}" = set; then

View File

@ -5841,65 +5841,6 @@ if test "$ac_cv_func_gettimeofday" = "yes"; then
fi
if test "$wxUSE_DATETIME" = "yes"; then
dnl check for strptime and for its declaration as some systems lack it
AC_CHECK_FUNC(strptime)
if test "$ac_cv_func_strptime" = "yes"; then
AC_CACHE_CHECK([for strptime declaration], wx_cv_func_strptime_decl,
[
AC_LANG_PUSH(C++)
AC_TRY_COMPILE(
[
#include <time.h>
],
[
struct tm t;
strptime("foo", "bar", &t);
],
wx_cv_func_strptime_decl=yes,
wx_cv_func_strptime_decl=no
)
AC_LANG_POP()
]
)
fi
if test "$wx_cv_func_strptime_decl" = "yes"; then
AC_DEFINE(HAVE_STRPTIME_DECL)
else
wx_strptime_decl="extern char *strptime(const char *, const char *, struct tm *);"
fi
if test "$ac_cv_func_strptime" = "yes"; then
dnl strptime() behaviour doesn't conform to POSIX under Mac OS X <
dnl 10.5 and possibly other BSD variants, check that strptime() we
dnl have fails to parse format when the string doesn't match it instea
dnl of just stopping immediately and returning non-NULL
AC_CACHE_CHECK([whether strptime() fails on invalid strings],
wx_cv_func_strptime_ok,
[AC_RUN_IFELSE(
[
#include <stdlib.h>
#include <time.h>
#include "confdefs.h"
$wx_strptime_decl
int main()
{
struct tm t;
return !!strptime("", "%x", &t);
}
],
wx_cv_func_strptime_ok=yes,
wx_cv_func_strptime_ok=no,
dnl be pessimistic when cross-compiling
wx_cv_func_strptime_ok=no
)]
)
if test "$wx_cv_func_strptime_ok" = "yes"; then
AC_DEFINE(HAVE_STRPTIME)
fi
fi
dnl check for timezone variable
dnl doesn't exist under Darwin / Mac OS X which uses tm_gmtoff instead
AC_CACHE_CHECK(for timezone variable in <time.h>,

View File

@ -386,6 +386,7 @@ All:
- Added support of %l format specifier to wxDateTime::ParseFormat().
- wxImage handlers can now support multiple extensions (Ivan Krestinin).
- Added wxFileName::StripExtension() (troelsk).
- Added wxLOCALE_DATE/TIME_FMT support to wxLocale::GetInfo().
All (Unix):

View File

@ -139,30 +139,6 @@ extern WXDLLIMPEXP_DATA_BASE(const wxDateTime) wxDefaultDateTime;
// conditional compilation
// ----------------------------------------------------------------------------
#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \
((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
// glibc 2.0.7 strptime() is broken - the following snippet causes it to
// crash (instead of just failing):
//
// strncpy(buf, "Tue Dec 21 20:25:40 1999", 128);
// strptime(buf, "%x", &tm);
//
// so don't use it
#undef HAVE_STRPTIME
#endif // broken strptime()
#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS
// configure detects strptime as linkable because it's in the OS X
// System library but MSL headers don't declare it.
// char *strptime(const char *, const char *, struct tm *);
// However, we DON'T want to just provide it here because we would
// crash and/or overwrite data when strptime from OS X tries
// to fill in MW's struct tm which is two fields shorter (no TZ stuff)
// So for now let's just say we don't have strptime
#undef HAVE_STRPTIME
#endif
// everyone has strftime except Win CE unless VC8 is used
#if !defined(__WXWINCE__) || defined(__VISUALC8__)
#define HAVE_STRFTIME

View File

@ -364,6 +364,10 @@ enum wxLocaleCategory
// monetary value
wxLOCALE_CAT_MONEY,
// default category for wxLocaleInfo values which only apply to a single
// category (e.g. wxLOCALE_SHORT_DATE_FMT)
wxLOCALE_CAT_DEFAULT,
wxLOCALE_CAT_MAX
};
@ -373,11 +377,21 @@ enum wxLocaleCategory
enum wxLocaleInfo
{
// the thounsands separator
// the thousands separator (for wxLOCALE_CAT_NUMBER or MONEY)
wxLOCALE_THOUSANDS_SEP,
// the character used as decimal point
wxLOCALE_DECIMAL_POINT
// the character used as decimal point (for wxLOCALE_CAT_NUMBER or MONEY)
wxLOCALE_DECIMAL_POINT,
// the stftime()-formats used for short/long date and time representations
// (under some platforms short and long date formats are the same)
//
// NB: these elements should appear in this order, code in GetInfo() relies
// on it
wxLOCALE_SHORT_DATE_FMT,
wxLOCALE_LONG_DATE_FMT,
wxLOCALE_DATE_TIME_FMT,
wxLOCALE_TIME_FMT
};
@ -449,7 +463,8 @@ public:
// get the values of the given locale-dependent datum: the current locale
// is used, the US default value is returned if everything else fails
static wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat);
static wxString GetInfo(wxLocaleInfo index,
wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT);
// return true if the locale was set successfully
bool IsOk() const { return m_pszOldLocale != NULL; }

View File

@ -280,7 +280,7 @@ enum wxLayoutDirection
*/
struct WXDLLIMPEXP_BASE wxLanguageInfo
{
/// ::wxLanguage id.
/// ::wxLanguage id.
/// It should be greater than @c wxLANGUAGE_USER_DEFINED when defining your own
/// language info structure.
int Language;
@ -314,20 +314,33 @@ struct WXDLLIMPEXP_BASE wxLanguageInfo
/**
The category of locale settings. See wxLocale::GetInfo().
The category of locale settings.
@see wxLocale::GetInfo()
*/
enum wxLocaleCategory
{
/// (any) numbers
/// Number formatting.
wxLOCALE_CAT_NUMBER,
/// date/time
/// Date/time formatting.
wxLOCALE_CAT_DATE,
/// monetary value
/// Monetary values formatting.
wxLOCALE_CAT_MONEY,
wxLOCALE_CAT_MAX
/**
Default category for the wxLocaleInfo value.
This category can be used for values which only make sense for a single
category, e.g. wxLOCALE_SHORT_DATE_FMT which can only be used with
wxLOCALE_CAT_DATE. As this is the default value of the second parameter
of wxLocale::GetInfo(), wxLOCALE_CAT_DATE can be omitted when asking
for wxLOCALE_SHORT_DATE_FMT value.
@since 2.9.0
*/
wxLOCALE_CAT_DEFAULT
};
/**
@ -335,11 +348,70 @@ enum wxLocaleCategory
*/
enum wxLocaleInfo
{
/// The thounsands separator
/**
The thousands separator.
This value can be used with either wxLOCALE_CAT_NUMBER or
wxLOCALE_CAT_MONEY categories.
*/
wxLOCALE_THOUSANDS_SEP,
/// The character used as decimal point
wxLOCALE_DECIMAL_POINT
/**
The character used as decimal point.
This value can be used with either wxLOCALE_CAT_NUMBER or
wxLOCALE_CAT_MONEY categories.
*/
wxLOCALE_DECIMAL_POINT,
/**
The date and time formats.
The strings returned by wxLocale::GetInfo() use strftime() or,
equivalently, wxDateTime::Format() format. If the relevant format
couldn't be determined, an empty string is returned -- there is no
fallback value so that the application could determine the best course
of actions itself in such case.
All of these values are used with wxLOCALE_CAT_DATE in
wxLocale::GetInfo() or, more typically, with wxLOCALE_CAT_DEFAULT as
they only apply to a single category.
*/
//@{
/**
Short date format.
Notice that short and long date formats may be the same under POSIX
systems currently but may, and typically are, different under MSW or OS
X.
@since 2.9.0
*/
wxLOCALE_SHORT_DATE_FMT,
/**
Long date format.
@since 2.9.0
*/
wxLOCALE_LONG_DATE_FMT,
/**
Date and time format.
@since 2.9.0
*/
wxLOCALE_DATE_TIME_FMT,
/**
Time format.
@since 2.9.0
*/
wxLOCALE_TIME_FMT
//@}
};
@ -649,7 +721,7 @@ public:
/**
Tries to detect the user's default language setting.
Returns the ::wxLanguage value or @c wxLANGUAGE_UNKNOWN if the language-guessing
algorithm failed.
*/
@ -658,10 +730,19 @@ public:
/**
Get the values of the given locale-dependent datum.
The current locale is used, the US default value is returned if everything
else fails.
This function returns the value of the locale-specific option specified
by the given @a index.
@param index
One of the elements of wxLocaleInfo enum.
@param cat
The category to use with the given index or wxLOCALE_CAT_DEFAULT if
the index can only apply to a single category.
@return
The option value or empty string if the function failed.
*/
static wxString GetInfo(wxLocaleInfo index, wxLocaleCategory cat);
static wxString GetInfo(wxLocaleInfo index,
wxLocaleCategory cat = wxLOCALE_CAT_DEFAULT);
/**
Initializes the wxLocale instance.

View File

@ -881,12 +881,6 @@
/* define if you have statvfs function */
#undef HAVE_STATVFS
/* Define if you have strptime() */
#undef HAVE_STRPTIME
/* Define if strptime() is declared in headers */
#undef HAVE_STRPTIME_DECL
/* Define if you have strtoull() and strtoll() */
#undef HAVE_STRTOULL

View File

@ -955,12 +955,6 @@ typedef pid_t GPid;
/* define if you have statvfs function */
#undef HAVE_STATVFS
/* Define if you have strptime() */
#define HAVE_STRPTIME 1
/* Define if you have strptime() declaration */
#define HAVE_STRPTIME_DECL 1
/* Define if you have strtoull() and strtoll() */
#define HAVE_STRTOULL 1

View 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,
@ -281,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();
}
@ -901,383 +863,6 @@ 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__
#ifdef __WXOSX__
#include "wx/osx/private.h"
// under OSX locale formats are defined using
// http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
//
// so we need a translation function, bluntly copied from the windows
// version above and enhanced with the additional elements needed
static wxString TranslateFromUnicodeFormat(const wxString& fmt)
{
wxString fmtWX;
wxChar chLast = _T('\0');
size_t lastCount = 0;
for ( wxString::const_iterator p = fmt.begin(); /* end handled inside */; ++p )
{
if ( p == fmt.end() || *p == chLast )
{
lastCount++;
if ( p == fmt.end() )
break;
continue;
}
switch ( (*p).GetValue() )
{
// these characters come in groups, start counting them
case _T('d'):
case _T('M'):
case _T('y'):
case _T('g'):
case _T('h'):
case _T('H'):
case _T('m'):
case _T('s'):
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('H'):
switch ( lastCount )
{
case 1: // H
case 2: // HH
fmtWX += _T("%H");
break;
default:
wxFAIL_MSG( _T("wrong number of 'H's") );
}
break;
case _T('h'):
switch ( lastCount )
{
case 1: // h
case 2: // hh
fmtWX += _T("%h");
break;
default:
wxFAIL_MSG( _T("wrong number of 'h's") );
}
break;
case _T('m'):
switch ( lastCount )
{
case 1: // m
case 2: // mm
fmtWX += _T("%M");
break;
default:
wxFAIL_MSG( _T("wrong number of 'm's") );
}
break;
case _T('s'):
switch ( lastCount )
{
case 1: // s
case 2: // ss
fmtWX += _T("%S");
break;
default:
wxFAIL_MSG( _T("wrong number of 's'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('%') )
{
// this one needs to be escaped
fmtWX += _T('%');
}
fmtWX += *p;
}
}
return fmtWX;
}
static wxString GetLocaleDateFormat()
{
wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
(NULL, currentLocale, kCFDateFormatterShortStyle, kCFDateFormatterNoStyle));
wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
return TranslateFromUnicodeFormat(cfs.AsString());
}
static wxString GetLocaleFullDateFormat()
{
wxCFRef<CFLocaleRef> currentLocale( CFLocaleCopyCurrent() );
wxCFRef<CFDateFormatterRef> dateFormatter( CFDateFormatterCreate
(NULL, currentLocale, kCFDateFormatterLongStyle, kCFDateFormatterMediumStyle));
wxCFStringRef cfs = wxCFRetain( CFDateFormatterGetFormat(dateFormatter ));
return TranslateFromUnicodeFormat(cfs.AsString());
}
#endif // __WXOSX__
bool
wxDateTime::ParseFormat(const wxString& date,
const wxString& format,
@ -1420,72 +1005,39 @@ 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) )
const wxString
fmtDateTime = wxLocale::GetInfo(wxLOCALE_DATE_TIME_FMT);
if ( !fmtDateTime.empty() )
dt = ParseFormatAt(input, end, fmtDateTime);
if ( !dt.IsValid() )
{
hour = tm.tm_hour;
min = tm.tm_min;
sec = tm.tm_sec;
year = 1900 + tm.tm_year;
mon = (Month)tm.tm_mon;
mday = tm.tm_mday;
// 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() )
{
Tm tm;
#ifdef __WXOSX__
bool hasValidDate = false;
wxString fmtDate = GetLocaleFullDateFormat();
if ( !fmtDate.empty() )
{
const wxDateTime dt = ParseFormatAt
(
input,
end,
fmtDate
);
if ( dt.IsValid() )
{
tm = dt.GetTm();
hasValidDate = true;
}
}
if ( !hasValidDate )
#endif // __WXOSX__
{
// try the format which corresponds to ctime() output
// first, then the generic date/time formats
const wxDateTime dt = ParseFormatAt
(
input,
end,
wxS("%a %b %d %H:%M:%S %Y"),
wxS("%x %X"),
wxS("%X %x")
);
if ( !dt.IsValid() )
return false;
tm = dt.GetTm();
}
hour = tm.hour;
min = tm.min;
sec = tm.sec;
year = tm.year;
mon = tm.mon;
mday = tm.mday;
// and finally also the two generic date/time formats
dt = ParseFormatAt(input, end, wxS("%x %X"), wxS("%X %x"));
}
if ( !dt.IsValid() )
return false;
const Tm tm = dt.GetTm();
hour = tm.hour;
min = tm.min;
sec = tm.sec;
year = tm.year;
mon = tm.mon;
mday = tm.mday;
haveDay = haveMon = haveYear =
haveHour = haveMin = haveSec = true;
}
@ -1608,7 +1160,7 @@ wxDateTime::ParseFormat(const wxString& date,
haveHour = haveMin = haveSec = true;
Tm tm = dt.GetTm();
const Tm tm = dt.GetTm();
hour = tm.hour;
min = tm.min;
sec = tm.sec;
@ -1625,7 +1177,7 @@ wxDateTime::ParseFormat(const wxString& date,
haveHour =
haveMin = true;
Tm tm = dt.GetTm();
const Tm tm = dt.GetTm();
hour = tm.hour;
min = tm.min;
}
@ -1654,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;
@ -1674,77 +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;
wxString
fmtDate = wxLocale::GetInfo(wxLOCALE_SHORT_DATE_FMT),
fmtDateAlt = wxLocale::GetInfo(wxLOCALE_LONG_DATE_FMT);
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;
#if defined( __WINDOWS__ ) || defined( __WXOSX__ )
// The above doesn't work for all locales, try to query
// the OS 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, end,
fmtDate, fmtDateAlt);
Tm tm;
wxDateTime
dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
if ( !dt.IsValid() )
{
wxString fmtDateLong = fmtDate;
wxString fmtDateLongAlt = fmtDateAlt;
// try with short years too
fmtDate.Replace("%Y","%y");
fmtDateAlt.Replace("%Y","%y");
dt = ParseFormatAt(input, end, fmtDate, fmtDateAlt);
if ( !fmtDateLong.empty() )
{
fmtDateLong.Replace("%y","%Y");
fmtDateLongAlt.Replace("%y","%Y");
const wxDateTime dtLong = ParseFormatAt(input, end,
fmtDateLong, fmtDateLongAlt);
if ( !dtLong.IsValid() )
return false;
tm = dtLong.GetTm();
}
else
if ( !dt.IsValid() )
return false;
}
else
tm = dt.GetTm();
const Tm tm = dt.GetTm();
haveDay =
haveMon =
@ -1758,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, end, "%T", "%r");
dt = ParseFormatAt(input, end, fmtTime, fmtTimeAlt);
if ( !dt.IsValid() )
return false;
@ -1788,12 +1296,11 @@ 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)
@ -1823,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

View File

@ -72,7 +72,7 @@
#include "wx/hashset.h"
#include "wx/filesys.h"
#if defined(__DARWIN__)
#if defined(__WXOSX__)
#include "wx/osx/core/cfref.h"
#include <CoreFoundation/CFLocale.h>
#include "wx/osx/core/cfstring.h"
@ -841,7 +841,7 @@ wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s)
//
// This is a "low-level" class and is used only by wxMsgCatalog
// NOTE: for the documentation of the binary catalog (.MO) files refer to
// the GNU gettext manual:
// the GNU gettext manual:
// http://www.gnu.org/software/autoconf/manual/gettext/MO-Files.html
// ----------------------------------------------------------------------------
@ -1464,9 +1464,9 @@ bool wxMsgCatalogFile::FillHash(wxMessagesHash& hash,
}
// skip this string
// IMPORTANT: accesses to the 'data' pointer are valid only for
// IMPORTANT: accesses to the 'data' pointer are valid only for
// the first 'length+1' bytes (GNU specs says that the
// final NUL is not counted in length); using wxStrnlen()
// final NUL is not counted in length); using wxStrnlen()
// we make sure we don't access memory beyond the valid range
// (which otherwise may happen for invalid MO files):
offset += wxStrnlen(str, length - offset) + 1;
@ -2593,56 +2593,283 @@ bool wxLocale::AddCatalog(const wxString& szDomain,
// accessors for locale-dependent data
// ----------------------------------------------------------------------------
#if defined(__WXMSW__) || defined(__WXOSX__)
namespace
{
// This function translates from Unicode date formats described at
//
// http://unicode.org/reports/tr35/tr35-6.html#Date_Format_Patterns
//
// to strftime()-like syntax. This translation is not lossless but we try to do
// our best.
static wxString TranslateFromUnicodeFormat(const wxString& fmt)
{
wxString fmtWX;
fmtWX.reserve(fmt.length());
char chLast = '\0';
size_t lastCount = 0;
for ( wxString::const_iterator p = fmt.begin(); /* end handled inside */; ++p )
{
if ( p != fmt.end() )
{
if ( *p == chLast )
{
lastCount++;
continue;
}
const wxUniChar ch = (*p).GetValue();
if ( ch.IsAscii() && strchr("dghHmMsSy", ch) )
{
// these characters come in groups, start counting them
chLast = ch;
lastCount = 1;
continue;
}
}
// interpret any special characters we collected so far
if ( lastCount )
{
switch ( chLast )
{
case '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 += "%d";
break;
case 3: // ddd
fmtWX += "%a";
break;
case 4: // dddd
fmtWX += "%A";
break;
default:
wxFAIL_MSG( "too many 'd's" );
}
break;
case 'M':
switch ( lastCount )
{
case 1: // M
case 2: // MM
// as for 'd' and 'dd' above
fmtWX += "%m";
break;
case 3:
fmtWX += "%b";
break;
case 4:
fmtWX += "%B";
break;
default:
wxFAIL_MSG( "too many 'M's" );
}
break;
case 'y':
switch ( lastCount )
{
case 1: // y
case 2: // yy
fmtWX += "%y";
break;
case 4: // yyyy
fmtWX += "%Y";
break;
default:
wxFAIL_MSG( "wrong number of 'y's" );
}
break;
case 'H':
switch ( lastCount )
{
case 1: // H
case 2: // HH
fmtWX += "%H";
break;
default:
wxFAIL_MSG( "wrong number of 'H's" );
}
break;
case 'h':
switch ( lastCount )
{
case 1: // h
case 2: // hh
fmtWX += "%h";
break;
default:
wxFAIL_MSG( "wrong number of 'h's" );
}
break;
case 'm':
switch ( lastCount )
{
case 1: // m
case 2: // mm
fmtWX += "%M";
break;
default:
wxFAIL_MSG( "wrong number of 'm's" );
}
break;
case 's':
switch ( lastCount )
{
case 1: // s
case 2: // ss
fmtWX += "%S";
break;
default:
wxFAIL_MSG( "wrong number of 's's" );
}
break;
case 'g':
// strftime() doesn't have era string,
// ignore this format
wxASSERT_MSG( lastCount <= 2, "too many 'g's" );
break;
default:
wxFAIL_MSG( "unreachable" );
}
chLast = '\0';
lastCount = 0;
}
if ( p == fmt.end() )
break;
// not a special character so must be just a separator, treat as is
if ( *p == _T('%') )
{
// this one needs to be escaped
fmtWX += _T('%');
}
fmtWX += *p;
}
return fmtWX;
}
} // anonymous namespace
#endif // __WXMSW__ || __WXOSX__
#if defined(__WXMSW__)
namespace
{
LCTYPE GetLCTYPEFormatFromLocalInfo(wxLocaleInfo index)
{
switch ( index )
{
case wxLOCALE_SHORT_DATE_FMT:
return LOCALE_SSHORTDATE;
case wxLOCALE_LONG_DATE_FMT:
return LOCALE_SLONGDATE;
case wxLOCALE_TIME_FMT:
return LOCALE_STIMEFORMAT;
default:
wxFAIL_MSG( "no matching LCTYPE" );
}
return 0;
}
} // anonymous namespace
/* static */
wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
{
wxUint32 lcid = LOCALE_USER_DEFAULT;
if (wxGetLocale())
if ( wxGetLocale() )
{
const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage());
const wxLanguageInfo * const
info = GetLanguageInfo(wxGetLocale()->GetLanguage());
if ( info )
lcid = info->GetLCID();
}
wxString str;
wxChar buffer[256];
size_t count;
buffer[0] = wxS('\0');
switch (index)
wxChar buf[256];
buf[0] = wxT('\0');
switch ( index )
{
case wxLOCALE_DECIMAL_POINT:
count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256);
if (!count)
str << wxS(".");
else
str << buffer;
if ( ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buf, WXSIZEOF(buf)) )
str = buf;
break;
#if 0
case wxSYS_LIST_SEPARATOR:
count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256);
if (!count)
str << wxS(",");
else
str << buffer;
case wxLOCALE_SHORT_DATE_FMT:
case wxLOCALE_LONG_DATE_FMT:
case wxLOCALE_TIME_FMT:
if ( ::GetLocaleInfo(lcid, GetLCTYPEFormatFromLocalInfo(index),
buf, WXSIZEOF(buf)) )
{
return TranslateFromUnicodeFormat(buf);
}
break;
case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero
count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256);
if (!count)
str << wxS("0");
else
str << buffer;
case wxLOCALE_DATE_TIME_FMT:
// there doesn't seem to be any specific setting for this, so just
// combine date and time ones
{
const wxString datefmt = GetInfo(wxLOCALE_LONG_DATE_FMT);
if ( datefmt.empty() )
break;
const wxString timefmt = GetInfo(wxLOCALE_TIME_FMT);
if ( timefmt.empty() )
break;
str << datefmt << ' ' << timefmt;
}
break;
#endif
default:
wxFAIL_MSG(wxS("Unknown System String !"));
wxFAIL_MSG( "unknown wxLocaleInfo" );
}
return str;
}
#elif defined(__DARWIN__)
#elif defined(__WXOSX__)
/* static */
wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
@ -2674,17 +2901,104 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat))
cfstr = (CFStringRef) CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator);
break;
case wxLOCALE_SHORT_DATE_FMT:
case wxLOCALE_LONG_DATE_FMT:
case wxLOCALE_DATE_TIME_FMT:
case wxLOCALE_TIME_FMT:
// TODO
return wxString();
default:
wxFAIL_MSG( "Unknown locale info" );
cfstr = CFSTR("");
break;
return wxString();
}
wxCFStringRef str(wxCFRetain(cfstr));
return str.AsString();
}
#else // !__WXMSW__ && !__DARWIN__
#else // !__WXMSW__ && !__WXOSX__, assume generic POSIX
namespace
{
wxString GetDateFormatFromLangInfo(wxLocaleInfo index)
{
#ifdef HAVE_LANGINFO_H
// array containing parameters for nl_langinfo() indexes by offset of index
// from wxLOCALE_SHORT_DATE_FMT
static const nl_item items[] =
{
D_FMT, D_T_FMT, D_T_FMT, T_FMT,
};
const int nlidx = index - wxLOCALE_SHORT_DATE_FMT;
if ( nlidx < 0 || nlidx >= (int)WXSIZEOF(items) )
{
wxFAIL_MSG( "logic error in GetInfo() code" );
return wxString();
}
const wxString fmt(nl_langinfo(items[nlidx]));
// just return the format returned by nl_langinfo() except for long date
// format which we need to recover from date/time format ourselves (but not
// if we failed completely)
if ( fmt.empty() || index != wxLOCALE_LONG_DATE_FMT )
return fmt;
// this is not 100% precise but the idea is that a typical date/time format
// under POSIX systems is a combination of a long date format with time one
// so we should be able to get just the long date format by removing all
// time-specific format specifiers
static const char *timeFmtSpecs = "HIklMpPrRsSTXzZ";
static const char *timeSep = " :./-";
wxString fmtDateOnly;
const wxString::const_iterator end = fmt.end();
wxString::const_iterator lastSep = end;
for ( wxString::const_iterator p = fmt.begin(); p != end; ++p )
{
if ( strchr(timeSep, *p) )
{
if ( lastSep == end )
lastSep = p;
// skip it for now, we'll discard it if it's followed by a time
// specifier later or add it to fmtDateOnly if it is not
continue;
}
if ( *p == '%' &&
(p + 1 != end) && strchr(timeFmtSpecs, p[1]) )
{
// time specified found: skip it and any preceding separators
++p;
lastSep = end;
continue;
}
if ( lastSep != end )
{
fmtDateOnly += wxString(lastSep, p);
lastSep = end;
}
fmtDateOnly += *p;
}
return fmtDateOnly;
#else // !HAVE_LANGINFO_H
// no fallback, let the application deal with unavailability of
// nl_langinfo() itself as there is no good way for us to do it (well, we
// could try to reverse engineer the format from strftime() output but this
// looks like too much trouble considering the relatively small number of
// systems without nl_langinfo() still in use)
return wxString();
#endif // HAVE_LANGINFO_H/!HAVE_LANGINFO_H
}
} // anonymous namespace
/* static */
wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat)
@ -2693,37 +3007,44 @@ wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat)
if ( !lc )
return wxString();
switch ( cat )
switch ( index )
{
case wxLOCALE_CAT_NUMBER:
switch ( index )
{
case wxLOCALE_THOUSANDS_SEP:
return lc->thousands_sep;
case wxLOCALE_THOUSANDS_SEP:
if ( cat == wxLOCALE_CAT_NUMBER )
return lc->thousands_sep;
else if ( cat == wxLOCALE_CAT_MONEY )
return lc->mon_thousands_sep;
case wxLOCALE_DECIMAL_POINT:
return lc->decimal_point;
}
wxFAIL_MSG( "invalid wxLocaleCategory" );
break;
case wxLOCALE_CAT_MONEY:
switch ( index )
{
case wxLOCALE_THOUSANDS_SEP:
return lc->mon_thousands_sep;
case wxLOCALE_DECIMAL_POINT:
return lc->mon_decimal_point;
}
case wxLOCALE_DECIMAL_POINT:
if ( cat == wxLOCALE_CAT_NUMBER )
return lc->decimal_point;
else if ( cat == wxLOCALE_CAT_MONEY )
return lc->mon_decimal_point;
wxFAIL_MSG( "invalid wxLocaleCategory" );
break;
case wxLOCALE_SHORT_DATE_FMT:
case wxLOCALE_LONG_DATE_FMT:
case wxLOCALE_DATE_TIME_FMT:
case wxLOCALE_TIME_FMT:
if ( cat != wxLOCALE_CAT_DATE && cat != wxLOCALE_CAT_DEFAULT )
{
wxFAIL_MSG( "invalid wxLocaleCategory" );
break;
}
return GetDateFormatFromLangInfo(index);
default:
wxFAIL_MSG( "unknown wxLocaleCategory" );
return wxString(); // skip second assert below
wxFAIL_MSG( "unknown wxLocaleInfo value" );
}
wxFAIL_MSG( "unknown wxLocaleInfo value for this category" );
return wxString();
}

View File

@ -691,7 +691,10 @@ void DateTimeTestCase::TestTimeFormat()
{ 6, wxDateTime::Feb, 1856, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay },
{ 6, wxDateTime::Feb, 1857, 23, 30, 00, 0.0, wxDateTime::Inv_WeekDay },
{ 29, wxDateTime::May, 2076, 18, 30, 00, 0.0, wxDateTime::Inv_WeekDay },
{ 29, wxDateTime::Feb, 2400, 02, 15, 25, 0.0, wxDateTime::Inv_WeekDay },
// FIXME: the test with 02:15:25 time doesn't pass because of DST
// computation problems, we get back 03:15:25
{ 29, wxDateTime::Feb, 2400, 04, 15, 25, 0.0, wxDateTime::Inv_WeekDay },
#if 0
// Need to add support for BCE dates.
{ 01, wxDateTime::Jan, -52, 03, 16, 47, 0.0, wxDateTime::Inv_WeekDay },
@ -777,6 +780,12 @@ void DateTimeTestCase::TestTimeFormat()
wxDateTime dt;
#if 0
// special case which was known to fail
CPPUNIT_ASSERT( dt.ParseFormat("02/06/1856", "%x") );
CPPUNIT_ASSERT_EQUAL( 1856, dt.GetYear() );
#endif
// test partially specified dates too
wxDateTime dtDef(26, wxDateTime::Sep, 2008);
CPPUNIT_ASSERT( dt.ParseFormat("17", "%d") );

View File

@ -41,10 +41,12 @@ private:
CPPUNIT_TEST_SUITE( IntlTestCase );
CPPUNIT_TEST( Domain );
CPPUNIT_TEST( Headers );
CPPUNIT_TEST( DateTimeFmt );
CPPUNIT_TEST_SUITE_END();
void Domain();
void Headers();
void DateTimeFmt();
wxLocale *m_locale;
@ -59,14 +61,17 @@ CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( IntlTestCase, "IntlTestCase" );
void IntlTestCase::setUp()
{
if (!wxLocale::IsAvailable(wxLANGUAGE_FRENCH))
return; // you should have french support installed to run this test!
// Check that French locale is supported, this test doesn't work without it
// and all the other function need to check whether m_locale is non-NULL
// before continuing
if ( !wxLocale::IsAvailable(wxLANGUAGE_FRENCH) )
return;
wxLocale::AddCatalogLookupPathPrefix("./intl");
m_locale = new wxLocale;
CPPUNIT_ASSERT( m_locale);
CPPUNIT_ASSERT( m_locale );
// don't load default catalog, it may be unavailable:
bool loaded = m_locale->Init(wxLANGUAGE_FRENCH, wxLOCALE_CONV_ENCODING);
CPPUNIT_ASSERT( loaded );
@ -86,7 +91,7 @@ void IntlTestCase::tearDown()
void IntlTestCase::Domain()
{
if (!m_locale)
return; // no french support installed on this system!
return;
// _() searches all domains by default:
CPPUNIT_ASSERT_EQUAL( "&Ouvrir un fichier", _("&Open bogus file") );
@ -100,8 +105,8 @@ void IntlTestCase::Domain()
void IntlTestCase::Headers()
{
if (!m_locale)
return; // no french support installed on this system!
if ( !m_locale )
return;
CPPUNIT_ASSERT_EQUAL( "wxWindows 2.0 i18n sample", m_locale->GetHeaderValue("Project-Id-Version") );
CPPUNIT_ASSERT_EQUAL( "1999-01-13 18:19+0100", m_locale->GetHeaderValue("POT-Creation-Date") );
@ -118,4 +123,43 @@ void IntlTestCase::Headers()
CPPUNIT_ASSERT_EQUAL( "", m_locale->GetHeaderValue("X-Not-Here") );
}
static void CompareFormats(const wxString& expected, wxString actual)
{
if ( actual.empty() )
{
// this means that GetInfo() failed which can happen, just ignore
return;
}
#ifdef __GLIBC__
// glibc uses some extensions in its formats which we need to convert to
// standard form
actual.Replace("%T", "%H:%M:%S");
actual.Replace("%e", "%d");
#endif // __GLIBC__
CPPUNIT_ASSERT_EQUAL( expected, actual );
}
void IntlTestCase::DateTimeFmt()
{
if ( !m_locale )
return;
CompareFormats( "%d.%m.%Y", m_locale->GetInfo(wxLOCALE_SHORT_DATE_FMT) );
CompareFormats( "%a %d %b %Y", m_locale->GetInfo(wxLOCALE_LONG_DATE_FMT) );
CompareFormats( "%a %d %b %Y %H:%M:%S %Z",
m_locale->GetInfo(wxLOCALE_DATE_TIME_FMT) );
CompareFormats( "%H:%M:%S", m_locale->GetInfo(wxLOCALE_TIME_FMT) );
// also test for "C" locale
setlocale(LC_ALL, "C");
CompareFormats( "%m/%d/%y", m_locale->GetInfo(wxLOCALE_SHORT_DATE_FMT) );
CompareFormats( "%a %b %d %Y", m_locale->GetInfo(wxLOCALE_LONG_DATE_FMT) );
CompareFormats( "%a %b %d %H:%M:%S %Y",
m_locale->GetInfo(wxLOCALE_DATE_TIME_FMT) );
CompareFormats( "%H:%M:%S", m_locale->GetInfo(wxLOCALE_TIME_FMT) );
}
#endif // wxUSE_INTL