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