]> err.no Git - sope/blob - libFoundation/Foundation/scanFloat.def
fixed some NGMail framework build issue
[sope] / libFoundation / Foundation / scanFloat.def
1 /* 
2    scanFloat.def
3
4    Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea.
5    All rights reserved.
6
7    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
8
9    This file is part of libFoundation.
10
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
15    documentation.
16
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.
23 */
24
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. */
28
29 #if defined(FLOAT_TYPE)
30 # define TYPE double
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)
37 # define TYPE double
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
43 #else
44 # error You should define FLOAT_TYPE or DOUBLE_TYPE
45 #endif
46
47     NSCharacterSet* decimals = nil;
48     id string = [self string];
49     unsigned int orig;
50     unsigned int location;
51     unsigned int length = [string length];
52     TYPE maxvalue = MAX_VALUE / 10;
53     TYPE mantissa = 0;
54     TYPE decValue = 0;
55     TYPE exponent1 = 0;
56     TYPE result;
57     int exponent2 = 0;
58     BOOL isNegative = NO;
59     NSDictionary* locale = [self locale];
60     unichar zeroChar = '0';
61     unichar thousandSep = ',';
62     unichar decimalSep = '.';
63     unichar c;
64
65     if ([self isAtEnd])
66         return NO;
67
68     /* First skip the blank characters */
69     [self scanCharactersFromSet:[self charactersToBeSkipped] intoString:NULL];
70
71     /* Create the decimals set */
72     if (locale) {
73         NSString* thousandString = [locale objectForKey:NSThousandsSeparator];
74         NSString* decimalsString = [locale objectForKey:NSDecimalDigits];
75         NSString* decimalSepString = [locale objectForKey:NSDecimalSeparator];
76
77         if (decimalsString) {
78             zeroChar = [decimalsString characterAtIndex:0];
79             decimals = [NSCharacterSet characterSetWithCharactersInString:
80                                     decimalsString];
81         }
82
83         if (thousandString)
84             thousandSep = [thousandString characterAtIndex:0];
85
86         if (decimalSepString)
87             decimalSep = [decimalSepString characterAtIndex:0];
88     }
89
90     if (!decimals)
91         decimals = [NSCharacterSet decimalDigitCharacterSet];
92
93     orig = [self scanLocation];
94     c = [string characterAtIndex:orig];
95     if (c == '-' || c == '+') {
96         isNegative = (c == '-');
97         orig++;
98     }
99
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);
108             continue;
109         }
110         if (c == thousandSep)
111             continue;
112
113         /* If `c' is neither a decimal nor a thousand separator, break. */
114         break;
115     }
116     result = mantissa;
117
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. */
121         int digits_no = 0;
122
123         location++;
124
125         /* Iterate through the exponent's digits */
126         for (exponent1 = 0.1; location < length; location++, exponent1 /= 10) {
127             c = [string characterAtIndex:location];
128
129             /* Break if the character is not a digit */
130             if (![decimals characterIsMember:c])
131                 break;
132
133             /* If result is too big to be represented just skip to the
134                next character. */
135             if (result > maxvalue)
136                 continue;
137
138             digits_no++;
139
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;
144         }
145     }
146     if (result <= maxvalue)
147         result += decValue;
148
149     if (c == 'e' || c == 'E') {
150         /* The number has an exponent. Store it in exponent2. */
151         BOOL expIsNegative = NO;
152
153         location++;
154         if (location < length) {
155             c = [string characterAtIndex:location];
156             if (c == '-') {
157                 expIsNegative = YES;
158                 location++;
159             }
160             else if (c == '+')
161                 location++;
162         }
163
164         /* Read the digits of the exponent. First skip the leading zeroes. */
165         for (; location < length; location++) {
166             c = [string characterAtIndex:location];
167             if (c == '0')
168                 continue;
169             else
170                 break;
171         }
172
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++) {
176             TYPE power10[10] = {
177                 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9
178             };
179
180             c = [string characterAtIndex:location];
181
182             /* Break if the character is not a digit */
183             if (![decimals characterIsMember:c])
184                 break;
185
186             /* If result is too big to be represented just skip to the
187                next character. */
188             if (result > maxvalue)
189                 continue;
190
191             if (expIsNegative) {
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];
197                 }
198             }
199             else {
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];
205                 }
206             }
207         }
208     }
209
210     if (location != orig) {
211         [self setScanLocation:location];
212
213         if (result > maxvalue) {
214             if (value)
215                 *value = (isNegative ? MIN_VALUE : MAX_VALUE);
216             return NO;
217         }
218         else {
219             if (value)
220                 *value = (isNegative ? -result : result);
221             return YES;
222         }
223     }
224
225     return NO;
226
227 #undef TYPE
228 #undef MIN_VALUE
229 #undef MAX_VALUE
230 #undef MAX_DIG
231 #undef MAX_EXP
232 #undef MIN_EXP