Date: Wed, 19 Dec 2018 22:57:47 +0000 (UTC) From: Conrad Meyer <cem@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r342260 - in head/lib/libc: stdlib tests/stdlib Message-ID: <201812192257.wBJMvlct055323@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: cem Date: Wed Dec 19 22:57:47 2018 New Revision: 342260 URL: https://svnweb.freebsd.org/changeset/base/342260 Log: Allow multi-byte thousands separators in strfmon(3) PR: 234010 Reported by: Jon Tejnung <jon AT herrskogen.se> Reviewed by: yuripv Differential Revision: https://reviews.freebsd.org/D18605 Added: head/lib/libc/tests/stdlib/strfmon_test.c (contents, props changed) Modified: head/lib/libc/stdlib/strfmon.c head/lib/libc/tests/stdlib/Makefile Modified: head/lib/libc/stdlib/strfmon.c ============================================================================== --- head/lib/libc/stdlib/strfmon.c Wed Dec 19 22:56:31 2018 (r342259) +++ head/lib/libc/stdlib/strfmon.c Wed Dec 19 22:57:47 2018 (r342260) @@ -92,7 +92,8 @@ __FBSDID("$FreeBSD$"); } while (0) #define GRPSEP do { \ - *--bufend = thousands_sep; \ + bufend -= thousands_sep_size; \ + memcpy(bufend, thousands_sep, thousands_sep_size); \ groups++; \ } while (0) @@ -520,7 +521,7 @@ get_groups(int size, char *grouping) { return (chars); } -/* convert double to ASCII */ +/* convert double to locale-encoded string */ static char * __format_grouped_double(double value, int *flags, int left_prec, int right_prec, int pad_char) { @@ -536,19 +537,24 @@ __format_grouped_double(double value, int *flags, struct lconv *lc = localeconv(); char *grouping; - char decimal_point; - char thousands_sep; + const char *decimal_point; + const char *thousands_sep; + size_t decimal_point_size; + size_t thousands_sep_size; int groups = 0; grouping = lc->mon_grouping; - decimal_point = *lc->mon_decimal_point; - if (decimal_point == '\0') - decimal_point = *lc->decimal_point; - thousands_sep = *lc->mon_thousands_sep; - if (thousands_sep == '\0') - thousands_sep = *lc->thousands_sep; + decimal_point = lc->mon_decimal_point; + if (*decimal_point == '\0') + decimal_point = lc->decimal_point; + thousands_sep = lc->mon_thousands_sep; + if (*thousands_sep == '\0') + thousands_sep = lc->thousands_sep; + decimal_point_size = strlen(decimal_point); + thousands_sep_size = strlen(thousands_sep); + /* fill left_prec with default value */ if (left_prec == -1) left_prec = 0; @@ -574,7 +580,8 @@ __format_grouped_double(double value, int *flags, return (NULL); /* make sure that we've enough space for result string */ - bufsize = avalue_size * 2 + 1; + bufsize = avalue_size * (1 + thousands_sep_size) + decimal_point_size + + 1; rslt = calloc(1, bufsize); if (rslt == NULL) { free(avalue); @@ -593,12 +600,13 @@ __format_grouped_double(double value, int *flags, bufend -= right_prec; memcpy(bufend, avalue + avalue_size+padded-right_prec, right_prec); - *--bufend = decimal_point; + bufend -= decimal_point_size; + memcpy(bufend, decimal_point, decimal_point_size); avalue_size -= (right_prec + 1); } if ((*flags & NEED_GROUPING) && - thousands_sep != '\0' && /* XXX: need investigation */ + thousands_sep_size > 0 && /* XXX: need investigation */ *grouping != CHAR_MAX && *grouping > 0) { while (avalue_size > (int)*grouping) { @@ -626,8 +634,9 @@ __format_grouped_double(double value, int *flags, } else { bufend -= avalue_size; memcpy(bufend, avalue+padded, avalue_size); + /* decrease assumed $decimal_point */ if (right_prec == 0) - padded--; /* decrease assumed $decimal_point */ + padded -= decimal_point_size; } /* do padding with pad_char */ Modified: head/lib/libc/tests/stdlib/Makefile ============================================================================== --- head/lib/libc/tests/stdlib/Makefile Wed Dec 19 22:56:31 2018 (r342259) +++ head/lib/libc/tests/stdlib/Makefile Wed Dec 19 22:57:47 2018 (r342260) @@ -6,6 +6,7 @@ ATF_TESTS_C+= heapsort_test ATF_TESTS_C+= mergesort_test ATF_TESTS_C+= qsort_test ATF_TESTS_C+= set_constraint_handler_s_test +ATF_TESTS_C+= strfmon_test ATF_TESTS_C+= tsearch_test .if ${COMPILER_FEATURES:Mc++11} ATF_TESTS_CXX+= cxa_thread_atexit_test Added: head/lib/libc/tests/stdlib/strfmon_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libc/tests/stdlib/strfmon_test.c Wed Dec 19 22:57:47 2018 (r342260) @@ -0,0 +1,71 @@ +/*- + * Copyright (C) 2018 Conrad Meyer <cem@FreeBSD.org> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <locale.h> +#include <monetary.h> +#include <stdio.h> + +#include <atf-c.h> + +ATF_TC_WITHOUT_HEAD(strfmon_locale_thousands); +ATF_TC_BODY(strfmon_locale_thousands, tc) +{ + char actual[40], expected[40]; + struct lconv *lc; + const char *ts; + double n; + + setlocale(LC_MONETARY, "sv_SE.UTF-8"); + + lc = localeconv(); + + ts = lc->mon_thousands_sep; + if (strlen(ts) == 0) + ts = lc->thousands_sep; + + if (strlen(ts) < 2) + atf_tc_skip("multi-byte thousands-separator not found"); + + n = 1234.56; + strfmon(actual, sizeof(actual), "%i", n); + + strcpy(expected, "1"); + strlcat(expected, ts, sizeof(expected)); + strlcat(expected, "234", sizeof(expected)); + + /* We're just testing the thousands separator, not all of strmon. */ + actual[strlen(expected)] = '\0'; + ATF_CHECK_STREQ(expected, actual); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, strfmon_locale_thousands); + return (atf_no_error()); +}
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201812192257.wBJMvlct055323>