| 315 | |
| 316 | |
| 317 | SymbolType IsNumeric(LPCTSTR aBuf, BOOL aAllowNegative, BOOL aAllowAllWhitespace |
| 318 | , BOOL aAllowFloat, BOOL aAllowImpure) // BOOL vs. bool might squeeze a little more performance out of this frequently-called function. |
| 319 | // String can contain whitespace. |
| 320 | // If aBuf doesn't contain something purely numeric, PURE_NOT_NUMERIC is returned. The same happens if |
| 321 | // aBuf contains a float but aAllowFloat is false. (The aAllowFloat parameter isn't strictly necessary |
| 322 | // because the caller could just check whether the return value is/isn't PURE_FLOAT to get the same effect. |
| 323 | // However, supporting aAllowFloat seems to greatly improve maintainability because it saves many callers |
| 324 | // from having to compare the return value to PURE_INTEGER [they can just interpret the return value as BOOL]. |
| 325 | // It also improves readability due to the "Is" part of the function name. So it seems worth keeping.) |
| 326 | // Otherwise, PURE_INTEGER or PURE_FLOAT is returned. |
| 327 | // If aAllowAllWhitespace==true and the string is blank or all whitespace, PURE_INTEGER is returned. |
| 328 | // Obsolete comment: Making this non-inline reduces the size of the compressed EXE by only 2K. Since this |
| 329 | // function is called so often, it seems preferable to keep it inline for performance. |
| 330 | { |
| 331 | aBuf = omit_leading_whitespace(aBuf); // i.e. caller doesn't have to have ltrimmed, only rtrimmed. |
| 332 | if (!*aBuf) // The string is empty or consists entirely of whitespace. |
| 333 | return aAllowAllWhitespace ? PURE_INTEGER : PURE_NOT_NUMERIC; |
| 334 | |
| 335 | if (*aBuf == '-') |
| 336 | { |
| 337 | if (aAllowNegative) |
| 338 | ++aBuf; |
| 339 | else |
| 340 | return PURE_NOT_NUMERIC; |
| 341 | } |
| 342 | else if (*aBuf == '+') |
| 343 | ++aBuf; |
| 344 | |
| 345 | // Relies on short circuit boolean order to prevent reading beyond the end of the string: |
| 346 | BOOL is_hex = IS_HEX(aBuf); // BOOL vs. bool might squeeze a little more performance out this frequently-called function. |
| 347 | if (is_hex) |
| 348 | aBuf += 2; // Skip over the 0x prefix. |
| 349 | |
| 350 | // Set defaults: |
| 351 | BOOL has_decimal_point = false; |
| 352 | BOOL has_exponent = false; |
| 353 | BOOL has_at_least_one_digit = false; // i.e. a string consisting of only "+", "-" or "." is not considered numeric. |
| 354 | int c; // int vs. char might squeeze a little more performance out of it (it does reduce code size by 5 bytes). Probably must stay signed vs. unsigned for some of the uses below. |
| 355 | |
| 356 | for (;; ++aBuf) |
| 357 | { |
| 358 | c = *aBuf; |
| 359 | if (IS_SPACE_OR_TAB(c)) |
| 360 | { |
| 361 | if (*omit_leading_whitespace(aBuf)) // But that space or tab is followed by something other than whitespace. |
| 362 | if (!aAllowImpure) // e.g. "123 456" is not a valid pure number. |
| 363 | return PURE_NOT_NUMERIC; |
| 364 | // else fall through to the bottom logic. |
| 365 | // else since just whitespace at the end, the number qualifies as pure, so fall through to the bottom |
| 366 | // logic (it would already have returned in the loop if it was impure) |
| 367 | break; |
| 368 | } |
| 369 | if (!c) // End of string was encountered. |
| 370 | break; // The number qualifies as pure, so fall through to the logic at the bottom. (It would already have returned elsewhere in the loop if the number is impure). |
| 371 | if (c == '.') |
| 372 | { |
| 373 | if (!aAllowFloat || has_decimal_point || is_hex) // If aAllowFloat==false, a decimal point at the very end of the number is considered non-numeric even if aAllowImpure==true. Some callers might rely on this. |
| 374 | // i.e. if aBuf contains 2 decimal points, it can't be a valid number. |
no test coverage detected