aboutsummaryrefslogtreecommitdiffstats
path: root/missing/strtod.c
blob: 38c7ce504ba4ae34df67d6fcaa1a073bb0e3ff03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
 * strtod.c
 *
 * Stupid version of System V strtod(3) library routine.
 * Does no overflow/underflow checking.
 *
 * A real number is defined to be
 *	optional leading white space
 *	optional sign
 *	string of digits with optional decimal point
 *	optional 'e' or 'E'
 *		followed by optional sign or space
 *		followed by an integer
 *
 * if ptr is not NULL a pointer to the character terminating the
 * scan is returned in *ptr.  If no number formed, *ptr is set to str
 * and 0 is returned.
 *
 * For speed, we don't do the conversion ourselves.  Instead, we find
 * the end of the number and then call atof() to do the dirty work.
 * This bought us a 10% speedup on a sample program at uunet.uu.net.
 */

#if 0
#include <ctype.h>
#endif

extern double atof();

double
strtod (s, ptr)
register const char *s;
register char **ptr;
{
	double ret = 0.0;
	char *start = s;
	char *begin = NULL;
	int success = 0;

	/* optional white space */
	while (isspace(*s))
		s++;

	/* optional sign */
	if (*s == '+' || *s == '-') {
		s++;
		if (*(s-1) == '-')
			begin = s - 1;
		else
			begin = s;
	}

	/* string of digits with optional decimal point */
	if (isdigit(*s) && ! begin)
		begin = s;

	while (isdigit(*s)) {
		s++;
		success++;
	}

	if (*s == '.') {
		if (! begin)
			begin = s;
		s++;
		while (isdigit(*s))
			s++;
		success++;
	}

	if (s == start || success == 0)		/* nothing there */
		goto out;

	/*
 	 *	optional 'e' or 'E'
	 *		followed by optional sign or space
	 *		followed by an integer
	 */

	if (*s == 'e' || *s == 'E') {
		s++;

		/* XXX - atof probably doesn't allow spaces here */
		while (isspace(*s))
			s++;

		if (*s == '+' || *s == '-')
			s++;

		while (isdigit(*s))
			s++;
	}

	/* go for it */
	ret = atof(begin);

out:
	if (! success)
		s = start;	/* in case all we did was skip whitespace */

	if (ptr)
		*ptr = s;

	return ret;
}

#ifdef TEST
main (argc, argv)
int argc;
char **argv;
{
	double d;
	char *p;

	for (argc--, argv++; argc; argc--, argv++) {
		d = strtod (*argv, & p);
		printf ("%lf [%s]\n", d, p);
	}
}
#endif