diff options
author | Elliott Hughes <enh@google.com> | 2016-11-18 16:27:29 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2016-11-19 11:46:54 -0800 |
commit | fc8e688c322a28803b62eb5bff3c842a440bb2b5 (patch) | |
tree | afd7c15b513b9ed246f7b1cbb34de3004c5e53e0 | |
parent | a5c16983a65e2169174a0e77a54c0ce650f87b48 (diff) | |
download | android_bionic-fc8e688c322a28803b62eb5bff3c842a440bb2b5.tar.gz android_bionic-fc8e688c322a28803b62eb5bff3c842a440bb2b5.tar.bz2 android_bionic-fc8e688c322a28803b62eb5bff3c842a440bb2b5.zip |
Implement <langinfo.h>.
POSIX locale only, as usual.
The GNU YESSTR and NOSTR extensions return the empty string in the C locale,
so I haven't bothered supporting them.
Bug: http://b/1401872
Test: bionic tests
Change-Id: I6846839e4f9f1812344ed5dce0b93f83c0c20eb3
-rw-r--r-- | libc/Android.bp | 1 | ||||
-rw-r--r-- | libc/bionic/langinfo.cpp | 103 | ||||
-rw-r--r-- | libc/include/langinfo.h | 100 | ||||
-rw-r--r-- | libc/libc.arm.map | 2 | ||||
-rw-r--r-- | libc/libc.arm64.map | 2 | ||||
-rw-r--r-- | libc/libc.map.txt | 2 | ||||
-rw-r--r-- | libc/libc.mips.map | 2 | ||||
-rw-r--r-- | libc/libc.mips64.map | 2 | ||||
-rw-r--r-- | libc/libc.x86.map | 2 | ||||
-rw-r--r-- | libc/libc.x86_64.map | 2 | ||||
-rw-r--r-- | libc/upstream-openbsd/lib/libc/include/langinfo.h | 3 | ||||
-rw-r--r-- | tests/Android.bp | 1 | ||||
-rw-r--r-- | tests/langinfo_test.cpp | 146 |
13 files changed, 365 insertions, 3 deletions
diff --git a/libc/Android.bp b/libc/Android.bp index f326db3a8..f0930fe08 100644 --- a/libc/Android.bp +++ b/libc/Android.bp @@ -1262,6 +1262,7 @@ cc_library_static { "bionic/ifaddrs.cpp", "bionic/inotify_init.cpp", "bionic/ioctl.cpp", + "bionic/langinfo.cpp", "bionic/lchown.cpp", "bionic/lfs64_support.cpp", "bionic/__libc_current_sigrtmax.cpp", diff --git a/libc/bionic/langinfo.cpp b/libc/bionic/langinfo.cpp new file mode 100644 index 000000000..6f5057cbd --- /dev/null +++ b/libc/bionic/langinfo.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + */ + +#include <langinfo.h> + +#include <stdlib.h> + +char* nl_langinfo(nl_item item) { + const char* result = ""; + switch (item) { + case CODESET: result = (MB_CUR_MAX == 1) ? "ASCII" : "UTF-8"; break; + + case D_T_FMT: result = "%F %T %z"; break; + case D_FMT: result = "%F"; break; + case T_FMT: result = "%T"; break; + case T_FMT_AMPM: result = "%I:%M:%S %p"; break; + case AM_STR: result = "AM"; break; + case PM_STR: result = "PM"; break; + case DAY_1: result = "Sunday"; break; + case DAY_2: result = "Monday"; break; + case DAY_3: result = "Tuesday"; break; + case DAY_4: result = "Wednesday"; break; + case DAY_5: result = "Thursday"; break; + case DAY_6: result = "Friday"; break; + case DAY_7: result = "Saturday"; break; + case ABDAY_1: result = "Sun"; break; + case ABDAY_2: result = "Mon"; break; + case ABDAY_3: result = "Tue"; break; + case ABDAY_4: result = "Wed"; break; + case ABDAY_5: result = "Thu"; break; + case ABDAY_6: result = "Fri"; break; + case ABDAY_7: result = "Sat"; break; + case MON_1: result = "January"; break; + case MON_2: result = "February"; break; + case MON_3: result = "March"; break; + case MON_4: result = "April"; break; + case MON_5: result = "May"; break; + case MON_6: result = "June"; break; + case MON_7: result = "July"; break; + case MON_8: result = "August"; break; + case MON_9: result = "September"; break; + case MON_10: result = "October"; break; + case MON_11: result = "November"; break; + case MON_12: result = "December"; break; + case ABMON_1: result = "Jan"; break; + case ABMON_2: result = "Feb"; break; + case ABMON_3: result = "Mar"; break; + case ABMON_4: result = "Apr"; break; + case ABMON_5: result = "May"; break; + case ABMON_6: result = "Jun"; break; + case ABMON_7: result = "Jul"; break; + case ABMON_8: result = "Aug"; break; + case ABMON_9: result = "Sep"; break; + case ABMON_10: result = "Oct"; break; + case ABMON_11: result = "Nov"; break; + case ABMON_12: result = "Dec"; break; + case ERA: result = ""; break; + case ERA_D_FMT: result = ""; break; + case ERA_D_T_FMT: result = ""; break; + case ERA_T_FMT: result = ""; break; + case ALT_DIGITS: result = ""; break; + + case RADIXCHAR: result = "."; break; + case THOUSEP: result = ""; break; + + case YESEXPR: result = "^[yY]"; break; + case NOEXPR: result = "^[nN]"; break; + + case CRNCYSTR: result = ""; break; + + default: break; + } + return const_cast<char*>(result); +} + +char* nl_langinfo_l(nl_item item, locale_t) { + return nl_langinfo(item); +} diff --git a/libc/include/langinfo.h b/libc/include/langinfo.h new file mode 100644 index 000000000..5c884ace8 --- /dev/null +++ b/libc/include/langinfo.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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 _LANGINFO_H_ +#define _LANGINFO_H_ + +#include <sys/cdefs.h> + +#include <nl_types.h> +#include <xlocale.h> + +__BEGIN_DECLS + +#define CODESET 1 +#define D_T_FMT 2 +#define D_FMT 3 +#define T_FMT 4 +#define T_FMT_AMPM 5 +#define AM_STR 6 +#define PM_STR 7 +#define DAY_1 8 +#define DAY_2 9 +#define DAY_3 10 +#define DAY_4 11 +#define DAY_5 12 +#define DAY_6 13 +#define DAY_7 14 +#define ABDAY_1 15 +#define ABDAY_2 16 +#define ABDAY_3 17 +#define ABDAY_4 18 +#define ABDAY_5 19 +#define ABDAY_6 20 +#define ABDAY_7 21 +#define MON_1 22 +#define MON_2 23 +#define MON_3 24 +#define MON_4 25 +#define MON_5 26 +#define MON_6 27 +#define MON_7 28 +#define MON_8 29 +#define MON_9 30 +#define MON_10 31 +#define MON_11 32 +#define MON_12 33 +#define ABMON_1 34 +#define ABMON_2 35 +#define ABMON_3 36 +#define ABMON_4 37 +#define ABMON_5 38 +#define ABMON_6 39 +#define ABMON_7 40 +#define ABMON_8 41 +#define ABMON_9 42 +#define ABMON_10 43 +#define ABMON_11 44 +#define ABMON_12 45 +#define ERA 46 +#define ERA_D_FMT 47 +#define ERA_D_T_FMT 48 +#define ERA_T_FMT 49 +#define ALT_DIGITS 50 +#define RADIXCHAR 51 +#define THOUSEP 52 +#define YESEXPR 53 +#define NOEXPR 54 +#define CRNCYSTR 55 + +char* nl_langinfo(nl_item) __INTRODUCED_IN_FUTURE; +char* nl_langinfo_l(nl_item, locale_t) __INTRODUCED_IN_FUTURE; + +__END_DECLS + +#endif diff --git a/libc/libc.arm.map b/libc/libc.arm.map index eb75e8fbb..f9c5ede7c 100644 --- a/libc/libc.arm.map +++ b/libc/libc.arm.map @@ -1288,6 +1288,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map index 28755d42d..179d8bff1 100644 --- a/libc/libc.arm64.map +++ b/libc/libc.arm64.map @@ -1210,6 +1210,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.map.txt b/libc/libc.map.txt index 1fba8eeb8..f122937fe 100644 --- a/libc/libc.map.txt +++ b/libc/libc.map.txt @@ -1313,6 +1313,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.mips.map b/libc/libc.mips.map index f61f615b7..a969703f2 100644 --- a/libc/libc.mips.map +++ b/libc/libc.mips.map @@ -1272,6 +1272,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map index 28755d42d..179d8bff1 100644 --- a/libc/libc.mips64.map +++ b/libc/libc.mips64.map @@ -1210,6 +1210,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.x86.map b/libc/libc.x86.map index a16636147..dfa839e9d 100644 --- a/libc/libc.x86.map +++ b/libc/libc.x86.map @@ -1270,6 +1270,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map index 28755d42d..179d8bff1 100644 --- a/libc/libc.x86_64.map +++ b/libc/libc.x86_64.map @@ -1210,6 +1210,8 @@ LIBC_O { msgget; # future msgrcv; # future msgsnd; # future + nl_langinfo; # future + nl_langinfo_l; # future pthread_getname_np; # future quotactl; # future semctl; # future diff --git a/libc/upstream-openbsd/lib/libc/include/langinfo.h b/libc/upstream-openbsd/lib/libc/include/langinfo.h deleted file mode 100644 index a871ab8bf..000000000 --- a/libc/upstream-openbsd/lib/libc/include/langinfo.h +++ /dev/null @@ -1,3 +0,0 @@ -/* Hack to build "vfprintf.c". */ -#define RADIXCHAR 1 -#define nl_langinfo(i) ((i == RADIXCHAR) ? (char*) "." : NULL) diff --git a/tests/Android.bp b/tests/Android.bp index 3e1e13b4c..362fe392e 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -68,6 +68,7 @@ cc_test_library { "grp_pwd_test.cpp", "ifaddrs_test.cpp", "inttypes_test.cpp", + "langinfo_test.cpp", "libc_logging_test.cpp", "libgen_basename_test.cpp", "libgen_test.cpp", diff --git a/tests/langinfo_test.cpp b/tests/langinfo_test.cpp new file mode 100644 index 000000000..6eae8bc66 --- /dev/null +++ b/tests/langinfo_test.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 + * COPYRIGHT OWNER OR CONTRIBUTORS 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. + */ + +#include <gtest/gtest.h> + +#include <langinfo.h> + +TEST(langinfo, category_CTYPE) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + EXPECT_STREQ("UTF-8", nl_langinfo(CODESET)); +} + +TEST(langinfo, category_TIME) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + +#if defined(__BIONIC__) + // bionic's C locale is ISO rather than en_US. + EXPECT_STREQ("%F %T %z", nl_langinfo(D_T_FMT)); + EXPECT_STREQ("%F", nl_langinfo(D_FMT)); +#else + EXPECT_STREQ("%a %d %b %Y %r %Z", nl_langinfo(D_T_FMT)); + EXPECT_STREQ("%m/%d/%Y", nl_langinfo(D_FMT)); +#endif + EXPECT_STREQ("%T", nl_langinfo(T_FMT)); + EXPECT_STREQ("%I:%M:%S %p", nl_langinfo(T_FMT_AMPM)); + EXPECT_STREQ("AM", nl_langinfo(AM_STR)); + EXPECT_STREQ("PM", nl_langinfo(PM_STR)); + EXPECT_STREQ("Sunday", nl_langinfo(DAY_1)); + EXPECT_STREQ("Monday", nl_langinfo(DAY_2)); + EXPECT_STREQ("Tuesday", nl_langinfo(DAY_3)); + EXPECT_STREQ("Wednesday", nl_langinfo(DAY_4)); + EXPECT_STREQ("Thursday", nl_langinfo(DAY_5)); + EXPECT_STREQ("Friday", nl_langinfo(DAY_6)); + EXPECT_STREQ("Saturday", nl_langinfo(DAY_7)); + EXPECT_STREQ("Sun", nl_langinfo(ABDAY_1)); + EXPECT_STREQ("Mon", nl_langinfo(ABDAY_2)); + EXPECT_STREQ("Tue", nl_langinfo(ABDAY_3)); + EXPECT_STREQ("Wed", nl_langinfo(ABDAY_4)); + EXPECT_STREQ("Thu", nl_langinfo(ABDAY_5)); + EXPECT_STREQ("Fri", nl_langinfo(ABDAY_6)); + EXPECT_STREQ("Sat", nl_langinfo(ABDAY_7)); + EXPECT_STREQ("January", nl_langinfo(MON_1)); + EXPECT_STREQ("February", nl_langinfo(MON_2)); + EXPECT_STREQ("March", nl_langinfo(MON_3)); + EXPECT_STREQ("April", nl_langinfo(MON_4)); + EXPECT_STREQ("May", nl_langinfo(MON_5)); + EXPECT_STREQ("June", nl_langinfo(MON_6)); + EXPECT_STREQ("July", nl_langinfo(MON_7)); + EXPECT_STREQ("August", nl_langinfo(MON_8)); + EXPECT_STREQ("September", nl_langinfo(MON_9)); + EXPECT_STREQ("October", nl_langinfo(MON_10)); + EXPECT_STREQ("November", nl_langinfo(MON_11)); + EXPECT_STREQ("December", nl_langinfo(MON_12)); + EXPECT_STREQ("Jan", nl_langinfo(ABMON_1)); + EXPECT_STREQ("Feb", nl_langinfo(ABMON_2)); + EXPECT_STREQ("Mar", nl_langinfo(ABMON_3)); + EXPECT_STREQ("Apr", nl_langinfo(ABMON_4)); + EXPECT_STREQ("May", nl_langinfo(ABMON_5)); + EXPECT_STREQ("Jun", nl_langinfo(ABMON_6)); + EXPECT_STREQ("Jul", nl_langinfo(ABMON_7)); + EXPECT_STREQ("Aug", nl_langinfo(ABMON_8)); + EXPECT_STREQ("Sep", nl_langinfo(ABMON_9)); + EXPECT_STREQ("Oct", nl_langinfo(ABMON_10)); + EXPECT_STREQ("Nov", nl_langinfo(ABMON_11)); + EXPECT_STREQ("Dec", nl_langinfo(ABMON_12)); + EXPECT_STREQ("", nl_langinfo(ERA)); + EXPECT_STREQ("", nl_langinfo(ERA_D_FMT)); + EXPECT_STREQ("", nl_langinfo(ERA_D_T_FMT)); + EXPECT_STREQ("", nl_langinfo(ERA_T_FMT)); + EXPECT_STREQ("", nl_langinfo(ALT_DIGITS)); +} + +TEST(langinfo, category_NUMERIC) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + EXPECT_STREQ(".", nl_langinfo(RADIXCHAR)); + EXPECT_STREQ("", nl_langinfo(THOUSEP)); +} + +TEST(langinfo, category_MESSAGES) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + EXPECT_STREQ("^[yY]", nl_langinfo(YESEXPR)); + EXPECT_STREQ("^[nN]", nl_langinfo(NOEXPR)); +} + +TEST(langinfo, category_MONETARY) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + // POSIX says that if the currency symbol is the empty string (as it is for + // the C locale), an implementation can return the empty string and not + // include the leading [+-.] that signifies where the currency symbol should + // appear. For consistency with localeconv (which POSIX says to prefer for + // RADIXCHAR, THOUSEP, and CRNCYSTR) we return the empty string. glibc + // disagrees. +#if defined(__BIONIC__) + EXPECT_STREQ("", nl_langinfo(CRNCYSTR)); +#else + EXPECT_STREQ("-", nl_langinfo(CRNCYSTR)); +#endif +} + +TEST(langinfo, invalid) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + EXPECT_STREQ("", nl_langinfo(-1)); + EXPECT_STREQ("", nl_langinfo(0)); + EXPECT_STREQ("", nl_langinfo(666)); +} + +TEST(langinfo, matches_localeconv) { + ASSERT_STREQ("C.UTF-8", setlocale(LC_ALL, "C.UTF-8")); + + EXPECT_STREQ(localeconv()->decimal_point, nl_langinfo(RADIXCHAR)); + EXPECT_STREQ(localeconv()->thousands_sep, nl_langinfo(THOUSEP)); +#if defined(__BIONIC__) + // (See comment in category_MONETARY test.) + EXPECT_STREQ(localeconv()->currency_symbol, nl_langinfo(CRNCYSTR)); +#endif +} |