From owner-svn-src-head@freebsd.org Wed Dec 19 22:57:48 2018 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id C9429134C581; Wed, 19 Dec 2018 22:57:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 5792975603; Wed, 19 Dec 2018 22:57:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4CB501C8FD; Wed, 19 Dec 2018 22:57:48 +0000 (UTC) (envelope-from cem@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id wBJMvmrK055325; Wed, 19 Dec 2018 22:57:48 GMT (envelope-from cem@FreeBSD.org) Received: (from cem@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id wBJMvlct055323; Wed, 19 Dec 2018 22:57:47 GMT (envelope-from cem@FreeBSD.org) Message-Id: <201812192257.wBJMvlct055323@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: cem set sender to cem@FreeBSD.org using -f From: Conrad Meyer Date: Wed, 19 Dec 2018 22:57:47 +0000 (UTC) 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 X-SVN-Group: head X-SVN-Commit-Author: cem X-SVN-Commit-Paths: in head/lib/libc: stdlib tests/stdlib X-SVN-Commit-Revision: 342260 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 5792975603 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_LONG(-1.00)[-0.998,0]; NEURAL_HAM_SHORT(-0.96)[-0.961,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 19 Dec 2018 22:57:49 -0000 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 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +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()); +}