]> git.street.me.uk Git - andy/viking.git/blob - src/misc/strtod.c
Open files in selected layer
[andy/viking.git] / src / misc / strtod.c
1 //
2 // strtod.c
3 //
4 // Convert string to double 
5 //
6 // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 // 
12 // 1. Redistributions of source code must retain the above copyright 
13 //    notice, this list of conditions and the following disclaimer.  
14 // 2. Redistributions in binary form must reproduce the above copyright
15 //    notice, this list of conditions and the following disclaimer in the
16 //    documentation and/or other materials provided with the distribution.  
17 // 3. Neither the name of the project nor the names of its contributors
18 //    may be used to endorse or promote products derived from this software
19 //    without specific prior written permission. 
20 // 
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
31 // SUCH DAMAGE.
32 // 
33
34 // Tweaked version for Viking project to read in values containing ',' or '.' as the decimal separator
35 // Modified functions to prevent clashing with the system ones
36
37 #include <errno.h>
38 #include <ctype.h>
39 #include <math.h>
40 #include <float.h>
41 #include <stdlib.h>
42
43 double strtod_i8n(const char *str, char **endptr) {
44   double number;
45   int exponent;
46   int negative;
47   char *p = (char *) str;
48   double p10;
49   int n;
50   int num_digits;
51   int num_decimals;
52
53   // Skip leading whitespace
54   while (isspace(*p)) p++;
55
56   // Handle optional sign
57   negative = 0;
58   switch (*p) {
59     case '-': negative = 1; // Fall through to increment position
60     case '+': p++;
61   }
62
63   number = 0.;
64   exponent = 0;
65   num_digits = 0;
66   num_decimals = 0;
67
68   // Process string of digits
69   while (isdigit(*p)) {
70     number = number * 10. + (*p - '0');
71     p++;
72     num_digits++;
73   }
74
75   // Process decimal part
76   if (*p == '.' || *p == ',') {
77     p++;
78
79     while (isdigit(*p)) {
80       number = number * 10. + (*p - '0');
81       p++;
82       num_digits++;
83       num_decimals++;
84     }
85
86     exponent -= num_decimals;
87   }
88
89   if (num_digits == 0) {
90     errno = ERANGE;
91     return 0.0;
92   }
93
94   // Correct for sign
95   if (negative) number = -number;
96
97   // Process an exponent string
98   if (*p == 'e' || *p == 'E') {
99     // Handle optional sign
100     negative = 0;
101     switch (*++p) {
102       case '-': negative = 1;   // Fall through to increment pos
103       case '+': p++;
104     }
105
106     // Process string of digits
107     n = 0;
108     while (isdigit(*p)) {
109       n = n * 10 + (*p - '0');
110       p++;
111     }
112
113     if (negative) {
114       exponent -= n;
115     } else {
116       exponent += n;
117     }
118   }
119
120   if (exponent < DBL_MIN_EXP  || exponent > DBL_MAX_EXP) {
121     errno = ERANGE;
122     return HUGE_VAL;
123   }
124
125   // Scale the result
126   p10 = 10.;
127   n = exponent;
128   if (n < 0) n = -n;
129   while (n) {
130     if (n & 1) {
131       if (exponent < 0) {
132         number /= p10;
133       } else {
134         number *= p10;
135       }
136     }
137     n >>= 1;
138     p10 *= p10;
139   }
140
141   if (number == HUGE_VAL) errno = ERANGE;
142   if (endptr) *endptr = p;
143
144   return number;
145 }
146
147 float strtof_i8n(const char *str, char **endptr) {
148   return (float) strtod_i8n(str, endptr);
149 }
150
151
152 long double strtold_i8n(const char *str, char **endptr) {
153   return strtod_i8n(str, endptr);
154 }
155
156 double atof_i8n(const char *str) {
157   return strtod_i8n(str, NULL);
158 }