4 Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
7 Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
9 This file is part of libFoundation.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted, provided
13 that the above copyright notice appear in all copies and that both that
14 copyright notice and this permission notice appear in supporting
17 We disclaim all warranties with regard to this software, including all
18 implied warranties of merchantability and fitness, in no event shall
19 we be liable for any special, indirect or consequential damages or any
20 damages whatsoever resulting from loss of use, data or profits, whether in
21 an action of contract, negligence or other tortious action, arising out of
22 or in connection with the use or performance of this software.
25 /* This file is included by NSScanner.m to produce the definitions of
26 -scanFloat: and -scanDouble: methods. In order to work, either FLOAT_TYPE or
27 DOUBLE_TYPE should be defined. */
29 #if defined(FLOAT_TYPE)
31 # define MIN_VALUE FLT_MIN
32 # define MAX_VALUE FLT_MAX
33 # define MAX_DIG FLT_DIG
34 # define MAX_EXP FLT_MAX_10_EXP
35 # define MIN_EXP FLT_MIN_10_EXP
36 #elif defined(DOUBLE_TYPE)
38 # define MIN_VALUE DBL_MIN
39 # define MAX_VALUE DBL_MAX
40 # define MAX_DIG DBL_DIG
41 # define MAX_EXP DBL_MAX_10_EXP
42 # define MIN_EXP DBL_MIN_10_EXP
44 # error You should define FLOAT_TYPE or DOUBLE_TYPE
47 NSCharacterSet* decimals = nil;
48 id string = [self string];
50 unsigned int location;
51 unsigned int length = [string length];
52 TYPE maxvalue = MAX_VALUE / 10;
59 NSDictionary* locale = [self locale];
60 unichar zeroChar = '0';
61 unichar thousandSep = ',';
62 unichar decimalSep = '.';
68 /* First skip the blank characters */
69 [self scanCharactersFromSet:[self charactersToBeSkipped] intoString:NULL];
71 /* Create the decimals set */
73 NSString* thousandString = [locale objectForKey:NSThousandsSeparator];
74 NSString* decimalsString = [locale objectForKey:NSDecimalDigits];
75 NSString* decimalSepString = [locale objectForKey:NSDecimalSeparator];
78 zeroChar = [decimalsString characterAtIndex:0];
79 decimals = [NSCharacterSet characterSetWithCharactersInString:
84 thousandSep = [thousandString characterAtIndex:0];
87 decimalSep = [decimalSepString characterAtIndex:0];
91 decimals = [NSCharacterSet decimalDigitCharacterSet];
93 orig = [self scanLocation];
94 c = [string characterAtIndex:orig];
95 if (c == '-' || c == '+') {
96 isNegative = (c == '-');
100 /* Scan the mantisa */
101 for (location = orig; location < length; location++) {
102 c = [string characterAtIndex:location];
103 if ([decimals characterIsMember:c]) {
104 /* Even if result is greater than the maximum value that can be
105 represented, continue the scanning to skip the hole number. */
106 if (mantissa <= maxvalue)
107 mantissa = mantissa * 10 + (c - zeroChar);
110 if (c == thousandSep)
113 /* If `c' is neither a decimal nor a thousand separator, break. */
118 if (c == decimalSep) {
119 /* The number has a decimal part. Store it in the decValue but no more
120 than MAX_DIG digits; then skip all the digits. */
125 /* Iterate through the exponent's digits */
126 for (exponent1 = 0.1; location < length; location++, exponent1 /= 10) {
127 c = [string characterAtIndex:location];
129 /* Break if the character is not a digit */
130 if (![decimals characterIsMember:c])
133 /* If result is too big to be represented just skip to the
135 if (result > maxvalue)
140 /* Only store the digit if the number of digits read so far is less
141 than MAX_DIG to avoid a possible overflow. */
142 if (digits_no <= MAX_DIG)
143 decValue += (c - zeroChar) * exponent1;
146 if (result <= maxvalue)
149 if (c == 'e' || c == 'E') {
150 /* The number has an exponent. Store it in exponent2. */
151 BOOL expIsNegative = NO;
154 if (location < length) {
155 c = [string characterAtIndex:location];
164 /* Read the digits of the exponent. First skip the leading zeroes. */
165 for (; location < length; location++) {
166 c = [string characterAtIndex:location];
173 /* Read the exponent digits but check if it's greater than MAX_EXP or
174 less than MIN_EXP. */
175 for (; location < length; location++) {
177 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
180 c = [string characterAtIndex:location];
182 /* Break if the character is not a digit */
183 if (![decimals characterIsMember:c])
186 /* If result is too big to be represented just skip to the
188 if (result > maxvalue)
192 if (exponent2 < abs(MIN_EXP)) {
193 exponent2 = exponent2 * 10 + (c - zeroChar);
194 /* Adjust the result */
195 if (exponent2 < abs(MIN_EXP))
196 result /= power10[c - zeroChar];
200 if (exponent2 < MAX_EXP) {
201 exponent2 = exponent2 * 10 + (c - zeroChar);
202 /* Adjust the result */
203 if (exponent2 < MAX_EXP)
204 result *= power10[c - zeroChar];
210 if (location != orig) {
211 [self setScanLocation:location];
213 if (result > maxvalue) {
215 *value = (isNegative ? MIN_VALUE : MAX_VALUE);
220 *value = (isNegative ? -result : result);