xref: /illumos-gate/usr/src/lib/libc/port/fp/gconvert.c (revision 1da57d55)
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 #include <locale.h>
32 
33 static void
__k_gconvert(int ndigits,decimal_record * pd,int trailing,char * buf)34 __k_gconvert(int ndigits, decimal_record *pd, int trailing, char *buf)
35 {
36 	char	*p;
37 	int	i;
38 	char	decpt = *(localeconv()->decimal_point);
39 
40 	p = buf;
41 	if (pd->sign)
42 		*(p++) = '-';
43 	switch (pd->fpclass) {
44 	case fp_zero:
45 		*(p++) = '0';
46 		if (trailing != 0) {
47 			*(p++) = decpt;
48 			for (i = 0; i < ndigits - 1; i++)
49 				*(p++) = '0';
50 		}
51 		*p++ = 0;
52 		break;
53 	case fp_subnormal:
54 	case fp_normal:
55 		if ((pd->exponent > 0) || (pd->exponent < -(ndigits + 3))) {
56 			/* E format. */
57 			char	estring[4];
58 			int	n;
59 
60 			*(p++) = pd->ds[0];
61 			*(p++) = decpt;
62 			for (i = 1; pd->ds[i] != 0; )
63 				*(p++) = pd->ds[i++];
64 			if (trailing == 0) {
65 				/* Remove trailing zeros and . */
66 				p--;
67 				while (*p == '0')
68 					p--;
69 				if (*p != decpt)
70 					p++;
71 			}
72 			*(p++) = 'e';
73 			n = pd->exponent + i - 1;
74 			if (n >= 0)
75 				*(p++) = '+';
76 			else {
77 				*(p++) = '-';
78 				n = -n;
79 			}
80 			__four_digits_quick((unsigned short) n, estring);
81 
82 				/* Find end of zeros. */
83 			for (i = 0; estring[i] == '0'; i++)
84 				;
85 
86 			if (i > 2)
87 				i = 2;	/* Guarantee two zeros. */
88 			for (; i <= 3; )
89 				*(p++) = estring[i++];	/* Copy exp digits. */
90 		} else {	/* F format. */
91 			if (pd->exponent >= (1 - ndigits)) {	/* x.xxx */
92 				for (i = 0; i < (ndigits + pd->exponent); )
93 					*(p++) = pd->ds[i++];
94 				*(p++) = decpt;
95 				if (pd->ds[i] != 0) {
96 					/* More follows point. */
97 					for (; i < ndigits; )
98 						*(p++) = pd->ds[i++];
99 				}
100 			} else { /* 0.00xxxx */
101 				*(p++) = '0';
102 				*(p++) = decpt;
103 				for (i = 0; i < -(pd->exponent + ndigits); i++)
104 					*(p++) = '0';
105 				for (i = 0; pd->ds[i] != 0; )
106 					*(p++) = pd->ds[i++];
107 			}
108 			if (trailing == 0) {
109 				/* Remove trailing zeros and point. */
110 				p--;
111 				while (*p == '0')
112 					p--;
113 				if (*p != decpt)
114 					p++;
115 			}
116 		}
117 		*(p++) = 0;
118 		break;
119 	default:
120 		__infnanstring(pd->fpclass, ndigits, p);
121 		break;
122 	}
123 }
124 
125 char *
gconvert(double number,int ndigits,int trailing,char * buf)126 gconvert(double number, int ndigits, int trailing, char *buf)
127 {
128 	decimal_mode    dm;
129 	decimal_record  dr;
130 	fp_exception_field_type fef;
131 
132 #if defined(__sparc)
133 	dm.rd = _QgetRD();
134 #elif defined(__i386) || defined(__amd64)
135 	dm.rd = __xgetRD();
136 #else
137 #error Unknown architecture
138 #endif
139 	dm.df = floating_form;
140 	if (ndigits < 0)
141 		ndigits = 6;
142 	else if (ndigits == 0)
143 		ndigits = 1;
144 	else if (ndigits >= DECIMAL_STRING_LENGTH)
145 		ndigits = DECIMAL_STRING_LENGTH - 1;
146 	dm.ndigits = ndigits;
147 	double_to_decimal(&number, &dm, &dr, &fef);
148 	__k_gconvert(ndigits, &dr, trailing, buf);
149 	return (buf);
150 }
151 
152 char *
sgconvert(single * number,int ndigits,int trailing,char * buf)153 sgconvert(single *number, int ndigits, int trailing, char *buf)
154 {
155 	decimal_mode    dm;
156 	decimal_record  dr;
157 	fp_exception_field_type fef;
158 
159 #if defined(__sparc)
160 	dm.rd = _QgetRD();
161 #elif defined(__i386) || defined(__amd64)
162 	dm.rd = __xgetRD();
163 #else
164 #error Unknown architecture
165 #endif
166 	dm.df = floating_form;
167 	if (ndigits < 0)
168 		ndigits = 6;
169 	else if (ndigits == 0)
170 		ndigits = 1;
171 	else if (ndigits >= DECIMAL_STRING_LENGTH)
172 		ndigits = DECIMAL_STRING_LENGTH - 1;
173 	dm.ndigits = ndigits;
174 	single_to_decimal(number, &dm, &dr, &fef);
175 	__k_gconvert(ndigits, &dr, trailing, buf);
176 	return (buf);
177 }
178 
179 char *
qgconvert(quadruple * number,int ndigits,int trailing,char * buf)180 qgconvert(quadruple *number, int ndigits, int trailing, char *buf)
181 {
182 	decimal_mode    dm;
183 	decimal_record  dr;
184 	fp_exception_field_type fef;
185 
186 #if defined(__sparc)
187 	dm.rd = _QgetRD();
188 #elif defined(__i386) || defined(__amd64)
189 	dm.rd = __xgetRD();
190 #else
191 #error Unknown architecture
192 #endif
193 	dm.df = floating_form;
194 	if (ndigits < 0)
195 		ndigits = 6;
196 	else if (ndigits == 0)
197 		ndigits = 1;
198 	else if (ndigits >= DECIMAL_STRING_LENGTH)
199 		ndigits = DECIMAL_STRING_LENGTH - 1;
200 	dm.ndigits = ndigits;
201 #if defined(__sparc)
202 	quadruple_to_decimal(number, &dm, &dr, &fef);
203 #elif defined(__i386) || defined(__amd64)
204 	extended_to_decimal((extended *)number, &dm, &dr, &fef);
205 #else
206 #error Unknown architecture
207 #endif
208 	__k_gconvert(ndigits, &dr, trailing, buf);
209 	return (buf);
210 }
211