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 #include "lint.h"
28 #include "base_conversion.h"
29 #include <sys/types.h>
30 #include "libc.h"
31
32 char *
fconvert(double arg,int ndigits,int * decpt,int * sign,char * buf)33 fconvert(double arg, int ndigits, int *decpt, int *sign, char *buf)
34 {
35 decimal_mode dm;
36 decimal_record dr;
37 fp_exception_field_type ef;
38 int i;
39
40 #if defined(__sparc)
41 dm.rd = _QgetRD();
42 #elif defined(__i386) || defined(__amd64)
43 dm.rd = __xgetRD();
44 #else
45 #error Unknown architecture
46 #endif
47 dm.df = fixed_form; /* F format. */
48 if (ndigits <= -DECIMAL_STRING_LENGTH)
49 ndigits = -DECIMAL_STRING_LENGTH + 1;
50 else if (ndigits >= DECIMAL_STRING_LENGTH)
51 ndigits = DECIMAL_STRING_LENGTH - 1;
52 dm.ndigits = ndigits; /* Number of digits after point. */
53 double_to_decimal(&arg, &dm, &dr, &ef);
54 *sign = dr.sign;
55 switch (dr.fpclass) {
56 case fp_normal:
57 case fp_subnormal:
58 *decpt = dr.exponent + dr.ndigits;
59 for (i = 0; i < dr.ndigits; i++)
60 buf[i] = dr.ds[i];
61 /*
62 * Pad with zeroes if we didn't get all the digits
63 * we asked for.
64 */
65 if (ndigits > 0 && dr.exponent > -ndigits) {
66 while (i < dr.ndigits + dr.exponent + ndigits)
67 buf[i++] = '0';
68 }
69 buf[i] = 0;
70 break;
71 case fp_zero:
72 *decpt = 0;
73 buf[0] = '0';
74 for (i = 1; i < ndigits; i++)
75 buf[i] = '0';
76 buf[i] = 0;
77 break;
78 default:
79 *decpt = 0;
80 __infnanstring(dr.fpclass, ndigits, buf);
81 break;
82 }
83 return (buf);
84 }
85
86 char *
sfconvert(single * arg,int ndigits,int * decpt,int * sign,char * buf)87 sfconvert(single *arg, int ndigits, int *decpt, int *sign, char *buf)
88 {
89 decimal_mode dm;
90 decimal_record dr;
91 fp_exception_field_type ef;
92 int i;
93
94 #if defined(__sparc)
95 dm.rd = _QgetRD();
96 #elif defined(__i386) || defined(__amd64)
97 dm.rd = __xgetRD();
98 #else
99 #error Unknown architecture
100 #endif
101 dm.df = fixed_form; /* F format. */
102 if (ndigits <= -DECIMAL_STRING_LENGTH)
103 ndigits = -DECIMAL_STRING_LENGTH + 1;
104 else if (ndigits >= DECIMAL_STRING_LENGTH)
105 ndigits = DECIMAL_STRING_LENGTH - 1;
106 dm.ndigits = ndigits; /* Number of digits after point. */
107 single_to_decimal(arg, &dm, &dr, &ef);
108 *sign = dr.sign;
109 switch (dr.fpclass) {
110 case fp_normal:
111 case fp_subnormal:
112 *decpt = dr.exponent + dr.ndigits;
113 for (i = 0; i < dr.ndigits; i++)
114 buf[i] = dr.ds[i];
115 /*
116 * Pad with zeroes if we didn't get all the digits
117 * we asked for.
118 */
119 if (ndigits > 0 && dr.exponent > -ndigits) {
120 while (i < dr.ndigits + dr.exponent + ndigits)
121 buf[i++] = '0';
122 }
123 buf[i] = 0;
124 break;
125 case fp_zero:
126 *decpt = 0;
127 buf[0] = '0';
128 for (i = 1; i < ndigits; i++)
129 buf[i] = '0';
130 buf[i] = 0;
131 break;
132 default:
133 *decpt = 0;
134 __infnanstring(dr.fpclass, ndigits, buf);
135 break;
136 }
137 return (buf);
138 }
139
140 char *
qfconvert(quadruple * arg,int ndigits,int * decpt,int * sign,char * buf)141 qfconvert(quadruple *arg, int ndigits, int *decpt, int *sign, char *buf)
142 {
143 decimal_mode dm;
144 decimal_record dr;
145 fp_exception_field_type ef;
146 int i;
147
148 #if defined(__sparc)
149 dm.rd = _QgetRD();
150 #elif defined(__i386) || defined(__amd64)
151 dm.rd = __xgetRD();
152 #else
153 #error Unknown architecture
154 #endif
155 dm.df = fixed_form; /* F format. */
156 if (ndigits <= -DECIMAL_STRING_LENGTH)
157 ndigits = -DECIMAL_STRING_LENGTH + 1;
158 else if (ndigits >= DECIMAL_STRING_LENGTH)
159 ndigits = DECIMAL_STRING_LENGTH - 1;
160 dm.ndigits = ndigits; /* Number of digits after point. */
161 #if defined(__sparc)
162 quadruple_to_decimal(arg, &dm, &dr, &ef);
163 #elif defined(__i386) || defined(__amd64)
164 extended_to_decimal((extended *)arg, &dm, &dr, &ef);
165 #else
166 #error Unknown architecture
167 #endif
168 *sign = dr.sign;
169 if (ef & (1 << fp_overflow)) {
170 /*
171 * *_to_decimal raises overflow whenever dr.ds isn't large
172 * enough to hold all the digits requested. For float and
173 * double, this can only happen when the requested format
174 * would require trailing zeroes, in which case fconvert
175 * and sfconvert just add them. For long double, the arg-
176 * ument might be large enough that even the nonzero digits
177 * would overflow dr.ds, so we punt instead. (We could
178 * distinguish these two cases, but it doesn't seem worth
179 * changing things now, particularly since no real appli-
180 * cation prints floating point numbers to 500 digits.)
181 */
182 *decpt = 0;
183 buf[0] = 0;
184 return (buf);
185 }
186 switch (dr.fpclass) {
187 case fp_normal:
188 case fp_subnormal:
189 *decpt = dr.exponent + dr.ndigits;
190 for (i = 0; i < dr.ndigits; i++)
191 buf[i] = dr.ds[i];
192 buf[i] = 0;
193 break;
194 case fp_zero:
195 *decpt = 0;
196 buf[0] = '0';
197 for (i = 1; i < ndigits; i++)
198 buf[i] = '0';
199 buf[i] = 0;
200 break;
201 default:
202 *decpt = 0;
203 __infnanstring(dr.fpclass, ndigits, buf);
204 break;
205 }
206 return (buf);
207 }
208