--- strfmon.c.orig 2003-05-20 15:23:25.000000000 -0700 +++ strfmon.c 2005-04-27 23:34:08.000000000 -0700 @@ -28,6 +28,8 @@ #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/lib/libc/stdlib/strfmon.c,v 1.14 2003/03/20 08:18:55 ache Exp $"); +#include "xlocale_private.h" + #include <sys/types.h> #include <ctype.h> #include <errno.h> @@ -61,9 +63,9 @@ PRINT(*tmps++); \ } while (0) -#define GET_NUMBER(VAR) do { \ +#define GET_NUMBER(VAR,LOC) do { \ VAR = 0; \ - while (isdigit((unsigned char)*fmt)) { \ + while (isdigit_l((unsigned char)*fmt, (LOC))) { \ VAR *= 10; \ VAR += *fmt - '0'; \ fmt++; \ @@ -83,15 +85,14 @@ groups++; \ } while (0) -static void __setup_vars(int, char *, char *, char *, char **); -static int __calc_left_pad(int, char *); -static char *__format_grouped_double(double, int *, int, int, int); - -ssize_t -strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, - ...) +static void __setup_vars(int, char *, char *, char *, char **, struct lconv *); +static int __calc_left_pad(int, char *, struct lconv *); +static char *__format_grouped_double(double, int *, int, int, int, struct lconv *, locale_t); + +static ssize_t +_strfmon(char * __restrict s, size_t maxsize, locale_t loc, + const char * __restrict format, va_list ap) { - va_list ap; char *dst; /* output destination pointer */ const char *fmt; /* current format poistion pointer */ struct lconv *lc; /* pointer to lconv structure */ @@ -115,9 +116,7 @@ char *tmpptr; /* temporary vars */ int sverrno; - va_start(ap, format); - - lc = localeconv(); + lc = localeconv_l(loc); dst = s; fmt = format; asciivalue = NULL; @@ -181,8 +180,8 @@ } /* field Width */ - if (isdigit((unsigned char)*fmt)) { - GET_NUMBER(width); + if (isdigit_l((unsigned char)*fmt, loc)) { + GET_NUMBER(width, loc); /* Do we have enough space to put number with * required width ? */ @@ -192,16 +191,16 @@ /* Left precision */ if (*fmt == '#') { - if (!isdigit((unsigned char)*++fmt)) + if (!isdigit_l((unsigned char)*++fmt, loc)) goto format_error; - GET_NUMBER(left_prec); + GET_NUMBER(left_prec, loc); } /* Right precision */ if (*fmt == '.') { - if (!isdigit((unsigned char)*++fmt)) + if (!isdigit_l((unsigned char)*++fmt, loc)) goto format_error; - GET_NUMBER(right_prec); + GET_NUMBER(right_prec, loc); } /* Conversion Characters */ @@ -219,8 +218,10 @@ if (flags & USE_INTL_CURRENCY) { currency_symbol = strdup(lc->int_curr_symbol); - if (currency_symbol != NULL) + if (currency_symbol != NULL) { space_char = *(currency_symbol+3); + currency_symbol[3] = '\0'; + } } else currency_symbol = strdup(lc->currency_symbol); @@ -239,21 +240,21 @@ /* fill left_prec with amount of padding chars */ if (left_prec >= 0) { pad_size = __calc_left_pad((flags ^ IS_NEGATIVE), - currency_symbol) - - __calc_left_pad(flags, currency_symbol); + currency_symbol, lc) - + __calc_left_pad(flags, currency_symbol, lc); if (pad_size < 0) pad_size = 0; } asciivalue = __format_grouped_double(value, &flags, - left_prec, right_prec, pad_char); + left_prec, right_prec, pad_char, lc, loc); if (asciivalue == NULL) goto end_error; /* errno already set */ /* to ENOMEM by malloc() */ /* set some variables for later use */ __setup_vars(flags, &cs_precedes, &sep_by_space, - &sign_posn, &signstr); + &sign_posn, &signstr, lc); /* * Description of some LC_MONETARY's values: @@ -313,8 +314,11 @@ } else if (sep_by_space == 1) PRINT(space_char); } - } else if (sign_posn == 1) + } else if (sign_posn == 1) { PRINTS(signstr); + if (sep_by_space == 2) + PRINT(' '); + } PRINTS(asciivalue); @@ -348,8 +352,12 @@ PRINTS(signstr); } - if (sign_posn == 0 && (flags & IS_NEGATIVE)) - PRINT(')'); + if (sign_posn == 0) { + if (flags & IS_NEGATIVE) + PRINT(')'); + else if (left_prec >= 0) + PRINT(' '); + } if (dst - tmpptr < width) { if (flags & LEFT_JUSTIFY) { @@ -366,7 +374,6 @@ } PRINT('\0'); - va_end(ap); free(asciivalue); free(currency_symbol); return (dst - s - 1); /* return size of put data except trailing '\0' */ @@ -385,15 +392,12 @@ if (currency_symbol != NULL) free(currency_symbol); errno = sverrno; - va_end(ap); return (-1); } static void __setup_vars(int flags, char *cs_precedes, char *sep_by_space, - char *sign_posn, char **signstr) { - - struct lconv *lc = localeconv(); + char *sign_posn, char **signstr, struct lconv *lc) { if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) { *cs_precedes = lc->int_n_cs_precedes; @@ -429,12 +433,12 @@ } static int -__calc_left_pad(int flags, char *cur_symb) { +__calc_left_pad(int flags, char *cur_symb, struct lconv *lc) { char cs_precedes, sep_by_space, sign_posn, *signstr; int left_chars = 0; - __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr); + __setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn, &signstr, lc); if (cs_precedes != 0) { left_chars += strlen(cur_symb); @@ -443,6 +447,10 @@ } switch (sign_posn) { + case 0: + if (flags & IS_NEGATIVE) + left_chars++; + break; case 1: left_chars += strlen(signstr); break; @@ -478,9 +486,11 @@ } /* convert double to ASCII */ +__private_extern__ const char *__fix_nogrouping(const char *); + static char * __format_grouped_double(double value, int *flags, - int left_prec, int right_prec, int pad_char) { + int left_prec, int right_prec, int pad_char, struct lconv *lc, locale_t loc) { char *rslt; char *avalue; @@ -492,14 +502,13 @@ int padded; - struct lconv *lc = localeconv(); char *grouping; char decimal_point; char thousands_sep; int groups = 0; - grouping = lc->mon_grouping; + grouping = __fix_nogrouping(lc->mon_grouping); decimal_point = *lc->mon_decimal_point; if (decimal_point == '\0') decimal_point = *lc->decimal_point; @@ -526,9 +535,9 @@ left_prec += get_groups(left_prec, grouping); /* convert to string */ - snprintf(fmt, sizeof(fmt), "%%%d.%df", left_prec + right_prec + 1, + snprintf_l(fmt, sizeof(fmt), loc, "%%%d.%df", left_prec + right_prec + 1, right_prec); - avalue_size = asprintf(&avalue, fmt, value); + avalue_size = asprintf_l(&avalue, loc, fmt, value); if (avalue_size < 0) return (NULL); @@ -601,3 +610,30 @@ free(avalue); return (rslt); } + +ssize_t +strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, + ...) +{ + ssize_t ret; + va_list ap; + + va_start(ap, format); + ret = _strfmon(s, maxsize, __current_locale(), format, ap); + va_end(ap); + return ret; +} + +ssize_t +strfmon_l(char * __restrict s, size_t maxsize, locale_t loc, + const char * __restrict format, ...) +{ + ssize_t ret; + va_list ap; + + NORMALIZE_LOCALE(loc); + va_start(ap, format); + ret = _strfmon(s, maxsize, loc, format, ap); + va_end(ap); + return ret; +}