xref: /illumos-gate/usr/src/lib/libc/port/fp/gconvert.c (revision 7257d1b4d25bfac0c802847390e98a464fd787ac)
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
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 *
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 *
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 *
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