From owner-freebsd-hackers Sat Apr 20 7:21:20 2002 Delivered-To: freebsd-hackers@freebsd.org Received: from columbus.cris.net (columbus.cris.net [212.110.128.65]) by hub.freebsd.org (Postfix) with ESMTP id E9F4137B405 for ; Sat, 20 Apr 2002 07:20:57 -0700 (PDT) Received: from ark.cris.net (root@ark.cris.net [212.110.128.68]) by columbus.cris.net (8.9.3/8.9.3) with ESMTP id RAA99377 for ; Sat, 20 Apr 2002 17:20:53 +0300 (EEST) Received: (from phantom@localhost) by ark.cris.net (8.11.1/8.11.1) id g3KEKrR05092; Sat, 20 Apr 2002 17:20:53 +0300 (EEST) Date: Sat, 20 Apr 2002 17:20:53 +0300 From: Alexey Zelkin To: hackers@FreeBSD.org Subject: CFR: [Fwd: generalized "\'" flag support for vfprintf() (for both decimal and float numbers)] Message-ID: <20020420172053.A2918@ark.cris.net> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Mailer: Mutt 1.0i X-Operating-System: FreeBSD 3.5-STABLE i386 Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG hi, Constructive comments are welcome! ----- Forwarded message from Alexey Zelkin ----- From: Alexey Zelkin To: standards@freebsd.org Subject: generalized "\'" flag support for vfprintf() (for both decimal and float numbers) hi, Heh, just finished it and it passed my basic tests. Tommorow I'll go with its cleanup, but anyway it would be interesting to listen opinions on the way how it's done. Index: vfprintf.c =================================================================== RCS file: /home/cvs/freebsd/src/lib/libc/stdio/vfprintf.c,v retrieving revision 1.36 diff -u -r1.36 vfprintf.c --- vfprintf.c 17 Dec 2001 15:11:29 -0000 1.36 +++ vfprintf.c 10 Feb 2002 18:04:30 -0000 @@ -114,12 +114,11 @@ static int __sprint __P((FILE *, struct __suio *)); static int __sbprintf __P((FILE *, const char *, va_list)) __printflike(2, 0); -static char *__ujtoa __P((uintmax_t, char *, int, int, char *, int, - char, const char *)); -static char *__ultoa __P((u_long, char *, int, int, char *, int, - char, const char *)); +static char *__ujtoa __P((uintmax_t, char *, int, int, char *)); +static char *__ultoa __P((u_long, char *, int, int, char *)); static void __find_arguments __P((const char *, va_list, union arg **)); static void __grow_type_table __P((int, enum typeid **, int *)); +static int __do_grouping __P((char *buf, char **cp, int size, int safety)); /* * Flush out all the vectors defined by the given uio, @@ -186,12 +185,10 @@ * use the given digits. */ static char * -__ultoa(u_long val, char *endp, int base, int octzero, char *xdigs, - int needgrp, char thousep, const char *grp) +__ultoa(u_long val, char *endp, int base, int octzero, char *xdigs) { register char *cp = endp; register long sval; - int ndig; /* * Handle the three cases separately, in the hope of getting @@ -203,7 +200,6 @@ *--cp = to_char(val); return (cp); } - ndig = 0; /* * On many machines, unsigned arithmetic is harder than * signed arithmetic, so we do at most one unsigned mod and @@ -212,29 +208,11 @@ */ if (val > LONG_MAX) { *--cp = to_char(val % 10); - ndig++; sval = val / 10; } else sval = val; do { *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && ndig == *grp && *grp != CHAR_MAX - && sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp+1) != '\0') - grp++; - } sval /= 10; } while (sval != 0); break; @@ -263,50 +241,28 @@ /* Identical to __ultoa, but for intmax_t. */ static char * -__ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs, - int needgrp, char thousep, const char *grp) +__ujtoa(uintmax_t val, char *endp, int base, int octzero, char *xdigs) { char *cp = endp; intmax_t sval; - int ndig; /* quick test for small values; __ultoa is typically much faster */ /* (perhaps instead we should run until small, then call __ultoa?) */ if (val <= ULONG_MAX) - return (__ultoa((u_long)val, endp, base, octzero, xdigs, - needgrp, thousep, grp)); + return (__ultoa((u_long)val, endp, base, octzero, xdigs)); switch (base) { case 10: if (val < 10) { *--cp = to_char(val % 10); return (cp); } - ndig = 0; if (val > INTMAX_MAX) { *--cp = to_char(val % 10); - ndig++; sval = val / 10; } else sval = val; do { *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && *grp != CHAR_MAX && ndig == *grp - && sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp+1) != '\0') - grp++; - } sval /= 10; } while (sval != 0); break; @@ -400,8 +356,6 @@ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format (%.3d), or -1 */ char sign; /* sign prefix (' ', '+', '-', or \0) */ - char thousands_sep; /* locale specific thousands separator */ - const char *grouping; /* locale specific numeric grouping rules */ #ifdef FLOATING_POINT char *decimal_point; /* locale specific decimal point */ char softsign; /* temporary negative sign for floats */ @@ -532,8 +486,6 @@ } - thousands_sep = '\0'; - grouping = NULL; #ifdef FLOATING_POINT dtoaresult = NULL; decimal_point = localeconv()->decimal_point; @@ -614,8 +566,6 @@ goto rflag; case '\'': flags |= GROUPING; - thousands_sep = *(localeconv()->thousands_sep); - grouping = localeconv()->grouping; goto rflag; case '.': if ((ch = *fmt++) == '*') { @@ -750,6 +700,7 @@ else cp = "inf"; size = 3; + flags &= ~GROUPING; break; } if (isnan(_double)) { @@ -758,6 +709,7 @@ else cp = "nan"; size = 3; + flags &= ~GROUPING; break; } flags |= FPT; @@ -912,15 +864,11 @@ if (flags & INTMAX_SIZE) { if (ujval != 0 || prec != 0) cp = __ujtoa(ujval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); + flags & ALT, xdigs); } else { if (ulval != 0 || prec != 0) cp = __ultoa(ulval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); + flags & ALT, xdigs); } size = buf + BUF - cp; break; @@ -981,9 +929,18 @@ /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); +#define DOGRP(PTR, SIZE, SAFETY) { \ + if (flags & GROUPING) { \ + n2 = __do_grouping(buf, &PTR, SIZE, SAFETY); \ + SIZE += n2; \ + realsz += n2; \ + } \ +} + /* the string or number proper */ #ifdef FLOATING_POINT if ((flags & FPT) == 0) { + DOGRP(cp, size, 0); PRINT(cp, size); } else { /* glue together f_p fragments */ if (ch >= 'f') { /* 'f' or 'g' */ @@ -1000,11 +957,13 @@ PAD(-expt, zeroes); PRINT(cp, ndig); } else if (expt >= ndig) { + DOGRP(cp, ndig, 0); PRINT(cp, ndig); PAD(expt - ndig, zeroes); if (flags & ALT) PRINT(decimal_point, 1); } else { + DOGRP(cp, expt, ndig-expt); PRINT(cp, expt); cp += expt; PRINT(decimal_point, 1); @@ -1026,6 +985,7 @@ } } #else + DOGRP(cp, size, 0); PRINT(cp, size); #endif /* left-adjusting padding (always blank) */ @@ -1387,6 +1347,64 @@ *typetable = newtable; *tablesize = newsize; +} + +/*- + * Reformat buffer to include grouping characters + * + * params: + * buf -- pointer to begining of the buffer + * cp -- address of pointer to actual adta + * size -- amount of characters to group + * safety -- amount of characters after (*cp+size) to preserve + * (post-decimal part of FPT number) + */ +static int +__do_grouping(char *buf, char **cp, int size, int safety) { + + char thousands_sep; + char *grouping; + char *ptr, *tp; + int ndig, proceed, result, n; + + grouping = localeconv()->grouping; + if (*grouping == CHAR_MAX) + return (0); + + thousands_sep = *(localeconv()->thousands_sep); + if (thousands_sep == '\0') + return (0); + + result = 0; + + /* assume that data is at the begin of buffer */ + /* NOTE: strings can't overlap since actual value can fill only 1/3 part of buffer */ + if (buf != *cp) { + memmove(buf, *cp, size+safety); + *cp = buf; + } + + ndig = 0; + proceed = 0; + ptr = (*cp + size); + while (proceed < size) { + if (*grouping <= ndig) { + memmove(ptr+1, ptr, proceed+result+safety); + *ptr = thousands_sep; + result++; + if (*(grouping+1) != '\0') + grouping++; + if (*grouping == CHAR_MAX) /* no more grouping */ + break; + ndig = 0; + } else { + ndig++; + proceed++; + ptr--; + } + } + + return (result); } ----- End forwarded message ----- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message