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
35static 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
127char *
128gconvert(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
154char *
155sgconvert(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
181char *
182qgconvert(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