Made on Kubuntu
00001 // Copyright (C) 2009-2010 Ferdinand Majerech 00002 // This file is part of MiniINI 00003 // For conditions of distribution and use, see copyright notice in LICENSE.txt 00004 00005 #include <cstring> 00006 #include <cerrno> 00007 #include <cstdlib> 00008 #include <cassert> 00009 #include <cfloat> 00010 00011 #include "typedefs.h" 00012 00013 #ifndef PARSE_H_INCLUDED 00014 #define PARSE_H_INCLUDED 00015 00016 namespace miniini_private 00017 { 00018 00019 //minimum and maximum 32bit int values, borrowed from C99 limits.h 00020 #define INT32_MAX (2147483647) 00021 #define INT32_MIN (-2147483647 - 1) 00022 00023 //repeat a piece of code 10 times 00024 #define FOR_10(instr) \ 00025 {\ 00026 instr;\ 00027 instr;\ 00028 instr;\ 00029 instr;\ 00030 instr;\ 00031 instr;\ 00032 instr;\ 00033 instr;\ 00034 instr;\ 00035 instr;\ 00036 } 00037 00038 //decimal orders of magnitude using in int parsing 00039 const s64 orders_of_magnitude_int [10] = {1, 10, 100, 1000, 10000, 100000, 00040 1000000, 10000000, 100000000, 00041 1000000000}; 00042 00043 //represents status of conversion in parsing methods 00044 enum ConversionStatus 00045 { 00046 CONV_OK, 00047 CONV_WAR_OVERFLOW, 00048 CONV_WAR_REDUNANT, 00049 CONV_ERR_TYPE 00050 }; 00051 00053 00066 inline ConversionStatus ParseInt(const c * string, s32 & out) 00067 { 00068 //process sign character, if any 00069 00070 //1 if the number we're parsing is positive, -1 if negative 00071 i sign = 1; 00072 if(*string == '-') 00073 { 00074 sign = -1; 00075 ++string; 00076 } 00077 else if(*string == '+') 00078 { 00079 ++string; 00080 } 00081 00082 //skip any leading zeroes 00083 00084 //if there is at least one leading zero, this will be true. 00085 //If the number is composed of only leading zeroe, which are skipped, 00086 //(e.g. number 0), this is used to check that the string contains a number 00087 //instead of containing only non-parsable characters. 00088 bool zero = false; 00089 //first zero 00090 if(*string == '0') 00091 { 00092 zero = true; 00093 ++string; 00094 //any more zeroes 00095 while (*string == '0') 00096 { 00097 ++string; 00098 } 00099 } 00100 00101 //stores digits of the parsed number (as integers). 00102 //32 bit integer can have at most 10 digits. 00103 static i digits [10]; 00104 ui digitcount = 0; 00105 00106 //read digits 00107 register c digitchar; 00108 FOR_10 00109 ( 00110 digitchar = *string; 00111 if(digitchar < '0' || digitchar > '9') 00112 { 00113 goto READ_END; 00114 } 00115 digits[digitcount] = digitchar - '0'; 00116 ++digitcount; 00117 ++string; 00118 ) 00119 //if 11th char is still a number, we're overflowing 00120 if(*string >= '0' && *string <= '9' ) 00121 { 00122 if(sign == 1) 00123 { 00124 out = INT32_MAX; 00125 } 00126 else 00127 { 00128 out = INT32_MIN; 00129 } 00130 return CONV_WAR_OVERFLOW; 00131 } 00132 00133 READ_END: 00134 00135 //if digitcount is 0, and there weren't any leading zeroes (which don't add to digitcount), 00136 //we have an error. 00137 if(digitcount == 0) 00138 { 00139 if(zero) 00140 { 00141 //The number only contains zeroes, so it is 0 00142 out = 0; 00143 return CONV_OK; 00144 } 00145 else 00146 { 00147 //out is not altered 00148 return CONV_ERR_TYPE; 00149 } 00150 } 00151 00152 //using 64 bit so we can check for overflows easily 00153 s64 temp = 0; 00154 00155 //parse the digits 00156 for(ui digit = 0; digit < digitcount; ++digit) 00157 { 00158 temp += static_cast<s64>(digits[digit] * orders_of_magnitude_int[digitcount - digit - 1]); 00159 } 00160 00161 //apply the sign 00162 temp *= sign; 00163 //handle overflows 00164 if(temp > INT32_MAX) 00165 { 00166 out = INT32_MAX; 00167 return CONV_WAR_OVERFLOW; 00168 } 00169 else if(temp < INT32_MIN) 00170 { 00171 out = INT32_MIN; 00172 return CONV_WAR_OVERFLOW; 00173 } 00174 00175 out = static_cast<s32>(temp); 00176 #ifdef MINIINI_DEBUG 00177 //if we're not yet at the trailing zero, this is a float or has redunant chars 00178 if(*string != '\0') 00179 { 00180 return CONV_WAR_REDUNANT; 00181 } 00182 #endif 00183 return CONV_OK; 00184 } 00185 00187 00202 inline ConversionStatus ParseFloatBase(const c *& string, ld & out) 00203 { 00204 //skip any leading zeroes 00205 00206 //if there is at least one leading zero, this will be true. 00207 //If the whole part is composed of only leading zeroes, which are skipped, 00208 //(e.g. in 0.0), this is used to check that the string contains a number 00209 //instead of containing only non-parsable characters. 00210 bool zero = false; 00211 //first zero 00212 if(*string == '0') 00213 { 00214 zero = true; 00215 ++string; 00216 //any more zeroes 00217 while (*string == '0') 00218 { 00219 ++string; 00220 } 00221 } 00222 00223 //stores digits of the parsed number (as integers). 00224 //32 bit float can have at most 39 digits before decimal point. 00225 static i digits [39]; 00226 ui digitcount = 0; 00227 00228 //read digits 00229 while(*string >= '0' && *string <= '9') 00230 { 00231 //if we already have 39 digits and there's another one, we're overflowing 00232 if(digitcount == 39) 00233 { 00234 return CONV_WAR_OVERFLOW; 00235 } 00236 digits[digitcount] = *string - '0'; 00237 ++digitcount; 00238 ++string; 00239 } 00240 00241 if(digitcount == 0) 00242 { 00243 //digitcount is 0 but there were leading zeroes so the whole number 00244 //part is 0 00245 if(zero) 00246 { 00247 //The number only contains zeroes, so it is 0 00248 out = 0.0; 00249 if(*string == '.' || *string == '\0') 00250 { 00251 return CONV_OK; 00252 } 00253 return CONV_WAR_REDUNANT; 00254 } 00255 //digitcount is 0, there weren't leading zeroes but we stopped at a 00256 //decimal point instead of an invalid character (e.g. .5 instead of X5) 00257 //so the whole number part is still a valid 0 00258 else if(*string == '.') 00259 { 00260 out = 0.0; 00261 return CONV_OK; 00262 } 00263 //we stopped at an invalid character without any digits or leading 00264 //zeroes, so we have an error 00265 else 00266 { 00267 //out is not altered 00268 return CONV_ERR_TYPE; 00269 } 00270 } 00271 00272 ld temp = 0.0; 00273 00274 //parse the digits 00275 ld order_of_magnitude = 1.0; 00276 for(i digit = digitcount - 1; digit >= 0; --digit) 00277 { 00278 temp += digits[digit] * order_of_magnitude; 00279 order_of_magnitude *= 10.0; 00280 } 00281 00282 //overflow will be checked by the caller (we're using long doubles 00283 //temporarily, which are precise enough as we're only parsing the first 00284 //39 digits) 00285 out = temp; 00286 00287 #ifdef MINIINI_DEBUG 00288 if(*string != '.' && *string != '\0') 00289 { 00290 return CONV_WAR_REDUNANT; 00291 } 00292 #endif 00293 return CONV_OK; 00294 } 00295 00297 00312 inline ConversionStatus ParseFloatFraction(const c *& string, ld & out) 00313 { 00314 out = 0.0; 00315 //stores digits of the parsed number (as integers). 00316 //32 bit float can have at most 38 digits after the decimal point. 00317 static i digits [38]; 00318 ui digitcount = 0; 00319 //read digits 00320 while(*string >= '0' && *string <= '9') 00321 { 00322 if(digitcount == 38) 00323 { 00324 break; 00325 } 00326 digits[digitcount] = *string - '0'; 00327 ++digitcount; 00328 ++string; 00329 } 00330 ld temp = 0.0; 00331 00332 //even if there are zero digits, there is no error, fraction is 0.0 00333 00334 //parse digits 00335 ld order_of_magnitude = 0.1; 00336 for(ui digit = 0; digit < digitcount; ++digit) 00337 { 00338 temp += digits[digit] * order_of_magnitude; 00339 order_of_magnitude *= 0.1; 00340 } 00341 00342 out = temp; 00343 00344 #ifdef MINIINI_DEBUG 00345 if(*string != '\0') 00346 { 00347 return CONV_WAR_REDUNANT; 00348 } 00349 #endif 00350 return CONV_OK; 00351 } 00352 00354 00369 inline ConversionStatus ParseFloat(const c * string, f & out) 00370 { 00371 //1 if the number we're parsing is positive, -1 if negative 00372 ld sign = 1.0; 00373 //process sign character, if any 00374 if(*string == '-') 00375 { 00376 sign = -1.0; 00377 ++string; 00378 } 00379 else if(*string == '+') 00380 { 00381 ++string; 00382 } 00383 00384 ld base, fraction; 00385 //First parse the whole number part of the float. 00386 ConversionStatus statbase = ParseFloatBase(string, base); 00387 if(statbase == CONV_ERR_TYPE) 00388 { 00389 return CONV_ERR_TYPE; 00390 } 00391 else if(statbase == CONV_WAR_OVERFLOW) 00392 { 00393 if(sign > 0.0) 00394 { 00395 out = FLT_MAX; 00396 } 00397 else 00398 { 00399 out = -FLT_MAX; 00400 } 00401 return CONV_WAR_OVERFLOW; 00402 } 00403 #ifdef MINIINI_DEBUG 00404 else if(statbase == CONV_WAR_REDUNANT) 00405 { 00406 out = static_cast<f>(sign * base); 00407 return CONV_WAR_REDUNANT; 00408 } 00409 #endif 00410 //there were no warnings but there wasn't a decimal point so we're done 00411 //parsing 00412 if(*string != '.') 00413 { 00414 out = static_cast<f>(sign * base); 00415 return CONV_OK; 00416 } 00417 //skip the decimal point 00418 ++string; 00419 //First parse the fraction part of the float 00420 ConversionStatus statfraction = ParseFloatFraction(string, fraction); 00421 //join the whole number and fraction parts 00422 ld temp = fraction + base; 00423 if(temp > FLT_MAX) 00424 { 00425 temp = FLT_MAX; 00426 out = static_cast<f>(sign * temp); 00427 return CONV_WAR_OVERFLOW; 00428 } 00429 out = static_cast<f>(sign * temp); 00430 #ifdef MINIINI_DEBUG 00431 if(statfraction == CONV_WAR_REDUNANT) 00432 { 00433 return CONV_WAR_REDUNANT; 00434 } 00435 #endif 00436 return CONV_OK; 00437 } 00438 #undef INT32_MAX 00439 #undef INT32_MIN 00440 00441 #undef FOR_10 00442 } 00443 #endif