From fe57329f991a0b347d40a5c97d9a62285eb708fe Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Fri, 22 Jan 2010 13:03:42 +0000 Subject: [PATCH] * libc/locale/lmonetary.c (__monetary_load_locale): Take additional parameters for wide char to multibyte conversion. Call __set_lc_monetary_from_win on Cygwin. * libc/locale/lmonetary.h: Make C++-safe. (__monetary_load_locale): Change declaration. * libc/locale/lnumeric.c (__numeric_load_locale): Take additional parameters for wide char to multibyte conversion. Call __set_lc_numeric_from_win on Cygwin. * libc/locale/lnumeric.h: Make C++-safe. (__numeric_load_locale): Change declaration. * libc/locale/locale.c (lconv): De-constify for Cygwin. (__set_charset_from_locale): Rename from __set_charset_from_codepage. Take locale as parameter instead of a codepage. (loadlocale): Allow "EUC-JP" for "EUCJP" and "EUC-KR" for "EUCKR". Change documnetation accordingly. Enable LC_COLLATE, LC_MONETARY, LC_NUMERIC, and LC_TIME handling on Cygwin. (_localeconv_r): On Cygwin, copy values from monetary and numeric domain if change has been noted. * libc/locale/nl_langinfo.c (nl_langinfo): Accommodate change of am/pm layout in struct lc_time_T. * libc/locale/timelocal.c (_C_time_locale): Accommodate redefinition of am/pm members. (__time_load_locale): Take additional parameters for wide char to multibyte conversion. Call __set_lc_time_from_win on Cygwin. * libc/locale/timelocal.h: Make C++-safe. (struct lc_time_T): Convert am and pm to a am_pm array for easier consumption by strftime and strptime. (__time_load_locale): Change declaration. * libc/time/strftime.c: Change documentation to reflect changes to strftime. Remove locale constant strings in favor of access to locale-specifc data. (_ctloc): Define access method for locale-specifc data. (TOLOWER): Define for tolower conversion. (strftime): Throughout, convert locale-specific formats to use locale-specific data. Add GNU-specific "%P" format. * libc/time/strptime.c: Remove locale constant strings in favor of access to locale-specifc data. (_ctloc): Define access method for locale-specifc data. (strptime): Throughout, convert locale-specific formats to use locale-specific data. --- newlib/ChangeLog | 44 ++++++++ newlib/libc/locale/lmonetary.c | 24 ++++- newlib/libc/locale/lmonetary.h | 8 +- newlib/libc/locale/lnumeric.c | 23 ++++- newlib/libc/locale/lnumeric.h | 8 +- newlib/libc/locale/locale.c | 73 ++++++++++++-- newlib/libc/locale/nl_langinfo.c | 4 +- newlib/libc/locale/timelocal.c | 26 +++-- newlib/libc/locale/timelocal.h | 11 +- newlib/libc/time/strftime.c | 168 ++++++++++++++++--------------- newlib/libc/time/strptime.c | 85 ++++------------ 11 files changed, 302 insertions(+), 172 deletions(-) diff --git a/newlib/ChangeLog b/newlib/ChangeLog index b8c04ce2b..396d0c3ee 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,47 @@ +2010-01-22 Corinna Vinschen + + * libc/locale/lmonetary.c (__monetary_load_locale): Take additional + parameters for wide char to multibyte conversion. Call + __set_lc_monetary_from_win on Cygwin. + * libc/locale/lmonetary.h: Make C++-safe. + (__monetary_load_locale): Change declaration. + * libc/locale/lnumeric.c (__numeric_load_locale): Take additional + parameters for wide char to multibyte conversion. Call + __set_lc_numeric_from_win on Cygwin. + * libc/locale/lnumeric.h: Make C++-safe. + (__numeric_load_locale): Change declaration. + * libc/locale/locale.c (lconv): De-constify for Cygwin. + (__set_charset_from_locale): Rename from + __set_charset_from_codepage. Take locale as parameter instead of + a codepage. + (loadlocale): Allow "EUC-JP" for "EUCJP" and "EUC-KR" for "EUCKR". + Change documnetation accordingly. Enable LC_COLLATE, LC_MONETARY, + LC_NUMERIC, and LC_TIME handling on Cygwin. + (_localeconv_r): On Cygwin, copy values from monetary and numeric + domain if change has been noted. + * libc/locale/nl_langinfo.c (nl_langinfo): Accommodate change of + am/pm layout in struct lc_time_T. + * libc/locale/timelocal.c (_C_time_locale): Accommodate + redefinition of am/pm members. + (__time_load_locale): Take additional parameters for wide char + to multibyte conversion. Call __set_lc_time_from_win on Cygwin. + * libc/locale/timelocal.h: Make C++-safe. + (struct lc_time_T): Convert am and pm to a am_pm array for easier + consumption by strftime and strptime. + (__time_load_locale): Change declaration. + * libc/time/strftime.c: Change documentation to reflect changes to + strftime. Remove locale constant strings in favor of access to + locale-specifc data. + (_ctloc): Define access method for locale-specifc data. + (TOLOWER): Define for tolower conversion. + (strftime): Throughout, convert locale-specific formats to use + locale-specific data. Add GNU-specific "%P" format. + * libc/time/strptime.c: Remove locale constant strings in favor of + access to locale-specifc data. + (_ctloc): Define access method for locale-specifc data. + (strptime): Throughout, convert locale-specific formats to use + locale-specific data. + 2010-01-20 Corinna Vinschen * libc/locale/nl_langinfo.c (nl_langinfo): On Cygwin, translate diff --git a/newlib/libc/locale/lmonetary.c b/newlib/libc/locale/lmonetary.c index d31e88ccd..745ade517 100644 --- a/newlib/libc/locale/lmonetary.c +++ b/newlib/libc/locale/lmonetary.c @@ -70,9 +70,28 @@ cnv(const char *str) { } int -__monetary_load_locale(const char *name) { - +__monetary_load_locale(const char *name , void *f_wctomb, const char *charset) +{ int ret; + +#ifdef __CYGWIN__ + extern int __set_lc_monetary_from_win (const char *, + struct lc_monetary_T *, + void *, const char *); + int old_monetary_using_locale = _monetary_using_locale; + _monetary_using_locale = 0; + ret = __set_lc_monetary_from_win (name, &_monetary_locale, + f_wctomb, charset); + /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ + if (ret < 0) + _monetary_using_locale = old_monetary_using_locale; + else + { + _monetary_using_locale = ret; + __mlocale_changed = 1; + ret = 0; + } +#else __mlocale_changed = 1; ret = __part_load_locale(name, &_monetary_using_locale, _monetary_locale_buf, "LC_MONETARY", @@ -94,6 +113,7 @@ __monetary_load_locale(const char *name) { M_ASSIGN_CHAR(p_sign_posn); M_ASSIGN_CHAR(n_sign_posn); } +#endif return ret; } diff --git a/newlib/libc/locale/lmonetary.h b/newlib/libc/locale/lmonetary.h index bbe77db42..14c9cc15d 100644 --- a/newlib/libc/locale/lmonetary.h +++ b/newlib/libc/locale/lmonetary.h @@ -29,6 +29,10 @@ #ifndef _LMONETARY_H_ #define _LMONETARY_H_ +#include + +__BEGIN_DECLS + struct lc_monetary_T { const char *int_curr_symbol; const char *currency_symbol; @@ -48,6 +52,8 @@ struct lc_monetary_T { }; struct lc_monetary_T *__get_current_monetary_locale(void); -int __monetary_load_locale(const char *); +int __monetary_load_locale(const char *, void *, const char *); + +__END_DECLS #endif /* !_LMONETARY_H_ */ diff --git a/newlib/libc/locale/lnumeric.c b/newlib/libc/locale/lnumeric.c index 90b404ca2..5bf0a7d11 100644 --- a/newlib/libc/locale/lnumeric.c +++ b/newlib/libc/locale/lnumeric.c @@ -48,10 +48,28 @@ static int _numeric_using_locale; static char *_numeric_locale_buf; int -__numeric_load_locale(const char *name) { - +__numeric_load_locale(const char *name , void *f_wctomb, const char *charset) +{ int ret; +#ifdef __CYGWIN__ + extern int __set_lc_numeric_from_win (const char *, + struct lc_numeric_T *, + void *, const char *); + int old_numeric_using_locale = _numeric_using_locale; + _numeric_using_locale = 0; + ret = __set_lc_numeric_from_win (name, &_numeric_locale, + f_wctomb, charset); + /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ + if (ret < 0) + _numeric_using_locale = old_numeric_using_locale; + else + { + _numeric_using_locale = ret; + __nlocale_changed = 1; + ret = 0; + } +#else __nlocale_changed = 1; ret = __part_load_locale(name, &_numeric_using_locale, _numeric_locale_buf, "LC_NUMERIC", @@ -60,6 +78,7 @@ __numeric_load_locale(const char *name) { if (ret == 0 && _numeric_using_locale) _numeric_locale.grouping = __fix_locale_grouping_str(_numeric_locale.grouping); +#endif return ret; } diff --git a/newlib/libc/locale/lnumeric.h b/newlib/libc/locale/lnumeric.h index 9678c1f02..bed75e868 100644 --- a/newlib/libc/locale/lnumeric.h +++ b/newlib/libc/locale/lnumeric.h @@ -29,6 +29,10 @@ #ifndef _LNUMERIC_H_ #define _LNUMERIC_H_ +#include + +__BEGIN_DECLS + struct lc_numeric_T { const char *decimal_point; const char *thousands_sep; @@ -36,6 +40,8 @@ struct lc_numeric_T { }; struct lc_numeric_T *__get_current_numeric_locale(void); -int __numeric_load_locale(const char *); +int __numeric_load_locale(const char *, void *, const char *); + +__END_DECLS #endif /* !_LNUMERIC_H_ */ diff --git a/newlib/libc/locale/locale.c b/newlib/libc/locale/locale.c index 1349927bf..4dd773463 100644 --- a/newlib/libc/locale/locale.c +++ b/newlib/libc/locale/locale.c @@ -75,7 +75,9 @@ Even when using POSIX locale strings, the only charsets allowed are 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258]. Charsets are case insensitive. For instance, <<"EUCJP">> and <<"eucJP">> are equivalent. <<"UTF-8">> can also be written without dash, as in -<<"UTF8">> or <<"utf8">>. +<<"UTF8">> or <<"utf8">>. <<"EUCJP">> and <<"EUCKR"> can also contain a +dash, <<"EUC-JP">> and <<"EUC-KR">>. + (<<"">> is also accepted; if given, the settings are read from the corresponding LC_* environment variables and $LANG according to POSIX rules. @@ -172,6 +174,8 @@ No supporting OS subroutines are required. #include #include #include +#include "lmonetary.h" +#include "lnumeric.h" #include "../stdlib/local.h" #define _LC_LAST 7 @@ -183,7 +187,11 @@ int __nlocale_changed = 0; int __mlocale_changed = 0; char *_PathLocale = NULL; -static _CONST struct lconv lconv = +static +#ifndef __CYGWIN__ +_CONST +#endif +struct lconv lconv = { ".", "", "", "", "", "", "", "", "", "", CHAR_MAX, CHAR_MAX, CHAR_MAX, CHAR_MAX, @@ -420,7 +428,8 @@ currentlocale() #ifdef _MB_CAPABLE #ifdef __CYGWIN__ -extern void *__set_charset_from_codepage (unsigned int, char *charset); +extern void __set_charset_from_locale (const char *locale, char *charset); +extern int __collate_load_locale (const char *, void *, const char *); #endif /* __CYGWIN__ */ extern void __set_ctype (const char *charset); @@ -447,6 +456,9 @@ loadlocale(struct _reent *p, int category) #ifdef _MB_CAPABLE int cjknarrow = 0; #endif +#ifdef __CYGWIN__ + int ret = 0; +#endif /* "POSIX" is translated to "C", as on Linux. */ if (!strcmp (locale, "POSIX")) @@ -502,7 +514,7 @@ loadlocale(struct _reent *p, int category) else if (c[0] == '\0' || c[0] == '@') /* End of string or just a modifier */ #ifdef __CYGWIN__ - __set_charset_from_codepage (0, charset); + __set_charset_from_locale (locale, charset); #else strcpy (charset, "ISO-8859-1"); #endif @@ -548,7 +560,7 @@ loadlocale(struct _reent *p, int category) break; case 'E': case 'e': - if (!strcasecmp (charset, "EUCJP")) + if (!strcasecmp (charset, "EUCJP") || !strcasecmp (charset, "EUC-JP")) { strcpy (charset, "EUCJP"); mbc_max = 3; @@ -558,7 +570,8 @@ loadlocale(struct _reent *p, int category) #endif } #ifdef __CYGWIN__ - else if (!strcasecmp (charset, "EUCKR")) + else if (!strcasecmp (charset, "EUCKR") + || !strcasecmp (charset, "EUC-KR")) { strcpy (charset, "EUCKR"); mbc_max = 2; @@ -729,6 +742,18 @@ loadlocale(struct _reent *p, int category) } else if (category == LC_MESSAGES) strcpy (lc_message_charset, charset); +#ifdef __CYGWIN__ + else if (category == LC_COLLATE) + ret = __collate_load_locale (locale, (void *) l_mbtowc, charset); + else if (category == LC_MONETARY) + ret = __monetary_load_locale (locale, (void *) l_wctomb, charset); + else if (category == LC_NUMERIC) + ret = __numeric_load_locale (locale, (void *) l_wctomb, charset); + else if (category == LC_TIME) + ret = __time_load_locale (locale, (void *) l_wctomb, charset); + if (ret) + return NULL; +#endif return strcpy(current_categories[category], new_categories[category]); } @@ -778,6 +803,42 @@ struct lconv * _DEFUN(_localeconv_r, (data), struct _reent *data) { +#ifdef __CYGWIN__ + if (__nlocale_changed) + { + struct lc_numeric_T *n = __get_current_numeric_locale (); + lconv.decimal_point = n->decimal_point; + lconv.thousands_sep = n->thousands_sep; + lconv.grouping = n->grouping; + __nlocale_changed = 0; + } + if (__mlocale_changed) + { + struct lc_monetary_T *m = __get_current_monetary_locale (); + lconv.int_curr_symbol = m->int_curr_symbol; + lconv.currency_symbol = m->currency_symbol; + lconv.mon_decimal_point = m->mon_decimal_point; + lconv.mon_thousands_sep = m->mon_thousands_sep; + lconv.mon_grouping = m->mon_grouping; + lconv.positive_sign = m->positive_sign; + lconv.negative_sign = m->negative_sign; + lconv.int_frac_digits = m->int_frac_digits[0]; + lconv.frac_digits = m->frac_digits[0]; + lconv.p_cs_precedes = m->p_cs_precedes[0]; + lconv.p_sep_by_space = m->p_sep_by_space[0]; + lconv.n_cs_precedes = m->n_cs_precedes[0]; + lconv.n_sep_by_space = m->n_sep_by_space[0]; + lconv.p_sign_posn = m->p_sign_posn[0]; + lconv.n_sign_posn = m->n_sign_posn[0]; + lconv.int_n_cs_precedes = m->n_cs_precedes[0]; + lconv.int_n_sep_by_space = m->n_sep_by_space[0]; + lconv.int_n_sign_posn = m->n_sign_posn[0]; + lconv.int_p_cs_precedes = m->p_cs_precedes[0]; + lconv.int_p_sep_by_space = m->p_sep_by_space[0]; + lconv.int_p_sign_posn = m->p_sign_posn[0]; + __mlocale_changed = 0; + } +#endif return (struct lconv *) &lconv; } diff --git a/newlib/libc/locale/nl_langinfo.c b/newlib/libc/locale/nl_langinfo.c index 550f92efd..ae7228cf6 100644 --- a/newlib/libc/locale/nl_langinfo.c +++ b/newlib/libc/locale/nl_langinfo.c @@ -133,10 +133,10 @@ _DEFUN(nl_langinfo, (item), ret = (char *) __get_current_time_locale()->ampm_fmt; break; case AM_STR: - ret = (char *) __get_current_time_locale()->am; + ret = (char *) __get_current_time_locale()->am_pm[0]; break; case PM_STR: - ret = (char *) __get_current_time_locale()->pm; + ret = (char *) __get_current_time_locale()->am_pm[1]; break; case DAY_1: case DAY_2: case DAY_3: case DAY_4: case DAY_5: case DAY_6: case DAY_7: diff --git a/newlib/libc/locale/timelocal.c b/newlib/libc/locale/timelocal.c index 5b097ad7c..0fe53bf42 100644 --- a/newlib/libc/locale/timelocal.c +++ b/newlib/libc/locale/timelocal.c @@ -70,11 +70,8 @@ static const struct lc_time_T _C_time_locale = { */ "%a %b %e %H:%M:%S %Y", - /* am */ - "AM", - - /* pm */ - "PM", + /* am pm */ + { "AM", "PM" }, /* date_fmt */ "%a %b %e %H:%M:%S %Z %Y", @@ -106,14 +103,29 @@ __get_current_time_locale(void) { } int -__time_load_locale(const char *name) { +__time_load_locale(const char *name, void *f_wctomb, const char *charset) { int ret; +#ifdef __CYGWIN__ + extern int __set_lc_time_from_win (const char *, struct lc_time_T *, + void *, const char *); + int old_time_using_locale = _time_using_locale; + _time_using_locale = 0; + ret = __set_lc_time_from_win (name, &_time_locale, f_wctomb, charset); + /* ret == -1: error, ret == 0: C/POSIX, ret > 0: valid */ + if (ret < 0) + _time_using_locale = old_time_using_locale; + else + { + _time_using_locale = ret; + ret = 0; + } +#else ret = __part_load_locale(name, &_time_using_locale, time_locale_buf, "LC_TIME", LCTIME_SIZE, LCTIME_SIZE, (const char **)&_time_locale); - +#endif return (ret); } diff --git a/newlib/libc/locale/timelocal.h b/newlib/libc/locale/timelocal.h index 0b0a59a48..e232a7304 100644 --- a/newlib/libc/locale/timelocal.h +++ b/newlib/libc/locale/timelocal.h @@ -29,6 +29,10 @@ #ifndef _TIMELOCAL_H_ #define _TIMELOCAL_H_ +#include + +__BEGIN_DECLS + /* * Private header file for the strftime and strptime localization * stuff. @@ -41,8 +45,7 @@ struct lc_time_T { const char *X_fmt; const char *x_fmt; const char *c_fmt; - const char *am; - const char *pm; + const char *am_pm[2]; const char *date_fmt; const char *alt_month[12]; const char *md_order; @@ -50,6 +53,8 @@ struct lc_time_T { }; struct lc_time_T *__get_current_time_locale(void); -int __time_load_locale(const char *); +int __time_load_locale(const char *, void *, const char *); + +__END_DECLS #endif /* !_TIMELOCAL_H_ */ diff --git a/newlib/libc/time/strftime.c b/newlib/libc/time/strftime.c index e9849ac9b..95fb3019c 100644 --- a/newlib/libc/time/strftime.c +++ b/newlib/libc/time/strftime.c @@ -52,26 +52,26 @@ following ways: o+ o %a -A three-letter abbreviation for the day of the week. [tm_wday] +The abbreviated weekday name according to the current locale. [tm_wday] o %A -The full name for the day of the week, one of `<>', -`<>', `<>', `<>', `<>', -`<>', or `<>'. [tm_wday] +The full weekday name according to the current locale. +In the default "C" locale, one of `<>', `<>', `<>', +`<>', `>', `<>', `<>'. [tm_wday] o %b -A three-letter abbreviation for the month name. [tm_mon] +The abbreviated month name according to the current locale. [tm_mon] o %B -The full name of the month, one of `<>', `<>', +The full month name according to the current locale. +In the default "C" locale, one of `<>', `<>', `<>', `<>', `<>', `<>', `<>', `<>', `<>', `<>', `<>', `<>'. [tm_mon] o %c -A string representing the complete date and time, in the form -`<<"%a %b %e %H:%M:%S %Y">>' (example "Mon Apr 01 13:13:13 -1992"). [tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday] +The preferred date and time representation for the current locale. +[tm_sec, tm_min, tm_hour, tm_mday, tm_mon, tm_year, tm_wday] o %C The century, that is, the year divided by 100 then truncated. For @@ -93,8 +93,7 @@ The day of the month, formatted with leading space if single digit o %E<> In some locales, the E modifier selects alternative representations of -certain modifiers <>. But in the "C" locale supported by newlib, -it is ignored, and treated as %<>. +certain modifiers <>. In newlib, it is ignored, and treated as %<>. o %F A string representing the ISO 8601:2000 date format, in the form @@ -115,8 +114,7 @@ Example: "%G" for Saturday 2nd January 1999 gives "1998", and for Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday] o %h -A three-letter abbreviation for the month name (synonym for -"%b"). [tm_mon] +Synonym for "%b". [tm_mon] o %H The hour (on a 24-hour clock), formatted with two digits (from @@ -150,15 +148,19 @@ A newline character (`<<\n>>'). o %O<> In some locales, the O modifier selects alternative digit characters -for certain modifiers <>. But in the "C" locale supported by newlib, it -is ignored, and treated as %<>. +for certain modifiers <>. In newlib, it is ignored, and treated as %<>. o %p -Either `<>' or `<>' as appropriate. [tm_hour] +Either `<>' or `<>' as appropriate, or the corresponding strings for +the current locale. [tm_hour] + +o %P +Same as '<<%p>>', but in lowercase. This is a GNU extension. [tm_hour] o %r -The 12-hour time, to the second. Equivalent to "%I:%M:%S %p". [tm_sec, -tm_min, tm_hour] +Replaced by the time in a.m. and p.m. notation. In the "C" locale this +is equivalent to "%I:%M:%S %p". In locales which don't define a.m./p.m. +notations, the result is an empty string. [tm_sec, tm_min, tm_hour] o %R The 24-hour time, to the minute. Equivalent to "%H:%M". [tm_min, tm_hour] @@ -198,12 +200,13 @@ Monday in a year, and earlier days are in week 0. Formatted with two digits (from `<<00>>' to `<<53>>'). [tm_wday, tm_yday] o %x -A string representing the complete date, equivalent to "%m/%d/%y". +Replaced by the preferred date representation in the current locale. +In the "C" locale this is equivalent to "%m/%d/%y". [tm_mon, tm_mday, tm_year] o %X -A string representing the full time of day (hours, minutes, and -seconds), equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour] +Replaced by the preferred time representation in the current locale. +In the "C" locale this is equivalent to "%H:%M:%S". [tm_sec, tm_min, tm_hour] o %y The last two digits of the year (from `<<00>>' to `<<99>>'). [tm_year] @@ -263,7 +266,10 @@ the "C" locale settings. #include #include #include +#include +#include #include "local.h" +#include "../locale/timelocal.h" /* Defines to make the file dual use for either strftime() or wcsftime(). * To get wcsftime, define MAKE_WCSFTIME. @@ -276,13 +282,28 @@ the "C" locale settings. # define CHAR char /* string type basis */ # define CQ(a) a /* character constant qualifier */ # define SFLG /* %s flag (null for normal char) */ +# define _ctloc(x) (ctloclen = strlen (ctloc = _CurrentTimeLocale->x), ctloc) +# define TOLOWER(c) tolower((int)(unsigned char)(c)) # else # define strftime wcsftime /* Alternate function name */ # define CHAR wchar_t /* string type basis */ # define CQ(a) L##a /* character constant qualifier */ # define snprintf swprintf /* wide-char equivalent function name */ # define strncmp wcsncmp /* wide-char equivalent function name */ +# define TOLOWER(c) towlower((wint_t)(c)) # define SFLG "l" /* %s flag (l for wide char) */ +# define CTLOCBUFLEN 256 /* Arbitrary big buffer size */ + const wchar_t * + __ctloc (wchar_t *buf, const char *elem, size_t *len_ret) + { + buf[CTLOCBUFLEN - 1] = L'\0'; + *len_ret = mbstowcs (buf, elem, CTLOCBUFLEN - 1); + if (*len_ret == (size_t) -1 ) + *len_ret = 0; + return buf; + } +# define _ctloc(x) (ctloc = __ctloc (ctlocbuf, _CurrentTimeLocale->x, \ + &ctloclen)) #endif /* MAKE_WCSFTIME */ /* Enforce the coding assumptions that YEAR_BASE is positive. (%C, %Y, etc.) */ @@ -293,18 +314,6 @@ the "C" locale settings. static _CONST int dname_len[7] = {6, 6, 7, 9, 8, 6, 8}; -static _CONST CHAR *_CONST dname[7] = -{CQ("Sunday"), CQ("Monday"), CQ("Tuesday"), CQ("Wednesday"), - CQ("Thursday"), CQ("Friday"), CQ("Saturday")}; - -static _CONST int mname_len[12] = -{7, 8, 5, 5, 3, 4, 4, 6, 9, 7, 8, 8}; - -static _CONST CHAR *_CONST mname[12] = -{CQ("January"), CQ("February"), CQ("March"), CQ("April"), - CQ("May"), CQ("June"), CQ("July"), CQ("August"), - CQ("September"), CQ("October"), CQ("November"), CQ("December")}; - /* Using the tm_year, tm_wday, and tm_yday components of TIM_P, return -1, 0, or 1 as the adjustment to add to the year for the ISO week numbering used in "%g%G%V", avoiding overflow. */ @@ -361,7 +370,13 @@ _DEFUN (strftime, (s, maxsize, format, tim_p), { size_t count = 0; int i, len; + const CHAR *ctloc; +#ifdef MAKE_WCSFTIME + CHAR ctlocbuf[CTLOCBUFLEN]; +#endif + size_t ctloclen; + struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale (); for (;;) { while (*format && *format != CQ('%')) @@ -382,56 +397,68 @@ _DEFUN (strftime, (s, maxsize, format, tim_p), switch (*format) { case CQ('a'): - for (i = 0; i < 3; i++) + _ctloc (wday[tim_p->tm_wday]); + for (i = 0; i < ctloclen; i++) { if (count < maxsize - 1) - s[count++] = - dname[tim_p->tm_wday][i]; + s[count++] = ctloc[i]; else return 0; } break; case CQ('A'): - for (i = 0; i < dname_len[tim_p->tm_wday]; i++) + _ctloc (weekday[tim_p->tm_wday]); + for (i = 0; i < ctloclen; i++) { if (count < maxsize - 1) - s[count++] = - dname[tim_p->tm_wday][i]; + s[count++] = ctloc[i]; else return 0; } break; case CQ('b'): case CQ('h'): - for (i = 0; i < 3; i++) + _ctloc (mon[tim_p->tm_mon]); + for (i = 0; i < ctloclen; i++) { if (count < maxsize - 1) - s[count++] = - mname[tim_p->tm_mon][i]; + s[count++] = ctloc[i]; else return 0; } break; case CQ('B'): - for (i = 0; i < mname_len[tim_p->tm_mon]; i++) + _ctloc (month[tim_p->tm_mon]); + for (i = 0; i < ctloclen; i++) { if (count < maxsize - 1) - s[count++] = - mname[tim_p->tm_mon][i]; + s[count++] = ctloc[i]; else return 0; } break; case CQ('c'): - { - /* Recurse to avoid need to replicate %Y formation. */ - size_t adjust = strftime (&s[count], maxsize - count, - CQ("%a %b %e %H:%M:%S %Y"), tim_p); - if (adjust > 0) - count += adjust; - else - return 0; - } + _ctloc (c_fmt); + goto recurse; + case CQ('r'): + _ctloc (ampm_fmt); + goto recurse; + case CQ('x'): + _ctloc (x_fmt); + goto recurse; + case CQ('X'): + _ctloc (X_fmt); +recurse: + if (*ctloc) + { + /* Recurse to avoid need to replicate %Y formation. */ + size_t adjust = strftime (&s[count], maxsize - count, ctloc, + tim_p); + if (adjust > 0) + count += adjust; + else + return 0; + } break; case CQ('C'): { @@ -472,7 +499,6 @@ _DEFUN (strftime, (s, maxsize, format, tim_p), if (len < 0 || (count+=len) >= maxsize) return 0; break; case CQ('D'): - case CQ('x'): /* %m/%d/%y */ len = snprintf (&s[count], maxsize - count, CQ("%.2d/%.2d/%.2d"), @@ -582,33 +608,16 @@ _DEFUN (strftime, (s, maxsize, format, tim_p), return 0; break; case CQ('p'): - if (count < maxsize - 1) + case CQ('P'): + _ctloc (am_pm[tim_p->tm_hour < 12 ? 0 : 1]); + for (i = 0; i < ctloclen; i++) { - if (tim_p->tm_hour < 12) - s[count++] = CQ('A'); + if (count < maxsize - 1) + s[count++] = (*format == CQ('P') ? TOLOWER (ctloc[i]) + : ctloc[i]); else - s[count++] = CQ('P'); - } - if (count < maxsize - 1) - { - s[count++] = CQ('M'); + return 0; } - else - return 0; - break; - case CQ('r'): - { - register int h12; - h12 = (tim_p->tm_hour == 0 || tim_p->tm_hour == 12) ? - 12 : tim_p->tm_hour % 12; - len = snprintf (&s[count], maxsize - count, - CQ("%.2d:%.2d:%.2d %cM"), - h12, - tim_p->tm_min, - tim_p->tm_sec, - (tim_p->tm_hour < 12) ? CQ('A') : CQ('P')); - if (len < 0 || (count+=len) >= maxsize) return 0; - } break; case CQ('R'): len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d"), @@ -627,7 +636,6 @@ _DEFUN (strftime, (s, maxsize, format, tim_p), return 0; break; case CQ('T'): - case CQ('X'): len = snprintf (&s[count], maxsize - count, CQ("%.2d:%.2d:%.2d"), tim_p->tm_hour, tim_p->tm_min, tim_p->tm_sec); if (len < 0 || (count+=len) >= maxsize) return 0; diff --git a/newlib/libc/time/strptime.c b/newlib/libc/time/strptime.c index 127772460..1457c93ed 100644 --- a/newlib/libc/time/strptime.c +++ b/newlib/libc/time/strptime.c @@ -36,66 +36,9 @@ #include #include #include +#include "../locale/timelocal.h" -static const char *abb_weekdays[] = { - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat", - NULL -}; - -static const char *full_weekdays[] = { - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - NULL -}; - -static const char *abb_month[] = { - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec", - NULL -}; - -static const char *full_month[] = { - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - NULL, -}; - -static const char *ampm[] = { - "am", - "pm", - NULL -}; +#define _ctloc(x) (_CurrentTimeLocale->x) /* * tm_year is relative this year @@ -205,6 +148,7 @@ _DEFUN (strptime, (buf, format, timeptr), { char c; + struct lc_time_T *_CurrentTimeLocale = __get_current_time_locale (); for (; (c = *format) != '\0'; ++format) { char *s; int ret; @@ -218,26 +162,26 @@ _DEFUN (strptime, (buf, format, timeptr), c = *++format; switch (c) { case 'A' : - ret = match_string (&buf, full_weekdays); + ret = match_string (&buf, _ctloc (weekday)); if (ret < 0) return NULL; timeptr->tm_wday = ret; break; case 'a' : - ret = match_string (&buf, abb_weekdays); + ret = match_string (&buf, _ctloc (wday)); if (ret < 0) return NULL; timeptr->tm_wday = ret; break; case 'B' : - ret = match_string (&buf, full_month); + ret = match_string (&buf, _ctloc (month)); if (ret < 0) return NULL; timeptr->tm_mon = ret; break; case 'b' : case 'h' : - ret = match_string (&buf, abb_month); + ret = match_string (&buf, _ctloc (mon)); if (ret < 0) return NULL; timeptr->tm_mon = ret; @@ -250,7 +194,7 @@ _DEFUN (strptime, (buf, format, timeptr), buf = s; break; case 'c' : /* %a %b %e %H:%M:%S %Y */ - s = strptime (buf, "%a %b %e %H:%M:%S %Y", timeptr); + s = strptime (buf, _ctloc (c_fmt), timeptr); if (s == NULL) return NULL; buf = s; @@ -316,7 +260,7 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; break; case 'p' : - ret = match_string (&buf, ampm); + ret = match_string (&buf, _ctloc (am_pm)); if (ret < 0) return NULL; if (timeptr->tm_hour == 0) { @@ -326,7 +270,7 @@ _DEFUN (strptime, (buf, format, timeptr), timeptr->tm_hour += 12; break; case 'r' : /* %I:%M:%S %p */ - s = strptime (buf, "%I:%M:%S %p", timeptr); + s = strptime (buf, _ctloc (ampm_fmt), timeptr); if (s == NULL) return NULL; buf = s; @@ -351,7 +295,6 @@ _DEFUN (strptime, (buf, format, timeptr), return NULL; break; case 'T' : /* %H:%M:%S */ - case 'X' : s = strptime (buf, "%H:%M:%S", timeptr); if (s == NULL) return NULL; @@ -393,11 +336,17 @@ _DEFUN (strptime, (buf, format, timeptr), buf = s; break; case 'x' : - s = strptime (buf, "%Y:%m:%d", timeptr); + s = strptime (buf, _ctloc (x_fmt), timeptr); if (s == NULL) return NULL; buf = s; break; + case 'X' : + s = strptime (buf, _ctloc (X_fmt), timeptr); + if (s == NULL) + return NULL; + buf = s; + break; case 'y' : ret = strtol (buf, &s, 10); if (s == buf) -- 2.43.5