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 { 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 00065 inline ConversionStatus ParseInt(const c * string, s32 & out) 00066 { 00067 //process sign character, if any 00068 00069 //1 if the number we're parsing is positive, -1 if negative 00070 i sign = 1; 00071 if(*string == '-') 00072 { 00073 sign = -1; 00074 ++string; 00075 } 00076 else if(*string == '+') 00077 { 00078 ++string; 00079 } 00080 00081 //skip any leading zeroes 00082 00083 //if there is at least one leading zero, this will be true. 00084 //If the number is composed of only leading zeroe, which are skipped, 00085 //(e.g. number 0), this is used to check that the string contains a number 00086 //instead of containing only non-parsable characters. 00087 bool zero = false; 00088 //first zero 00089 if(*string == '0') 00090 { 00091 zero = true; 00092 ++string; 00093 //any more zeroes 00094 while (*string == '0') 00095 { 00096 ++string; 00097 } 00098 } 00099 00100 //stores digits of the parsed number (as integers). 00101 //32 bit integer can have at most 10 digits. 00102 static i digits [10]; 00103 ui digitcount = 0; 00104 00105 //read digits 00106 register c digitchar; 00107 FOR_10 00108 ( 00109 digitchar = *string; 00110 if(digitchar < '0' || digitchar > '9') 00111 { 00112 goto READ_END; 00113 } 00114 digits[digitcount] = digitchar - '0'; 00115 ++digitcount; 00116 ++string; 00117 ) 00118 //if 11th char is still a number, we're overflowing 00119 if(*string >= '0' && *string <= '9' ) 00120 { 00121 if(sign == 1) 00122 { 00123 out = INT32_MAX; 00124 } 00125 else 00126 { 00127 out = INT32_MIN; 00128 } 00129 return CONV_WAR_OVERFLOW; 00130 } 00131 00132 READ_END: 00133 00134 //if digitcount is 0, and there weren't any leading zeroes (which don't add to digitcount), 00135 //we have an error. 00136 if(digitcount == 0) 00137 { 00138 if(zero) 00139 { 00140 //The number only contains zeroes, so it is 0 00141 out = 0; 00142 return CONV_OK; 00143 } 00144 else 00145 { 00146 //out is not altered 00147 return CONV_ERR_TYPE; 00148 } 00149 } 00150 00151 //using 64 bit so we can check for overflows easily 00152 s64 temp = 0; 00153 00154 //parse the digits 00155 for(ui digit = 0; digit < digitcount; ++digit) 00156 { 00157 temp += static_cast<s64>(digits[digit] * orders_of_magnitude_int[digitcount - digit - 1]); 00158 } 00159 00160 //apply the sign 00161 temp *= sign; 00162 //handle overflows 00163 if(temp > INT32_MAX) 00164 { 00165 out = INT32_MAX; 00166 return CONV_WAR_OVERFLOW; 00167 } 00168 else if(temp < INT32_MIN) 00169 { 00170 out = INT32_MIN; 00171 return CONV_WAR_OVERFLOW; 00172 } 00173 00174 out = static_cast<s32>(temp); 00175 #ifdef MINIINI_DEBUG 00176 //if we're not yet at the trailing zero, this is a float or has redunant chars 00177 if(*string != '\0') 00178 { 00179 return CONV_WAR_REDUNANT; 00180 } 00181 #endif 00182 return CONV_OK; 00183 } 00184 00200 inline ConversionStatus ParseFloatBase(const c *& string, ld & out) 00201 { 00202 //skip any leading zeroes 00203 00204 //if there is at least one leading zero, this will be true. 00205 //If the whole part is composed of only leading zeroes, which are skipped, 00206 //(e.g. in 0.0), this is used to check that the string contains a number 00207 //instead of containing only non-parsable characters. 00208 bool zero = false; 00209 //first zero 00210 if(*string == '0') 00211 { 00212 zero = true; 00213 ++string; 00214 //any more zeroes 00215 while (*string == '0') 00216 { 00217 ++string; 00218 } 00219 } 00220 00221 //stores digits of the parsed number (as integers). 00222 //32 bit float can have at most 39 digits before decimal point. 00223 static i digits [39]; 00224 ui digitcount = 0; 00225 00226 //read digits 00227 while(*string >= '0' && *string <= '9') 00228 { 00229 //if we already have 39 digits and there's another one, we're overflowing 00230 if(digitcount == 39) 00231 { 00232 return CONV_WAR_OVERFLOW; 00233 } 00234 digits[digitcount] = *string - '0'; 00235 ++digitcount; 00236 ++string; 00237 } 00238 00239 if(digitcount == 0) 00240 { 00241 //digitcount is 0 but there were leading zeroes so the whole number 00242 //part is 0 00243 if(zero) 00244 { 00245 //The number only contains zeroes, so it is 0 00246 out = 0.0; 00247 if(*string == '.' || *string == '\0') 00248 { 00249 return CONV_OK; 00250 } 00251 return CONV_WAR_REDUNANT; 00252 } 00253 //digitcount is 0, there weren't leading zeroes but we stopped at a 00254 //decimal point instead of an invalid character (e.g. .5 instead of X5) 00255 //so the whole number part is still a valid 0 00256 else if(*string == '.') 00257 { 00258 out = 0.0; 00259 return CONV_OK; 00260 } 00261 //we stopped at an invalid character without any digits or leading 00262 //zeroes, so we have an error 00263 else 00264 { 00265 //out is not altered 00266 return CONV_ERR_TYPE; 00267 } 00268 } 00269 00270 ld temp = 0.0; 00271 00272 //parse the digits 00273 ld order_of_magnitude = 1.0; 00274 for(i digit = digitcount - 1; digit >= 0; --digit) 00275 { 00276 temp += digits[digit] * order_of_magnitude; 00277 order_of_magnitude *= 10.0; 00278 } 00279 00280 //overflow will be checked by the caller (we're using long doubles 00281 //temporarily, which are precise enough as we're only parsing the first 00282 //39 digits) 00283 out = temp; 00284 00285 #ifdef MINIINI_DEBUG 00286 if(*string != '.' && *string != '\0') 00287 { 00288 return CONV_WAR_REDUNANT; 00289 } 00290 #endif 00291 return CONV_OK; 00292 } 00293 00309 inline ConversionStatus ParseFloatFraction(const c *& string, ld & out) 00310 { 00311 out = 0.0; 00312 //stores digits of the parsed number (as integers). 00313 //32 bit float can have at most 38 digits after the decimal point. 00314 static i digits [38]; 00315 ui digitcount = 0; 00316 //read digits 00317 while(*string >= '0' && *string <= '9') 00318 { 00319 if(digitcount == 38) 00320 { 00321 break; 00322 } 00323 digits[digitcount] = *string - '0'; 00324 ++digitcount; 00325 ++string; 00326 } 00327 ld temp = 0.0; 00328 00329 //even if there are zero digits, there is no error, fraction is 0.0 00330 00331 //parse digits 00332 ld order_of_magnitude = 0.1; 00333 for(ui digit = 0; digit < digitcount; ++digit) 00334 { 00335 temp += digits[digit] * order_of_magnitude; 00336 order_of_magnitude *= 0.1; 00337 } 00338 00339 out = temp; 00340 00341 #ifdef MINIINI_DEBUG 00342 if(*string != '\0') 00343 { 00344 return CONV_WAR_REDUNANT; 00345 } 00346 #endif 00347 return CONV_OK; 00348 } 00349 00365 inline ConversionStatus ParseFloat(const c * string, f & out) 00366 { 00367 //1 if the number we're parsing is positive, -1 if negative 00368 ld sign = 1.0; 00369 //process sign character, if any 00370 if(*string == '-') 00371 { 00372 sign = -1.0; 00373 ++string; 00374 } 00375 else if(*string == '+') 00376 { 00377 ++string; 00378 } 00379 00380 ld base, fraction; 00381 //First parse the whole number part of the float. 00382 ConversionStatus statbase = ParseFloatBase(string, base); 00383 if(statbase == CONV_ERR_TYPE) 00384 { 00385 return CONV_ERR_TYPE; 00386 } 00387 else if(statbase == CONV_WAR_OVERFLOW) 00388 { 00389 if(sign > 0.0) 00390 { 00391 out = FLT_MAX; 00392 } 00393 else 00394 { 00395 out = -FLT_MAX; 00396 } 00397 return CONV_WAR_OVERFLOW; 00398 } 00399 #ifdef MINIINI_DEBUG 00400 else if(statbase == CONV_WAR_REDUNANT) 00401 { 00402 out = static_cast<f>(sign * base); 00403 return CONV_WAR_REDUNANT; 00404 } 00405 #endif 00406 //there were no warnings but there wasn't a decimal point so we're done 00407 //parsing 00408 if(*string != '.') 00409 { 00410 out = static_cast<f>(sign * base); 00411 return CONV_OK; 00412 } 00413 //skip the decimal point 00414 ++string; 00415 //First parse the fraction part of the float 00416 ConversionStatus statfraction = ParseFloatFraction(string, fraction); 00417 //join the whole number and fraction parts 00418 ld temp = fraction + base; 00419 if(temp > FLT_MAX) 00420 { 00421 temp = FLT_MAX; 00422 out = static_cast<f>(sign * temp); 00423 return CONV_WAR_OVERFLOW; 00424 } 00425 out = static_cast<f>(sign * temp); 00426 #ifdef MINIINI_DEBUG 00427 if(statfraction == CONV_WAR_REDUNANT) 00428 { 00429 return CONV_WAR_REDUNANT; 00430 } 00431 #endif 00432 return CONV_OK; 00433 } 00434 #undef INT32_MAX 00435 #undef INT32_MIN 00436 00437 #undef FOR_10 00438 00439 } 00440 #endif