diff options
author | millert <> | 2010-09-25 13:19:19 +0000 |
---|---|---|
committer | millert <> | 2010-09-25 13:19:19 +0000 |
commit | 424deb351931af3fd885740bc351436321fad2f9 (patch) | |
tree | 3cf23e4a041ea0438257fe1b9ddf7281e18f5273 /src | |
parent | ca3efbcfa52175f6883523a4782ce280dd592054 (diff) | |
download | openbsd-424deb351931af3fd885740bc351436321fad2f9.tar.gz openbsd-424deb351931af3fd885740bc351436321fad2f9.tar.bz2 openbsd-424deb351931af3fd885740bc351436321fad2f9.zip |
Make gcvt() better match printf("%g") behavior, it now passes regress.
OK deraadt@
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libc/stdlib/gcvt.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/src/lib/libc/stdlib/gcvt.c b/src/lib/libc/stdlib/gcvt.c index e5488d912d..d9081a7d39 100644 --- a/src/lib/libc/stdlib/gcvt.c +++ b/src/lib/libc/stdlib/gcvt.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* $OpenBSD: gcvt.c,v 1.11 2009/10/16 12:15:03 martynas Exp $ */ | 1 | /* $OpenBSD: gcvt.c,v 1.12 2010/09/25 13:19:19 millert Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2002, 2003, 2006 Todd C. Miller <Todd.Miller@courtesan.com> | 4 | * Copyright (c) 2002, 2003, 2006, 2010 |
5 | * Todd C. Miller <Todd.Miller@courtesan.com> | ||
5 | * | 6 | * |
6 | * Permission to use, copy, modify, and distribute this software for any | 7 | * Permission to use, copy, modify, and distribute this software for any |
7 | * purpose with or without fee is hereby granted, provided that the above | 8 | * purpose with or without fee is hereby granted, provided that the above |
@@ -28,6 +29,8 @@ | |||
28 | extern char *__dtoa(double, int, int, int *, int *, char **); | 29 | extern char *__dtoa(double, int, int, int *, int *, char **); |
29 | extern void __freedtoa(char *); | 30 | extern void __freedtoa(char *); |
30 | 31 | ||
32 | #define DEFPREC 6 | ||
33 | |||
31 | char * | 34 | char * |
32 | gcvt(double value, int ndigit, char *buf) | 35 | gcvt(double value, int ndigit, char *buf) |
33 | { | 36 | { |
@@ -36,9 +39,9 @@ gcvt(double value, int ndigit, char *buf) | |||
36 | struct lconv *lconv; | 39 | struct lconv *lconv; |
37 | 40 | ||
38 | lconv = localeconv(); | 41 | lconv = localeconv(); |
39 | if (ndigit == 0) { | 42 | if (ndigit <= 0) { |
40 | buf[0] = '\0'; | 43 | /* Match printf(3) behavior. */ |
41 | return (buf); | 44 | ndigit = ndigit ? DEFPREC : 1; |
42 | } | 45 | } |
43 | 46 | ||
44 | digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL); | 47 | digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL); |
@@ -47,9 +50,10 @@ gcvt(double value, int ndigit, char *buf) | |||
47 | if (decpt == 9999) { | 50 | if (decpt == 9999) { |
48 | /* | 51 | /* |
49 | * Infinity or NaN, convert to inf or nan with sign. | 52 | * Infinity or NaN, convert to inf or nan with sign. |
50 | * We assume the buffer is at least ndigit long. | 53 | * We can't infer buffer size based on ndigit. |
54 | * We have to assume it is at least 5 chars. | ||
51 | */ | 55 | */ |
52 | snprintf(buf, ndigit + 1, "%s%s", sign ? "-" : "", | 56 | snprintf(buf, 5, "%s%s", sign ? "-" : "", |
53 | *digits == 'I' ? "inf" : "nan"); | 57 | *digits == 'I' ? "inf" : "nan"); |
54 | __freedtoa(digits); | 58 | __freedtoa(digits); |
55 | return (buf); | 59 | return (buf); |
@@ -59,7 +63,8 @@ gcvt(double value, int ndigit, char *buf) | |||
59 | if (sign) | 63 | if (sign) |
60 | *dst++ = '-'; | 64 | *dst++ = '-'; |
61 | 65 | ||
62 | if (decpt < 0 || decpt > ndigit) { | 66 | /* Match printf(3) behavior for exponential vs. regular fomatting. */ |
67 | if (decpt <= -4 || decpt > ndigit) { | ||
63 | /* exponential format (e.g. 1.2345e+13) */ | 68 | /* exponential format (e.g. 1.2345e+13) */ |
64 | if (--decpt < 0) { | 69 | if (--decpt < 0) { |
65 | sign = 1; | 70 | sign = 1; |
@@ -68,9 +73,12 @@ gcvt(double value, int ndigit, char *buf) | |||
68 | sign = 0; | 73 | sign = 0; |
69 | src = digits; | 74 | src = digits; |
70 | *dst++ = *src++; | 75 | *dst++ = *src++; |
71 | *dst++ = *lconv->decimal_point; | 76 | if (*src != '\0') { |
72 | while (*src != '\0') | 77 | *dst++ = *lconv->decimal_point; |
73 | *dst++ = *src++; | 78 | do { |
79 | *dst++ = *src++; | ||
80 | } while (*src != '\0'); | ||
81 | } | ||
74 | *dst++ = 'e'; | 82 | *dst++ = 'e'; |
75 | if (sign) | 83 | if (sign) |
76 | *dst++ = '-'; | 84 | *dst++ = '-'; |
@@ -102,6 +110,10 @@ gcvt(double value, int ndigit, char *buf) | |||
102 | if (src == digits) | 110 | if (src == digits) |
103 | *dst++ = '0'; /* zero before decimal point */ | 111 | *dst++ = '0'; /* zero before decimal point */ |
104 | *dst++ = *lconv->decimal_point; | 112 | *dst++ = *lconv->decimal_point; |
113 | while (decpt < 0) { | ||
114 | *dst++ = '0'; | ||
115 | decpt++; | ||
116 | } | ||
105 | for (i = decpt; digits[i] != '\0'; i++) { | 117 | for (i = decpt; digits[i] != '\0'; i++) { |
106 | *dst++ = digits[i]; | 118 | *dst++ = digits[i]; |
107 | } | 119 | } |