1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 #include "lint.h"
30 #include "base_conversion.h"
31 #include <sys/types.h>
32 #include "libc.h"
33 #include <locale.h>
34
35 static void
__k_gconvert(int ndigits,decimal_record * pd,int trailing,char * buf)36 __k_gconvert(int ndigits, decimal_record *pd, int trailing, char *buf)
37 {
38 char *p;
39 int i;
40 char decpt = *(localeconv()->decimal_point);
41
42 p = buf;
43 if (pd->sign)
44 *(p++) = '-';
45 switch (pd->fpclass) {
46 case fp_zero:
47 *(p++) = '0';
48 if (trailing != 0) {
49 *(p++) = decpt;
50 for (i = 0; i < ndigits - 1; i++)
51 *(p++) = '0';
52 }
53 *p++ = 0;
54 break;
55 case fp_subnormal:
56 case fp_normal:
57 if ((pd->exponent > 0) || (pd->exponent < -(ndigits + 3))) {
58 /* E format. */
59 char estring[4];
60 int n;
61
62 *(p++) = pd->ds[0];
63 *(p++) = decpt;
64 for (i = 1; pd->ds[i] != 0; )
65 *(p++) = pd->ds[i++];
66 if (trailing == 0) {
67 /* Remove trailing zeros and . */
68 p--;
69 while (*p == '0')
70 p--;
71 if (*p != decpt)
72 p++;
73 }
74 *(p++) = 'e';
75 n = pd->exponent + i - 1;
76 if (n >= 0)
77 *(p++) = '+';
78 else {
79 *(p++) = '-';
80 n = -n;
81 }
82 __four_digits_quick((unsigned short) n, estring);
83
84 /* Find end of zeros. */
85 for (i = 0; estring[i] == '0'; i++)
86 ;
87
88 if (i > 2)
89 i = 2; /* Guarantee two zeros. */
90 for (; i <= 3; )
91 *(p++) = estring[i++]; /* Copy exp digits. */
92 } else { /* F format. */
93 if (pd->exponent >= (1 - ndigits)) { /* x.xxx */
94 for (i = 0; i < (ndigits + pd->exponent); )
95 *(p++) = pd->ds[i++];
96 *(p++) = decpt;
97 if (pd->ds[i] != 0) {
98 /* More follows point. */
99 for (; i < ndigits; )
100 *(p++) = pd->ds[i++];
101 }
102 } else { /* 0.00xxxx */
103 *(p++) = '0';
104 *(p++) = decpt;
105 for (i = 0; i < -(pd->exponent + ndigits); i++)
106 *(p++) = '0';
107 for (i = 0; pd->ds[i] != 0; )
108 *(p++) = pd->ds[i++];
109 }
110 if (trailing == 0) {
111 /* Remove trailing zeros and point. */
112 p--;
113 while (*p == '0')
114 p--;
115 if (*p != decpt)
116 p++;
117 }
118 }
119 *(p++) = 0;
120 break;
121 default:
122 __infnanstring(pd->fpclass, ndigits, p);
123 break;
124 }
125 }
126
127 char *
gconvert(double number,int ndigits,int trailing,char * buf)128 gconvert(double number, int ndigits, int trailing, char *buf)
129 {
130 decimal_mode dm;
131 decimal_record dr;
132 fp_exception_field_type fef;
133
134 #if defined(__sparc)
135 dm.rd = _QgetRD();
136 #elif defined(__i386) || defined(__amd64)
137 dm.rd = __xgetRD();
138 #else
139 #error Unknown architecture
140 #endif
141 dm.df = floating_form;
142 if (ndigits < 0)
143 ndigits = 6;
144 else if (ndigits == 0)
145 ndigits = 1;
146 else if (ndigits >= DECIMAL_STRING_LENGTH)
147 ndigits = DECIMAL_STRING_LENGTH - 1;
148 dm.ndigits = ndigits;
149 double_to_decimal(&number, &dm, &dr, &fef);
150 __k_gconvert(ndigits, &dr, trailing, buf);
151 return (buf);
152 }
153
154 char *
sgconvert(single * number,int ndigits,int trailing,char * buf)155 sgconvert(single *number, int ndigits, int trailing, char *buf)
156 {
157 decimal_mode dm;
158 decimal_record dr;
159 fp_exception_field_type fef;
160
161 #if defined(__sparc)
162 dm.rd = _QgetRD();
163 #elif defined(__i386) || defined(__amd64)
164 dm.rd = __xgetRD();
165 #else
166 #error Unknown architecture
167 #endif
168 dm.df = floating_form;
169 if (ndigits < 0)
170 ndigits = 6;
171 else if (ndigits == 0)
172 ndigits = 1;
173 else if (ndigits >= DECIMAL_STRING_LENGTH)
174 ndigits = DECIMAL_STRING_LENGTH - 1;
175 dm.ndigits = ndigits;
176 single_to_decimal(number, &dm, &dr, &fef);
177 __k_gconvert(ndigits, &dr, trailing, buf);
178 return (buf);
179 }
180
181 char *
qgconvert(quadruple * number,int ndigits,int trailing,char * buf)182 qgconvert(quadruple *number, int ndigits, int trailing, char *buf)
183 {
184 decimal_mode dm;
185 decimal_record dr;
186 fp_exception_field_type fef;
187
188 #if defined(__sparc)
189 dm.rd = _QgetRD();
190 #elif defined(__i386) || defined(__amd64)
191 dm.rd = __xgetRD();
192 #else
193 #error Unknown architecture
194 #endif
195 dm.df = floating_form;
196 if (ndigits < 0)
197 ndigits = 6;
198 else if (ndigits == 0)
199 ndigits = 1;
200 else if (ndigits >= DECIMAL_STRING_LENGTH)
201 ndigits = DECIMAL_STRING_LENGTH - 1;
202 dm.ndigits = ndigits;
203 #if defined(__sparc)
204 quadruple_to_decimal(number, &dm, &dr, &fef);
205 #elif defined(__i386) || defined(__amd64)
206 extended_to_decimal((extended *)number, &dm, &dr, &fef);
207 #else
208 #error Unknown architecture
209 #endif
210 __k_gconvert(ndigits, &dr, trailing, buf);
211 return (buf);
212 }
213