Import upstream 2.3.14
[packages/xinetd.git] / libs / src / portable / cvt.c
1 /*
2  * (c) Copyright 1998-2001 by Rob Braun
3  * All rights reserved.  The file named COPYRIGHT specifies the terms
4  * and conditions for redistribution.
5  */
6
7 #include "config.h"
8 #include <stdlib.h>
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <math.h>
13 #include <errno.h>
14 #include <ctype.h>
15
16 #ifndef FLOAT_TYPE
17 #define FLOAT_TYPE double
18 #define FUNC_PREFIX
19 #define FLOAT_FMT_FLAG
20 #define FLOAT_NAME_EXT
21 #endif
22
23 #ifndef MAXDIG
24 #define MAXDIG 120
25 #endif
26
27 #ifndef APPEND
28 #define APPEND(a, b) APPEND2 (a, b)
29 #endif
30
31 #ifndef APPEND2
32 #define APPEND2(a, b) a##b
33 #endif
34
35 #ifndef FLOOR
36 #define FLOOR APPEND(floor, FLOAT_NAME_EXT)
37 #endif
38 #ifndef FABS
39 #define FABS APPEND(fabs, FLOAT_NAME_EXT)
40 #endif
41 #ifndef LOG10
42 #define LOG10 APPEND(log10, FLOAT_NAME_EXT)
43 #endif
44 #ifndef EXP
45 #define EXP APPEND(exp, FLOAT_NAME_EXT)
46 #endif
47 #ifndef ISINF
48 #define ISINF APPEND(isinf, FLOAT_NAME_EXT)
49 #endif
50 #ifndef ISNAN
51 #define ISNAN APPEND(isnan, FLOAT_NAME_EXT)
52 #endif
53
54 #ifndef EINVAL
55 #define EINVAL 22
56 #endif
57
58 #ifndef MAX
59 #define MAX(a,b) ((a)>(b)?(a):(b))
60 #endif
61
62 #ifndef __set_errno
63 #define __set_errno(x) errno = (x)
64 #endif
65
66 #ifndef HAVE_FCVT
67 int
68 APPEND (FUNC_PREFIX, fcvt_r) (FLOAT_TYPE value, 
69                               int ndigit, 
70                               int *decpt, 
71                               int *sign, 
72                               char *buf, 
73                               size_t len)
74 {
75    int n, i;
76    int left;
77
78    if (buf == NULL) {
79       __set_errno (EINVAL);
80       return -1;
81    }
82
83    left = 0;
84    if (!ISINF (value) && !ISNAN (value)) {
85       /* OK, the following is not entirely correct.  -0.0 is not handled
86        * correctly but glibc 2.0 does not have a portable function to
87        * implement this test.  
88        */
89        *sign = value < 0.0;
90        if (*sign)
91           value = -value;
92
93        if (ndigit < 0) {
94           /* Rounding to the left of the decimal point.  */
95           while (ndigit < 0) {
96              FLOAT_TYPE new_value = value * 0.1;
97
98              if (new_value < 1.0) {
99                 ndigit = 0;
100                 break;
101              }
102
103              value = new_value;
104              ++left;
105              ++ndigit;
106           }
107        }
108     } else {
109        /* Value is Inf or NaN.  */
110        *sign = 0;
111     }
112
113     n = strx_nprint (buf, len, "%.*" FLOAT_FMT_FLAG "f", ndigit, value);
114     if (n < 0)
115        return -1;
116
117     i = 0;
118     while (i < n && isdigit (buf[i]))
119        ++i;
120     *decpt = i;
121
122     if (i == 0)
123        /* Value is Inf or NaN.  */
124        return 0;
125
126     if (i < n) {
127        do
128        ++i;
129        while (i < n && !isdigit (buf[i]));
130
131        if (*decpt == 1 && buf[0] == '0' && value != 0.0) {
132           /* We must not have leading zeroes.  Strip them all out and
133            * adjust *DECPT if necessary.  */
134           --*decpt;
135           while (i < n && buf[i] == '0')
136           {
137              --*decpt;
138              ++i;
139           }
140        }
141
142        memmove (&buf[MAX (*decpt, 0)], &buf[i], n - i);
143        buf[n - (i - MAX (*decpt, 0))] = '\0';
144     }
145
146     if (left) {
147        *decpt += left;
148        if (--len > n) {
149           while (left-- > 0 && n < len)
150              buf[n++] = '0';
151           buf[n] = '\0';
152        }
153     }
154
155     return 0;
156 }
157 #endif /* HAVE_FCVT */
158
159 #define weak_extern2(name) 
160 weak_extern2 (FLOOR) weak_extern2 (LOG10) weak_extern2 (FABS)
161 weak_extern2 (EXP)
162
163 #ifndef HAVE_ECVT
164 int
165 APPEND (FUNC_PREFIX, ecvt_r) (FLOAT_TYPE value, 
166                               int ndigit, 
167                               int *decpt, 
168                               int *sign, 
169                               char *buf, 
170                               size_t len)
171 {
172   int exponent = 0;
173
174   if (!ISNAN (value) && !ISINF (value) && value != 0.0) {
175       FLOAT_TYPE (*log10_function) (FLOAT_TYPE) = &LOG10;
176
177       if (log10_function) {
178          /* Use the reasonable code if -lm is included.  */
179          FLOAT_TYPE dexponent;
180          dexponent = FLOOR (LOG10 (FABS (value)));
181          value *= EXP (dexponent * -M_LN10);
182          exponent = (int) dexponent;
183       } else {
184          /* Slow code that doesn't require -lm functions.  */
185          FLOAT_TYPE d;
186          if (value < 0.0)
187             d = -value;
188          else
189             d = value;
190          if (d < 1.0) {
191             do {
192                d *= 10.0;
193                --exponent;
194             } while (d < 1.0);
195          } else if (d >= 10.0) {
196             do {
197                d *= 0.1;
198                ++exponent;
199             } while (d >= 10.0);
200          }
201          if (value < 0.0)
202             value = -d;
203          else
204             value = d;
205        }
206     } else if (value == 0.0)
207        /* SUSv2 leaves it unspecified whether *DECPT is 0 or 1 for 0.0.
208         * This could be changed to -1 if we want to return 0.  */
209         exponent = 0;
210
211     if (ndigit <= 0 && len > 0) {
212        buf[0] = '\0';
213        *decpt = 1;
214        if (!ISINF (value) && !ISNAN (value))
215           *sign = value < 0.0;
216        else
217           *sign = 0;
218     } else
219        if (APPEND (FUNC_PREFIX, fcvt_r) (value, ndigit - 1, decpt, sign,
220                       buf, len))
221           return -1;
222
223     *decpt += exponent;
224     return 0;
225 }
226 #endif /* HAVE_ECVT */
227
228 #ifndef HAVE_FCVT
229 char *
230 APPEND (FUNC_PREFIX, fcvt) (FLOAT_TYPE value, 
231                             int ndigit, 
232                             int *decpt, 
233                             int *sign)
234 {
235   static char buf[MAXDIG];
236
237   (void) APPEND (FUNC_PREFIX, fcvt_r) (value, ndigit, decpt, sign,
238                        buf, sizeof buf);
239
240   return buf;
241 }
242 #endif /* HAVE_FCVT */
243
244 #ifndef HAVE_ECVT
245 char *
246 APPEND (FUNC_PREFIX, ecvt) (FLOAT_TYPE value, 
247                             int ndigit, 
248                             int *decpt, 
249                             int *sign)
250 {
251   static char buf[MAXDIG];
252
253   (void) APPEND (FUNC_PREFIX, ecvt_r) (value, ndigit, decpt, sign,
254                        buf, sizeof buf);
255
256   return buf;
257 }
258 #endif /* HAVE_ECVT */
259
260 #ifndef HAVE_GCVT
261 char *
262 APPEND (FUNC_PREFIX, gcvt) (FLOAT_TYPE value, 
263                             int ndigit, 
264                             char *buf)
265 {
266   sprintf (buf, "%.*" FLOAT_FMT_FLAG "g", ndigit, value);
267   return buf;
268 }
269 #endif /* HAVE_GCVT */