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 <string.h>
32#include <sys/types.h>
33#include "libc.h"
34
35/*
36 * Copies the appropriate string for a datum of class cl into *buf,
37 * choosing "Inf" or "Infinity" according to ndigits, the desired
38 * output string length.
39 */
40void
41__infnanstring(enum fp_class_type cl, int ndigits, char *buf)
42{
43	if (cl == fp_infinity) {
44		if (ndigits < 8)
45			(void) memcpy(buf, "Inf", 4);
46		else
47			(void) memcpy(buf, "Infinity", 9);
48		__inf_written = 1;
49	} else {
50		(void) memcpy(buf, "NaN", 4);
51		__nan_written = 1;
52	}
53}
54
55char *
56econvert(double arg, int ndigits, int *decpt, int *sign, char *buf)
57{
58	decimal_mode    dm;
59	decimal_record  dr;
60	fp_exception_field_type ef;
61	int		i;
62
63#if defined(__sparc)
64	dm.rd = _QgetRD();
65#elif defined(__i386) || defined(__amd64)
66	dm.rd = __xgetRD();
67#else
68#error Unknown architecture
69#endif
70	dm.df = floating_form;	/* E format. */
71	if (ndigits <= 0)
72		ndigits = 1;
73	else if (ndigits >= DECIMAL_STRING_LENGTH)
74		ndigits = DECIMAL_STRING_LENGTH - 1;
75	dm.ndigits = ndigits;	/* Number of significant digits. */
76	double_to_decimal(&arg, &dm, &dr, &ef);
77	*sign = dr.sign;
78	switch (dr.fpclass) {
79	case fp_normal:
80	case fp_subnormal:
81		*decpt = dr.exponent + ndigits;
82		for (i = 0; i < ndigits; i++)
83			buf[i] = dr.ds[i];
84		buf[ndigits] = 0;
85		break;
86	case fp_zero:
87		*decpt = 1;
88		for (i = 0; i < ndigits; i++)
89			buf[i] = '0';
90		buf[ndigits] = 0;
91		break;
92	default:
93		*decpt = 0;
94		__infnanstring(dr.fpclass, ndigits, buf);
95		break;
96	}
97	return (buf);
98}
99
100char *
101seconvert(single *arg, int ndigits, int *decpt, int *sign, char *buf)
102{
103	decimal_mode    dm;
104	decimal_record  dr;
105	fp_exception_field_type ef;
106	int		i;
107
108#if defined(__sparc)
109	dm.rd = _QgetRD();
110#elif defined(__i386) || defined(__amd64)
111	dm.rd = __xgetRD();
112#else
113#error Unknown architecture
114#endif
115	dm.df = floating_form;	/* E format. */
116	if (ndigits <= 0)
117		ndigits = 1;
118	else if (ndigits >= DECIMAL_STRING_LENGTH)
119		ndigits = DECIMAL_STRING_LENGTH - 1;
120	dm.ndigits = ndigits;	/* Number of significant digits. */
121	single_to_decimal(arg, &dm, &dr, &ef);
122	*sign = dr.sign;
123	switch (dr.fpclass) {
124	case fp_normal:
125	case fp_subnormal:
126		*decpt = dr.exponent + ndigits;
127		for (i = 0; i < ndigits; i++)
128			buf[i] = dr.ds[i];
129		buf[ndigits] = 0;
130		break;
131	case fp_zero:
132		*decpt = 1;
133		for (i = 0; i < ndigits; i++)
134			buf[i] = '0';
135		buf[ndigits] = 0;
136		break;
137	default:
138		*decpt = 0;
139		__infnanstring(dr.fpclass, ndigits, buf);
140		break;
141	}
142	return (buf);
143}
144
145char *
146qeconvert(quadruple *arg, int ndigits, int *decpt, int *sign, char *buf)
147{
148	decimal_mode	dm;
149	decimal_record	dr;
150	fp_exception_field_type ef;
151	int		i;
152
153#if defined(__sparc)
154	dm.rd = _QgetRD();
155#elif defined(__i386) || defined(__amd64)
156	dm.rd = __xgetRD();
157#else
158#error Unknown architecture
159#endif
160	dm.df = floating_form;	/* E format. */
161	if (ndigits <= 0)
162		ndigits = 1;
163	else if (ndigits >= DECIMAL_STRING_LENGTH)
164		ndigits = DECIMAL_STRING_LENGTH - 1;
165	dm.ndigits = ndigits;	/* Number of significant digits. */
166#if defined(__sparc)
167	quadruple_to_decimal(arg, &dm, &dr, &ef);
168#elif defined(__i386) || defined(__amd64)
169	extended_to_decimal((extended *)arg, &dm, &dr, &ef);
170#else
171#error Unknown architecture
172#endif
173	*sign = dr.sign;
174	switch (dr.fpclass) {
175	case fp_normal:
176	case fp_subnormal:
177		*decpt = dr.exponent + ndigits;
178		for (i = 0; i < ndigits; i++)
179			buf[i] = dr.ds[i];
180		buf[ndigits] = 0;
181		break;
182	case fp_zero:
183		*decpt = 1;
184		for (i = 0; i < ndigits; i++)
185			buf[i] = '0';
186		buf[ndigits] = 0;
187		break;
188	default:
189		*decpt = 0;
190		__infnanstring(dr.fpclass, ndigits, buf);
191		break;
192	}
193	return (buf);
194}
195