summaryrefslogtreecommitdiff
path: root/src/lib/libc/stdlib/gcvt.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/stdlib/gcvt.c')
-rw-r--r--src/lib/libc/stdlib/gcvt.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/lib/libc/stdlib/gcvt.c b/src/lib/libc/stdlib/gcvt.c
new file mode 100644
index 0000000000..d9081a7d39
--- /dev/null
+++ b/src/lib/libc/stdlib/gcvt.c
@@ -0,0 +1,125 @@
1/* $OpenBSD: gcvt.c,v 1.12 2010/09/25 13:19:19 millert Exp $ */
2
3/*
4 * Copyright (c) 2002, 2003, 2006, 2010
5 * Todd C. Miller <Todd.Miller@courtesan.com>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 * Sponsored in part by the Defense Advanced Research Projects
20 * Agency (DARPA) and Air Force Research Laboratory, Air Force
21 * Materiel Command, USAF, under agreement number F39502-99-1-0512.
22 */
23
24#include <locale.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29extern char *__dtoa(double, int, int, int *, int *, char **);
30extern void __freedtoa(char *);
31
32#define DEFPREC 6
33
34char *
35gcvt(double value, int ndigit, char *buf)
36{
37 char *digits, *dst, *src;
38 int i, decpt, sign;
39 struct lconv *lconv;
40
41 lconv = localeconv();
42 if (ndigit <= 0) {
43 /* Match printf(3) behavior. */
44 ndigit = ndigit ? DEFPREC : 1;
45 }
46
47 digits = __dtoa(value, 2, ndigit, &decpt, &sign, NULL);
48 if (digits == NULL)
49 return (NULL);
50 if (decpt == 9999) {
51 /*
52 * Infinity or NaN, convert to inf or nan with sign.
53 * We can't infer buffer size based on ndigit.
54 * We have to assume it is at least 5 chars.
55 */
56 snprintf(buf, 5, "%s%s", sign ? "-" : "",
57 *digits == 'I' ? "inf" : "nan");
58 __freedtoa(digits);
59 return (buf);
60 }
61
62 dst = buf;
63 if (sign)
64 *dst++ = '-';
65
66 /* Match printf(3) behavior for exponential vs. regular fomatting. */
67 if (decpt <= -4 || decpt > ndigit) {
68 /* exponential format (e.g. 1.2345e+13) */
69 if (--decpt < 0) {
70 sign = 1;
71 decpt = -decpt;
72 } else
73 sign = 0;
74 src = digits;
75 *dst++ = *src++;
76 if (*src != '\0') {
77 *dst++ = *lconv->decimal_point;
78 do {
79 *dst++ = *src++;
80 } while (*src != '\0');
81 }
82 *dst++ = 'e';
83 if (sign)
84 *dst++ = '-';
85 else
86 *dst++ = '+';
87 if (decpt < 10) {
88 *dst++ = '0';
89 *dst++ = '0' + decpt;
90 *dst = '\0';
91 } else {
92 /* XXX - optimize */
93 for (sign = decpt, i = 0; (sign /= 10) != 0; i++)
94 continue;
95 dst[i + 1] = '\0';
96 while (decpt != 0) {
97 dst[i--] = '0' + decpt % 10;
98 decpt /= 10;
99 }
100 }
101 } else {
102 /* standard format */
103 for (i = 0, src = digits; i < decpt; i++) {
104 if (*src != '\0')
105 *dst++ = *src++;
106 else
107 *dst++ = '0';
108 }
109 if (*src != '\0') {
110 if (src == digits)
111 *dst++ = '0'; /* zero before decimal point */
112 *dst++ = *lconv->decimal_point;
113 while (decpt < 0) {
114 *dst++ = '0';
115 decpt++;
116 }
117 for (i = decpt; digits[i] != '\0'; i++) {
118 *dst++ = digits[i];
119 }
120 }
121 *dst = '\0';
122 }
123 __freedtoa(digits);
124 return (buf);
125}