xref: /titanic_44/usr/src/lib/libast/common/sfio/sfstrtod.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #include	"sfhdr.h"
23 
24 /*	Convert a Sfdouble_t value represented in an ASCII format into
25 **	the internal Sfdouble_t representation.
26 **
27 **	Written by Kiem-Phong Vo.
28 */
29 
30 #define BATCH	(2*sizeof(int))	/* accumulate this many digits at a time */
31 #define IPART		0	/* doing integer part */
32 #define FPART		1	/* doing fractional part */
33 #define EPART		2	/* doing exponent part */
34 
35 #if __STD_C
36 static Sfdouble_t sfpow10(reg int n)
37 #else
38 static Sfdouble_t sfpow10(n)
39 reg int	n;
40 #endif
41 {
42 	Sfdouble_t	dval;
43 
44 	switch(n)
45 	{	case -3:	return .001;
46 		case -2:	return .01;
47 		case -1:	return .1;
48 		case  0:	return 1.;
49 		case  1:	return 10.;
50 		case  2:	return 100.;
51 		case  3:	return 1000.;
52 	}
53 
54 	if(n < 0)
55 	{	dval = .0001;
56 		for(n += 4; n < 0; n += 1)
57 			dval /= 10.;
58 	}
59 	else
60 	{	dval = 10000.;
61 		for(n -= 4; n > 0; n -= 1)
62 			dval *= 10.;
63 	}
64 
65 	return dval;
66 }
67 
68 #if __STD_C
69 Sfdouble_t _sfstrtod(reg const char* s, char** retp)
70 #else
71 Sfdouble_t _sfstrtod(s,retp)
72 reg char*	s;	/* string to convert */
73 char**		retp;	/* to return the remainder of string */
74 #endif
75 {
76 	reg int		n, c, m;
77 	reg int		mode, fexp, sign, expsign;
78 	Sfdouble_t	dval;
79 #if _lib_locale
80 	int		decpoint = 0;
81 	int		thousand = 0;
82 	SFSETLOCALE(&decpoint,&thousand);
83 #else
84 #define decpoint	'.'
85 #endif
86 
87 	/* skip initial blanks */
88 	while(isspace(*s))
89 		++s;
90 
91 	/* get the sign */
92 	if((sign = (*s == '-')) || *s == '+')
93 		s += 1;
94 
95 	mode = IPART;
96 	fexp = expsign = 0;
97 	dval = 0.;
98 	while(*s)
99 	{	/* accumulate a handful of the digits */
100 		for(m = BATCH, n = 0; m > 0; --m, ++s)
101 		{	/* get and process a char */
102 			c = *s;
103 			if(isdigit(c))
104 				n = 10*n + (c - '0');
105 			else	break;
106 		}
107 
108 		/* number of digits accumulated */
109 		m = BATCH-m;
110 
111 		if(mode == IPART)
112 		{	/* doing the integer part */
113 			if(dval == 0.)
114 				dval = (Sfdouble_t)n;
115 			else	dval = dval*sfpow10(m) + (Sfdouble_t)n;
116 		}
117 		else if(mode == FPART)
118 		{	/* doing the fractional part */
119 			fexp -= m;
120 			if(n > 0)
121 				dval += n*sfpow10(fexp);
122 		}
123 		else if(n)
124 		{	/* doing the exponent part */
125 			if(expsign)
126 				n = -n;
127 			dval *= sfpow10(n);
128 		}
129 
130 		if(!c)
131 			break;
132 
133 		if(m < BATCH)
134 		{	/* detected a non-digit */
135 			if(c == decpoint)
136 			{	/* start the fractional part or no match */
137 				if(mode != IPART)
138 					break;
139 				mode = FPART;
140 				s += 1;
141 			}
142 			else if(c == 'e' || c == 'E')
143 			{	if(mode == EPART)
144 					break;
145 				mode = EPART;
146 				c = *++s;
147 				if((expsign = (c == '-')) || c == '+')
148 					s += 1;
149 			}
150 			else	break;
151 		}
152 	}
153 
154 	if(retp)
155 		*retp = (char*)s;
156 	return sign ? -dval : dval;
157 }
158