From 50282f72bb9be6b49212a3978faec70786e9f97f Mon Sep 17 00:00:00 2001 From: Pavel Chupin Date: Tue, 25 Mar 2014 13:43:04 +0400 Subject: [PATCH] Add lconv declaration and localeconv(3) lconv is taken from ndk/sources/android/support/include/locale.h and matches bsd/glibc upstream. Keep old declaration for 32-bits for compatibility. localeconv.c and deps are taken from openbsd upstream. Changed strtod.c accordingly. Change-Id: I9fcc4d15f5674d192950d80edf26f36006cd31b4 Signed-off-by: Pavel Chupin --- libc/arch-arm64/arm64.mk | 5 + libc/arch-mips64/mips64.mk | 5 + libc/arch-x86_64/x86_64.mk | 5 + libc/include/locale.h | 35 +++++- libc/include/sys/localedef.h | 101 ++++++++++++++++++ libc/stdlib/strtod.c | 5 +- .../lib/libc/locale/_def_messages.c | 18 ++++ .../lib/libc/locale/_def_monetary.c | 30 ++++++ .../lib/libc/locale/_def_numeric.c | 17 +++ .../lib/libc/locale/_def_time.c | 36 +++++++ .../lib/libc/locale/localeconv.c | 59 ++++++++++ tests/Android.mk | 1 + tests/locale_test.cpp | 28 +++++ 13 files changed, 340 insertions(+), 5 deletions(-) create mode 100644 libc/include/sys/localedef.h create mode 100644 libc/upstream-openbsd/lib/libc/locale/_def_messages.c create mode 100644 libc/upstream-openbsd/lib/libc/locale/_def_monetary.c create mode 100644 libc/upstream-openbsd/lib/libc/locale/_def_numeric.c create mode 100644 libc/upstream-openbsd/lib/libc/locale/_def_time.c create mode 100644 libc/upstream-openbsd/lib/libc/locale/localeconv.c create mode 100644 tests/locale_test.cpp diff --git a/libc/arch-arm64/arm64.mk b/libc/arch-arm64/arm64.mk index 88da1f354..7b6b1c3c8 100644 --- a/libc/arch-arm64/arm64.mk +++ b/libc/arch-arm64/arm64.mk @@ -14,6 +14,11 @@ libc_common_src_files_arm64 := \ upstream-freebsd/lib/libc/string/wcslen.c \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ + upstream-openbsd/lib/libc/locale/_def_numeric.c \ + upstream-openbsd/lib/libc/locale/_def_messages.c \ + upstream-openbsd/lib/libc/locale/_def_monetary.c \ + upstream-openbsd/lib/libc/locale/_def_time.c \ + upstream-openbsd/lib/libc/locale/localeconv.c \ upstream-openbsd/lib/libc/string/bcopy.c \ upstream-openbsd/lib/libc/string/strcat.c \ upstream-openbsd/lib/libc/string/strcpy.c \ diff --git a/libc/arch-mips64/mips64.mk b/libc/arch-mips64/mips64.mk index 28806e183..9b29f0d01 100644 --- a/libc/arch-mips64/mips64.mk +++ b/libc/arch-mips64/mips64.mk @@ -16,6 +16,11 @@ libc_common_src_files_mips64 := \ upstream-freebsd/lib/libc/string/wcslen.c \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ + upstream-openbsd/lib/libc/locale/_def_numeric.c \ + upstream-openbsd/lib/libc/locale/_def_messages.c \ + upstream-openbsd/lib/libc/locale/_def_monetary.c \ + upstream-openbsd/lib/libc/locale/_def_time.c \ + upstream-openbsd/lib/libc/locale/localeconv.c \ upstream-openbsd/lib/libc/string/bcopy.c \ upstream-openbsd/lib/libc/string/strcat.c \ upstream-openbsd/lib/libc/string/strcmp.c \ diff --git a/libc/arch-x86_64/x86_64.mk b/libc/arch-x86_64/x86_64.mk index 9bce065b3..a3adaa4a2 100644 --- a/libc/arch-x86_64/x86_64.mk +++ b/libc/arch-x86_64/x86_64.mk @@ -18,6 +18,11 @@ libc_common_src_files_x86_64 := \ upstream-freebsd/lib/libc/string/wcslen.c \ upstream-freebsd/lib/libc/string/wcsrchr.c \ upstream-freebsd/lib/libc/string/wmemcmp.c \ + upstream-openbsd/lib/libc/locale/_def_numeric.c \ + upstream-openbsd/lib/libc/locale/_def_messages.c \ + upstream-openbsd/lib/libc/locale/_def_monetary.c \ + upstream-openbsd/lib/libc/locale/_def_time.c \ + upstream-openbsd/lib/libc/locale/localeconv.c \ upstream-openbsd/lib/libc/string/bcopy.c \ upstream-openbsd/lib/libc/string/strcat.c \ upstream-openbsd/lib/libc/string/strcmp.c \ diff --git a/libc/include/locale.h b/libc/include/locale.h index b6dbfdbb5..4efc5643b 100644 --- a/libc/include/locale.h +++ b/libc/include/locale.h @@ -51,12 +51,41 @@ enum { extern char* setlocale(int, const char*); -#if !defined(__LP64__) -// TODO: LP32 had these bogus declarations but LP64 should have a real struct lconv and localeconv(3). +#if defined(__LP64__) +struct lconv { + char* decimal_point; + char* thousands_sep; + char* grouping; + char* int_curr_symbol; + char* currency_symbol; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + /* ISO-C99 */ + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; +#else +// Keep old declaration for ILP32 for compatibility struct lconv { }; -struct lconv* localeconv(void); #endif +struct lconv* localeconv(void); + __END_DECLS #endif /* _LOCALE_H_ */ diff --git a/libc/include/sys/localedef.h b/libc/include/sys/localedef.h new file mode 100644 index 000000000..b6b5eb1af --- /dev/null +++ b/libc/include/sys/localedef.h @@ -0,0 +1,101 @@ +/* $OpenBSD: localedef.h,v 1.3 1996/04/21 22:31:47 deraadt Exp $ */ +/* $NetBSD: localedef.h,v 1.4 1996/04/09 20:55:31 cgd Exp $ */ + +/* + * Copyright (c) 1994 Winning Strategies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Winning Strategies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_LOCALEDEF_H_ +#define _SYS_LOCALEDEF_H_ + +#include +#include + +typedef struct +{ + char *yesexpr; + char *noexpr; + char *yesstr; + char *nostr; +} _MessagesLocale; + +extern const _MessagesLocale *_CurrentMessagesLocale; +extern const _MessagesLocale _DefaultMessagesLocale; + + +typedef struct +{ + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; +} _MonetaryLocale; + +extern const _MonetaryLocale *_CurrentMonetaryLocale; +extern const _MonetaryLocale _DefaultMonetaryLocale; + + +typedef struct +{ + const char *decimal_point; + const char *thousands_sep; + const char *grouping; +} _NumericLocale; + +extern const _NumericLocale *_CurrentNumericLocale; +extern const _NumericLocale _DefaultNumericLocale; + + +typedef struct { + const char *abday[7]; + const char *day[7]; + const char *abmon[12]; + const char *mon[12]; + const char *am_pm[2]; + const char *d_t_fmt; + const char *d_fmt; + const char *t_fmt; + const char *t_fmt_ampm; +} _TimeLocale; + +extern const _TimeLocale *_CurrentTimeLocale; +extern const _TimeLocale _DefaultTimeLocale; + +#endif /* !_SYS_LOCALEDEF_H_ */ diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c index 0a19446c1..b39c90efa 100644 --- a/libc/stdlib/strtod.c +++ b/libc/stdlib/strtod.c @@ -1332,13 +1332,14 @@ strtod Bigint *bb1, *bd0; Bigint *bb = NULL, *bd = NULL, *bs = NULL, *delta = NULL;/* pacify gcc */ - CONST char decimal_point = '.'; -#if 0 /* BEGIN android-changed: no localeconv. */ +#if defined(__LP64__) /* BEGIN android-changed: no localeconv for ILP32. */ #ifndef KR_headers CONST char decimal_point = localeconv()->decimal_point[0]; #else CONST char decimal_point = '.'; #endif +#else + CONST char decimal_point = '.'; #endif /* END android-changed */ sign = nz0 = nz = 0; diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_messages.c b/libc/upstream-openbsd/lib/libc/locale/_def_messages.c new file mode 100644 index 000000000..1ed653a97 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/_def_messages.c @@ -0,0 +1,18 @@ +/* $OpenBSD: _def_messages.c,v 1.5 2005/08/08 08:05:35 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include +#include + +const _MessagesLocale _DefaultMessagesLocale = +{ + "^[Yy]", + "^[Nn]", + "yes", + "no" +} ; + +const _MessagesLocale *_CurrentMessagesLocale = &_DefaultMessagesLocale; diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_monetary.c b/libc/upstream-openbsd/lib/libc/locale/_def_monetary.c new file mode 100644 index 000000000..aa92c75d1 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/_def_monetary.c @@ -0,0 +1,30 @@ +/* $OpenBSD: _def_monetary.c,v 1.4 2005/08/08 08:05:35 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include +#include +#include + +const _MonetaryLocale _DefaultMonetaryLocale = +{ + "", + "", + "", + "", + "", + "", + "", + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX, + CHAR_MAX +}; + +const _MonetaryLocale *_CurrentMonetaryLocale = &_DefaultMonetaryLocale; diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_numeric.c b/libc/upstream-openbsd/lib/libc/locale/_def_numeric.c new file mode 100644 index 000000000..6511254ac --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/_def_numeric.c @@ -0,0 +1,17 @@ +/* $OpenBSD: _def_numeric.c,v 1.4 2005/08/08 08:05:35 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include +#include + +const _NumericLocale _DefaultNumericLocale = +{ + ".", + "", + "" +}; + +const _NumericLocale *_CurrentNumericLocale = &_DefaultNumericLocale; diff --git a/libc/upstream-openbsd/lib/libc/locale/_def_time.c b/libc/upstream-openbsd/lib/libc/locale/_def_time.c new file mode 100644 index 000000000..75179a605 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/_def_time.c @@ -0,0 +1,36 @@ +/* $OpenBSD: _def_time.c,v 1.5 2011/10/09 06:39:53 ajacoutot Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include +#include + +const _TimeLocale _DefaultTimeLocale = +{ + { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat", + }, + { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }, + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, + { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" + }, + { + "AM", "PM" + }, + "%a %b %e %H:%M:%S %Y", + "%m/%d/%y", + "%H:%M:%S", + "%I:%M:%S %p" +}; + +const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale; diff --git a/libc/upstream-openbsd/lib/libc/locale/localeconv.c b/libc/upstream-openbsd/lib/libc/locale/localeconv.c new file mode 100644 index 000000000..989eb4bca --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/localeconv.c @@ -0,0 +1,59 @@ +/* $OpenBSD: localeconv.c,v 1.5 2005/08/08 08:05:35 espie Exp $ */ +/* + * Written by J.T. Conklin . + * Public domain. + */ + +#include +#include + +/* + * The localeconv() function constructs a struct lconv from the current + * monetary and numeric locales. + * + * Because localeconv() may be called many times (especially by library + * routines like printf() & strtod()), the approprate members of the + * lconv structure are computed only when the monetary or numeric + * locale has been changed. + */ +int __mlocale_changed = 1; +int __nlocale_changed = 1; + +/* + * Return the current locale conversion. + */ +struct lconv * +localeconv(void) +{ + static struct lconv ret; + + if (__mlocale_changed) { + /* LC_MONETARY */ + ret.int_curr_symbol = _CurrentMonetaryLocale->int_curr_symbol; + ret.currency_symbol = _CurrentMonetaryLocale->currency_symbol; + ret.mon_decimal_point = _CurrentMonetaryLocale->mon_decimal_point; + ret.mon_thousands_sep = _CurrentMonetaryLocale->mon_thousands_sep; + ret.mon_grouping = _CurrentMonetaryLocale->mon_grouping; + ret.positive_sign = _CurrentMonetaryLocale->positive_sign; + ret.negative_sign = _CurrentMonetaryLocale->negative_sign; + ret.int_frac_digits = _CurrentMonetaryLocale->int_frac_digits; + ret.frac_digits = _CurrentMonetaryLocale->frac_digits; + ret.p_cs_precedes = _CurrentMonetaryLocale->p_cs_precedes; + ret.p_sep_by_space = _CurrentMonetaryLocale->p_sep_by_space; + ret.n_cs_precedes = _CurrentMonetaryLocale->n_cs_precedes; + ret.n_sep_by_space = _CurrentMonetaryLocale->n_sep_by_space; + ret.p_sign_posn = _CurrentMonetaryLocale->p_sign_posn; + ret.n_sign_posn = _CurrentMonetaryLocale->n_sign_posn; + __mlocale_changed = 0; + } + + if (__nlocale_changed) { + /* LC_NUMERIC */ + ret.decimal_point = (char *) _CurrentNumericLocale->decimal_point; + ret.thousands_sep = (char *) _CurrentNumericLocale->thousands_sep; + ret.grouping = (char *) _CurrentNumericLocale->grouping; + __nlocale_changed = 0; + } + + return (&ret); +} diff --git a/tests/Android.mk b/tests/Android.mk index a37ea4a75..788dbcf0f 100644 --- a/tests/Android.mk +++ b/tests/Android.mk @@ -50,6 +50,7 @@ libBionicStandardTests_src_files := \ inttypes_test.cpp \ libc_logging_test.cpp \ libgen_test.cpp \ + locale_test.cpp \ malloc_test.cpp \ math_test.cpp \ netdb_test.cpp \ diff --git a/tests/locale_test.cpp b/tests/locale_test.cpp new file mode 100644 index 000000000..df58a70df --- /dev/null +++ b/tests/locale_test.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +TEST(locale, localeconv) { +#ifdef __LP64__ + ASSERT_STREQ(".", localeconv()->decimal_point); + ASSERT_STREQ("", localeconv()->currency_symbol); +#else + GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif +}