Sync usage with man page.
[netbsd-mini2440.git] / lib / libc / gdtoa / gethex.c
blobb7bf1f84c8c29eb1d2a895faa82eaf38960c7c2e
1 /* $NetBSD: gethex.c,v 1.3 2006/03/11 18:38:14 kleink Exp $ */
3 /****************************************************************
5 The author of this software is David M. Gay.
7 Copyright (C) 1998 by Lucent Technologies
8 All Rights Reserved
10 Permission to use, copy, modify, and distribute this software and
11 its documentation for any purpose and without fee is hereby
12 granted, provided that the above copyright notice appear in all
13 copies and that both that the copyright notice and this
14 permission notice and warranty disclaimer appear in supporting
15 documentation, and that the name of Lucent or any of its entities
16 not be used in advertising or publicity pertaining to
17 distribution of the software without specific, written prior
18 permission.
20 LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
21 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
22 IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
23 SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
25 IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27 THIS SOFTWARE.
29 ****************************************************************/
31 /* Please send bug reports to David M. Gay (dmg at acm dot org,
32 * with " at " changed at "@" and " dot " changed to "."). */
34 #include "gdtoaimp.h"
36 #ifdef USE_LOCALE
37 #include "locale.h"
38 #endif
40 int
41 #ifdef KR_headers
42 gethex(sp, fpi, expt, bp, sign)
43 CONST char **sp; CONST FPI *fpi; Long *expt; Bigint **bp; int sign;
44 #else
45 gethex( CONST char **sp, CONST FPI *fpi, Long *expt, Bigint **bp, int sign)
46 #endif
48 Bigint *b;
49 CONST unsigned char *decpt, *s0, *s, *s1;
50 int esign, havedig, irv, k, n, nbits, up, zret;
51 ULong L, lostbits, *x;
52 Long e, e1;
53 #ifdef USE_LOCALE
54 unsigned char decimalpoint = *localeconv()->decimal_point;
55 #else
56 #define decimalpoint '.'
57 #endif
59 if (!hexdig['0'])
60 hexdig_init_D2A();
61 havedig = 0;
62 s0 = *(CONST unsigned char **)sp + 2;
63 while(s0[havedig] == '0')
64 havedig++;
65 s0 += havedig;
66 s = s0;
67 decpt = 0;
68 zret = 0;
69 e = 0;
70 if (!hexdig[*s]) {
71 zret = 1;
72 if (*s != decimalpoint)
73 goto pcheck;
74 decpt = ++s;
75 if (!hexdig[*s])
76 goto pcheck;
77 while(*s == '0')
78 s++;
79 if (hexdig[*s])
80 zret = 0;
81 havedig = 1;
82 s0 = s;
84 while(hexdig[*s])
85 s++;
86 if (*s == decimalpoint && !decpt) {
87 decpt = ++s;
88 while(hexdig[*s])
89 s++;
91 if (decpt)
92 e = -(((Long)(s-decpt)) << 2);
93 pcheck:
94 s1 = s;
95 switch(*s) {
96 case 'p':
97 case 'P':
98 esign = 0;
99 switch(*++s) {
100 case '-':
101 esign = 1;
102 /* FALLTHROUGH */
103 case '+':
104 s++;
106 if ((n = hexdig[*s]) == 0 || n > 0x19) {
107 s = s1;
108 break;
110 e1 = n - 0x10;
111 while((n = hexdig[*++s]) !=0 && n <= 0x19)
112 e1 = 10*e1 + n - 0x10;
113 if (esign)
114 e1 = -e1;
115 e += e1;
117 *sp = __UNCONST(s);
118 if (zret)
119 return havedig ? STRTOG_Zero : STRTOG_NoNumber;
120 n = s1 - s0 - 1;
121 for(k = 0; n > 7; n = (unsigned int)n >> 1)
122 k++;
123 b = Balloc(k);
124 if (b == NULL)
125 return STRTOG_NoMemory;
126 x = b->x;
127 n = 0;
128 L = 0;
129 while(s1 > s0) {
130 if (*--s1 == decimalpoint)
131 continue;
132 if (n == 32) {
133 *x++ = L;
134 L = 0;
135 n = 0;
137 L |= (hexdig[*s1] & 0x0f) << n;
138 n += 4;
140 *x++ = L;
141 b->wds = n = x - b->x;
142 n = 32*n - hi0bits(L);
143 nbits = fpi->nbits;
144 lostbits = 0;
145 x = b->x;
146 if (n > nbits) {
147 n -= nbits;
148 if (any_on(b,n)) {
149 lostbits = 1;
150 k = n - 1;
151 if (x[(unsigned int)k>>kshift] & 1 << (k & kmask)) {
152 lostbits = 2;
153 if (k > 1 && any_on(b,k-1))
154 lostbits = 3;
157 rshift(b, n);
158 e += n;
160 else if (n < nbits) {
161 n = nbits - n;
162 b = lshift(b, n);
163 if (b == NULL)
164 return STRTOG_NoMemory;
165 e -= n;
166 x = b->x;
168 if (e > fpi->emax) {
169 ovfl:
170 Bfree(b);
171 *bp = 0;
172 return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
174 irv = STRTOG_Normal;
175 if (e < fpi->emin) {
176 irv = STRTOG_Denormal;
177 n = fpi->emin - e;
178 if (n >= nbits) {
179 switch (fpi->rounding) {
180 case FPI_Round_near:
181 if (n == nbits && (n < 2 || any_on(b,n-1)))
182 goto one_bit;
183 break;
184 case FPI_Round_up:
185 if (!sign)
186 goto one_bit;
187 break;
188 case FPI_Round_down:
189 if (sign) {
190 one_bit:
191 *expt = fpi->emin;
192 x[0] = b->wds = 1;
193 *bp = b;
194 return STRTOG_Denormal | STRTOG_Inexhi
195 | STRTOG_Underflow;
198 Bfree(b);
199 *bp = 0;
200 return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
202 k = n - 1;
203 if (lostbits)
204 lostbits = 1;
205 else if (k > 0)
206 lostbits = any_on(b,k);
207 if (x[(unsigned int)k>>kshift] & 1 << (k & kmask))
208 lostbits |= 2;
209 nbits -= n;
210 rshift(b,n);
211 e = fpi->emin;
213 if (lostbits) {
214 up = 0;
215 switch(fpi->rounding) {
216 case FPI_Round_zero:
217 break;
218 case FPI_Round_near:
219 if (lostbits & 2
220 && (lostbits & 1) | (x[0] & 1))
221 up = 1;
222 break;
223 case FPI_Round_up:
224 up = 1 - sign;
225 break;
226 case FPI_Round_down:
227 up = sign;
229 if (up) {
230 k = b->wds;
231 b = increment(b);
232 x = b->x;
233 if (irv == STRTOG_Denormal) {
234 if (nbits == fpi->nbits - 1
235 && x[(unsigned int)nbits >> kshift] & 1 << (nbits & kmask))
236 irv = STRTOG_Normal;
238 else if (b->wds > k
239 || ((n = nbits & kmask) !=0
240 && hi0bits(x[k-1]) < 32-n)) {
241 rshift(b,1);
242 if (++e > fpi->emax)
243 goto ovfl;
245 irv |= STRTOG_Inexhi;
247 else
248 irv |= STRTOG_Inexlo;
250 *bp = b;
251 *expt = e;
252 return irv;