diff options
author | Florian Weimer <fweimer@redhat.com> | 2016-04-04 15:18:13 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2016-04-04 15:18:13 +0200 |
commit | 985fc132f23dbb83de76c5af9e783ef1b5900148 (patch) | |
tree | f41ba85592ceae633f11c973f81971da23653f15 /stdlib | |
parent | 5cd7af016d8587ff53b20ba259746f97edbddbf7 (diff) | |
download | glibc-985fc132f23dbb83de76c5af9e783ef1b5900148.tar.gz glibc-985fc132f23dbb83de76c5af9e783ef1b5900148.tar.xz glibc-985fc132f23dbb83de76c5af9e783ef1b5900148.zip |
strfmon_l: Use specified locale for number formatting [BZ #19633]
Diffstat (limited to 'stdlib')
-rw-r--r-- | stdlib/Makefile | 6 | ||||
-rw-r--r-- | stdlib/strfmon_l.c | 5 | ||||
-rw-r--r-- | stdlib/tst-strfmon_l.c | 220 |
3 files changed, 225 insertions, 6 deletions
diff --git a/stdlib/Makefile b/stdlib/Makefile index 26fe67ad95..d9787744d5 100644 --- a/stdlib/Makefile +++ b/stdlib/Makefile @@ -76,7 +76,7 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \ tst-secure-getenv tst-strtod-overflow tst-strtod-round \ tst-tininess tst-strtod-underflow tst-tls-atexit \ tst-setcontext3 tst-tls-atexit-nodelete \ - tst-strtol-locale tst-strtod-nan-locale + tst-strtol-locale tst-strtod-nan-locale tst-strfmon_l tests-static := tst-secure-getenv modules-names = tst-tls-atexit-lib @@ -126,7 +126,8 @@ include ../Rules ifeq ($(run-built-tests),yes) LOCALES := cs_CZ.UTF-8 de_DE.UTF-8 en_US.ISO-8859-1 tr_TR.UTF-8 \ - tr_TR.ISO-8859-9 + tr_TR.ISO-8859-9 tg_TJ.UTF-8 te_IN.UTF-8 bn_IN.UTF-8 \ + el_GR.UTF-8 include ../gen-locales.mk $(objpfx)bug-strtod2.out: $(gen-locales) @@ -137,6 +138,7 @@ $(objpfx)tst-strtod4.out: $(gen-locales) $(objpfx)tst-strtod5.out: $(gen-locales) $(objpfx)tst-strtol-locale.out: $(gen-locales) $(objpfx)tst-strtod-nan-locale.out: $(gen-locales) +$(objpfx)tst-strfmon_l.out: $(gen-locales) endif # Testdir has to be named stdlib and needs to be writable diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c index b3570209fa..5851a5b94a 100644 --- a/stdlib/strfmon_l.c +++ b/stdlib/strfmon_l.c @@ -68,9 +68,6 @@ #define _NL_CURRENT(category, item) \ (current->values[_NL_ITEM_INDEX (item)].string) -extern int __printf_fp (FILE *, const struct printf_info *, - const void *const *); -libc_hidden_proto (__printf_fp) /* This function determines the number of digit groups in the output. The definition is in printf_fp.c. */ extern unsigned int __guess_grouping (unsigned int intdig_max, @@ -532,7 +529,7 @@ __vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format, info.extra = 1; /* This means use values from LC_MONETARY. */ ptr = &fpnum; - done = __printf_fp (&f._sbf._f, &info, &ptr); + done = __printf_fp_l (&f._sbf._f, loc, &info, &ptr); if (done < 0) return -1; diff --git a/stdlib/tst-strfmon_l.c b/stdlib/tst-strfmon_l.c new file mode 100644 index 0000000000..684151106d --- /dev/null +++ b/stdlib/tst-strfmon_l.c @@ -0,0 +1,220 @@ +/* Test locale dependence of strfmon_l. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <stdio.h> +#include <monetary.h> +#include <string.h> +#include <stdlib.h> +#include <locale.h> + +static const char *const en_us_name = "en_US.ISO-8859-1"; + +/* Locale value to be used by tests. */ +static locale_t loc; +static const char *loc_name; + +/* Set the global locale to GLOBAL_NAME, and the locale referenced by + the loc variable above to LOCAL_NAME. */ +static void +init_loc (const char *global_name, const char *local_name) +{ + loc = newlocale (LC_ALL_MASK, local_name, 0); + if (loc == 0) + { + printf ("error: newlocale (%s): %m\n", local_name); + abort (); + } + loc_name = local_name; + + if (setlocale (LC_ALL, global_name) == NULL) + { + printf ("error: setlocale (%s): %m\n", global_name); + abort (); + } +} + +/* Expected strings for a positive or negative value. */ +struct testcase +{ + const char *i; /* %i */ + const char *n; /* %n */ + const char *i_ungrouped; /* %^i */ + const char *n_ungrouped; /* %^n */ +}; + +/* Collected expected strings for both positive and negative + values. */ +struct testcase_pair +{ + struct testcase positive; /* 1234567.89 */ + struct testcase negative; /* -1234567.89 */ +}; + +static bool errors; + +/* Test one value using the locale loc. */ +static void +test_one (const char *format, double value, const char *expected) +{ + static char actual[64]; + int result = strfmon_l (actual, sizeof (actual), loc, format, value); + if (result < 0) + { + printf ("error: locale %s, format \"%s\", value %g: strfmon_l: %m\n", + loc_name, format, value); + errors = true; + } + else if (strcmp (actual, expected) != 0) + { + printf ("error: locale %s, format \"%s\", value %g: mismatch\n", + loc_name, format, value); + printf ("error: expected: \"%s\"\n", expected); + printf ("error: actual: \"%s\"\n", actual); + errors = true; + } +} + +static void +test_pair (const struct testcase_pair *pair) +{ + double positive = 1234567.89; + test_one ("%i", positive, pair->positive.i); + test_one ("%n", positive, pair->positive.n); + test_one ("%^i", positive, pair->positive.i_ungrouped); + test_one ("%^n", positive, pair->positive.n_ungrouped); + double negative = -1234567.89; + test_one ("%i", negative, pair->negative.i); + test_one ("%n", negative, pair->negative.n); + test_one ("%^i", negative, pair->negative.i_ungrouped); + test_one ("%^n", negative, pair->negative.n_ungrouped); +} + +static const struct testcase_pair en_us = + { + { + "USD 1,234,567.89", "$1,234,567.89", + "USD 1234567.89", "$1234567.89" + }, + { + "-USD 1,234,567.89", "-$1,234,567.89", + "-USD 1234567.89", "-$1234567.89" + } + }; + +static void +test_en_us (const char *other_name) +{ + init_loc (other_name, en_us_name); + test_pair (&en_us); + freelocale (loc); +} + +struct locale_pair +{ + const char *locale_name; + struct testcase_pair pair; +}; + +static const struct locale_pair tests[] = + { + { + "de_DE.UTF-8", + { + { + "1.234.567,89 EUR", "1.234.567,89 \u20ac", + "1234567,89 EUR", "1234567,89 \u20ac" + }, + { + "-1.234.567,89 EUR", "-1.234.567,89 \u20ac", + "-1234567,89 EUR", "-1234567,89 \u20ac" + } + }, + }, + { + "tg_TJ.UTF-8", + { + { + "1 234 567.89 TJS", "1 234 567.89 \u0440\u0443\u0431", + "1234567.89 TJS", "1234567.89 \u0440\u0443\u0431" + }, + { + "-1 234 567.89 TJS", "-1 234 567.89 \u0440\u0443\u0431", + "-1234567.89 TJS", "-1234567.89 \u0440\u0443\u0431" + } + } + }, + { + "te_IN.UTF-8", + { + { + "INR12,34,567.89", "\u20b912,34,567.89", + "INR1234567.89", "\u20b91234567.89" + }, + { + "-INR12,34,567.89", "-\u20b912,34,567.89", + "-INR1234567.89", "-\u20b91234567.89" + } + } + }, + { + "bn_IN.UTF-8", + { + { + "INR 12,345,67.89", "\u20b9 12,345,67.89", + "INR 1234567.89", "\u20b9 1234567.89" + }, + { + "-INR 12,345,67.89", "-\u20b9 12,345,67.89", + "-INR 1234567.89", "-\u20b9 1234567.89" + } + } + }, + { + "el_GR.UTF-8", + { + { + "1.234.567,89EUR", "1.234.567,89\u20ac", + "1234567,89EUR", "1234567,89\u20ac" + }, + { + "-EUR1.234.567,89", "-\u20ac1.234.567,89", + "-EUR1234567,89", "-\u20ac1234567,89", + } + } + }, + {} + }; + +static int +do_test (void) +{ + for (const struct locale_pair *test = tests; + test->locale_name != NULL; ++test) + { + init_loc (en_us_name, test->locale_name); + test_pair (&test->pair); + freelocale (loc); + test_en_us (test->locale_name); + } + + return errors; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |