Overview
Comment: | Use strtof_l, strtod_l and asprintf_l if available
This avoids the hacks introduced in the previous commit, if those |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
0ad678f125615f5a39e51e3f1dd0a0ac |
User & Date: | js on 2017-01-07 03:26:50 |
Other Links: | manifest | tags |
Context
2017-01-07
| ||
22:58 | Use -Wl,--allow-multiple-definition on Windows check-in: 8b2107e238 user: js tags: trunk | |
03:26 | Use strtof_l, strtod_l and asprintf_l if available check-in: 0ad678f125 user: js tags: trunk | |
02:34 | Always use "." for the decimal point check-in: 6dff0f5922 user: js tags: trunk | |
Changes
Modified configure.ac from [a772299926] to [e0038a8dd6].
︙ | ︙ | |||
867 868 869 870 871 872 873 874 875 876 877 878 879 880 | AC_MSG_RESULT(no) ]) OBJCFLAGS="$old_OBJCFLAGS" ]) AC_CHECK_FUNCS([sysconf gmtime_r localtime_r nanosleep fcntl]) AC_CHECK_FUNC(pipe, [ AC_DEFINE(OF_HAVE_PIPE, 1, [Whether we have pipe()]) ]) AC_ARG_ENABLE(sockets, AS_HELP_STRING([--disable-sockets], [disable socket support])) AS_IF([test x"$enable_sockets" != x"no"], [ | > > > | 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 | AC_MSG_RESULT(no) ]) OBJCFLAGS="$old_OBJCFLAGS" ]) AC_CHECK_FUNCS([sysconf gmtime_r localtime_r nanosleep fcntl]) AC_CHECK_HEADERS(xlocale.h) AC_CHECK_FUNCS([strtod_l strtof_l vasprintf_l]) AC_CHECK_FUNC(pipe, [ AC_DEFINE(OF_HAVE_PIPE, 1, [Whether we have pipe()]) ]) AC_ARG_ENABLE(sockets, AS_HELP_STRING([--disable-sockets], [disable socket support])) AS_IF([test x"$enable_sockets" != x"no"], [ |
︙ | ︙ |
Modified src/OFString.m from [2a34be912f] to [011cdaca0e].
︙ | ︙ | |||
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include "config.h" #include <ctype.h> #include <errno.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #import "OFString.h" #import "OFString_UTF8.h" #import "OFString_UTF8+Private.h" #import "OFArray.h" | > > > > > > > | 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #include "config.h" #include <ctype.h> #include <errno.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) # include <locale.h> #endif #ifdef HAVE_XLOCALE_H # include <xlocale.h> #endif #include <sys/stat.h> #import "OFString.h" #import "OFString_UTF8.h" #import "OFString_UTF8+Private.h" #import "OFArray.h" |
︙ | ︙ | |||
62 63 64 65 66 67 68 69 70 71 72 73 74 75 | /* * It seems strtod is buggy on Win32. * However, the MinGW version __strtod seems to be ok. */ #ifdef __MINGW32__ # define strtod __strtod #endif @interface OFString () - (size_t)OF_getCString: (char*)cString maxLength: (size_t)maxLength encoding: (of_string_encoding_t)encoding lossy: (bool)lossy; - (const char*)OF_cStringWithEncoding: (of_string_encoding_t)encoding | > > > > | 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | /* * It seems strtod is buggy on Win32. * However, the MinGW version __strtod seems to be ok. */ #ifdef __MINGW32__ # define strtod __strtod #endif #if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) static locale_t cLocale; #endif @interface OFString () - (size_t)OF_getCString: (char*)cString maxLength: (size_t)maxLength encoding: (of_string_encoding_t)encoding lossy: (bool)lossy; - (const char*)OF_cStringWithEncoding: (of_string_encoding_t)encoding |
︙ | ︙ | |||
497 498 499 500 501 502 503 | OF_DEALLOC_UNSUPPORTED } @end @implementation OFString + (void)initialize { | | > > | > > > > > | 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | OF_DEALLOC_UNSUPPORTED } @end @implementation OFString + (void)initialize { if (self != [OFString class]) return; placeholder.isa = [OFString_placeholder class]; #if defined(HAVE_STRTOF_L) || defined(HAVE_STRTOD_L) if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) @throw [OFInitializationFailedException exception]; #endif } + alloc { if (self == [OFString class]) return (id)&placeholder; |
︙ | ︙ | |||
2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 | return value; } - (float)floatValue { void *pool = objc_autoreleasePoolPush(); OFString *decimalPoint = [OFSystemInfo decimalPoint]; const char *UTF8String = [[self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint] UTF8String]; char *endPointer = NULL; float value; while (*UTF8String == ' ' || *UTF8String == '\t' || *UTF8String == '\n' || *UTF8String == '\r' || *UTF8String == '\f') UTF8String++; value = strtof(UTF8String, &endPointer); /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) if (*endPointer != ' ' && *endPointer != '\t' && *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; } - (double)doubleValue { void *pool = objc_autoreleasePoolPush(); OFString *decimalPoint = [OFSystemInfo decimalPoint]; const char *UTF8String = [[self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint] UTF8String]; char *endPointer = NULL; double value; while (*UTF8String == ' ' || *UTF8String == '\t' || *UTF8String == '\n' || *UTF8String == '\r' || *UTF8String == '\f') UTF8String++; value = strtod(UTF8String, &endPointer); /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) if (*endPointer != ' ' && *endPointer != '\t' && *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') | > > > > > > > > > > > > > > > > > > > > > > > > | 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 | return value; } - (float)floatValue { void *pool = objc_autoreleasePoolPush(); #ifdef HAVE_STRTOF_L const char *UTF8String = [self UTF8String]; #else /* * If we have no strtof_l, we have no other choice but to replace "." * with the locale's decimal point. */ OFString *decimalPoint = [OFSystemInfo decimalPoint]; const char *UTF8String = [[self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint] UTF8String]; #endif char *endPointer = NULL; float value; while (*UTF8String == ' ' || *UTF8String == '\t' || *UTF8String == '\n' || *UTF8String == '\r' || *UTF8String == '\f') UTF8String++; #ifdef HAVE_STRTOF_L value = strtof_l(UTF8String, &endPointer, cLocale); #else value = strtof(UTF8String, &endPointer); #endif /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) if (*endPointer != ' ' && *endPointer != '\t' && *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') @throw [OFInvalidFormatException exception]; objc_autoreleasePoolPop(pool); return value; } - (double)doubleValue { void *pool = objc_autoreleasePoolPush(); #ifdef HAVE_STRTOD_L const char *UTF8String = [self UTF8String]; #else /* * If we have no strtod_l, we have no other choice but to replace "." * with the locale's decimal point. */ OFString *decimalPoint = [OFSystemInfo decimalPoint]; const char *UTF8String = [[self stringByReplacingOccurrencesOfString: @"." withString: decimalPoint] UTF8String]; #endif char *endPointer = NULL; double value; while (*UTF8String == ' ' || *UTF8String == '\t' || *UTF8String == '\n' || *UTF8String == '\r' || *UTF8String == '\f') UTF8String++; #ifdef HAVE_STRTOD_L value = strtod_l(UTF8String, &endPointer, cLocale); #else value = strtod(UTF8String, &endPointer); #endif /* Check if there are any invalid chars left */ if (endPointer != NULL) for (; *endPointer != '\0'; endPointer++) if (*endPointer != ' ' && *endPointer != '\t' && *endPointer != '\n' && *endPointer != '\r' && *endPointer != '\f') |
︙ | ︙ |
Modified src/of_asprintf.m from [91cd8b629a] to [78991846e2].
︙ | ︙ | |||
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <stdbool.h> #include <wchar.h> #include <sys/types.h> #import "OFString.h" #import "OFSystemInfo.h" #define MAX_SUBFORMAT_LEN 64 #ifndef HAVE_ASPRINTF /* * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because * configure determined it is broken. In this case, we must make sure there is | > > > > > > > > > | 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <stdbool.h> #include <wchar.h> #ifdef HAVE_ASPRINTF_L # include <locale.h> #endif #ifdef HAVE_XLOCALE_H # include <xlocale.h> #endif #include <sys/types.h> #import "OFString.h" #import "OFSystemInfo.h" #import "OFInitializationFailedException.h" #define MAX_SUBFORMAT_LEN 64 #ifndef HAVE_ASPRINTF /* * (v)asprintf might be declared, but HAVE_ASPRINTF not defined because * configure determined it is broken. In this case, we must make sure there is |
︙ | ︙ | |||
65 66 67 68 69 70 71 72 73 74 75 76 77 78 | LENGTH_MODIFIER_J, LENGTH_MODIFIER_Z, LENGTH_MODIFIER_T, LENGTH_MODIFIER_CAPITAL_L } lengthModifier; bool useLocale; }; #ifndef HAVE_ASPRINTF static int vasprintf(char **string, const char *format, va_list arguments) { int length; va_list argumentsCopy; | > > > > > > > > > > > | 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | LENGTH_MODIFIER_J, LENGTH_MODIFIER_Z, LENGTH_MODIFIER_T, LENGTH_MODIFIER_CAPITAL_L } lengthModifier; bool useLocale; }; #ifdef HAVE_ASPRINTF_L static locale_t cLocale; static void __attribute__((init)) init(void) { if ((cLocale = newlocale(LC_ALL_MASK, "C", NULL)) == NULL) @throw [OFInitializationFailedException exception]; } #endif #ifndef HAVE_ASPRINTF static int vasprintf(char **string, const char *format, va_list arguments) { int length; va_list argumentsCopy; |
︙ | ︙ | |||
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 | case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: case LENGTH_MODIFIER_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, double)); break; case LENGTH_MODIFIER_CAPITAL_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double)); break; default: return false; } /* | > > > > > > > > > > > > > > > > > > > > > | | | 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 | case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': #ifdef HAVE_ASPRINTF_L { locale_t locale = (ctx->useLocale ? NULL : cLocale); switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: case LENGTH_MODIFIER_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, double), locale); break; case LENGTH_MODIFIER_CAPITAL_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double), locale); break; default: return false; } } #else switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: case LENGTH_MODIFIER_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, double)); break; case LENGTH_MODIFIER_CAPITAL_L: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, long double)); break; default: return false; } /* * If there's no asprintf_l, we have no other choice than to * use this ugly hack to replace the locale's decimal point * back to ".". */ if (!ctx->useLocale) { void *pool = objc_autoreleasePoolPush(); char *tmp2; @try { OFMutableString *tmpStr = [OFMutableString |
︙ | ︙ | |||
532 533 534 535 536 537 538 539 540 541 542 543 544 545 | } @finally { free(tmp); objc_autoreleasePoolPop(pool); } tmp = tmp2; } break; case 'c': switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, int)); | > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | } @finally { free(tmp); objc_autoreleasePoolPop(pool); } tmp = tmp2; } #endif break; case 'c': switch (ctx->lengthModifier) { case LENGTH_MODIFIER_NONE: tmpLen = asprintf(&tmp, ctx->subformat, va_arg(ctx->arguments, int)); |
︙ | ︙ |
Modified tests/OFStringTests.m from [cd4f1dfd47] to [e6c617fc86].
︙ | ︙ | |||
523 524 525 526 527 528 529 530 531 | EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #4", OFInvalidFormatException, [@"$ " hexadecimalValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #1", OFInvalidFormatException, [@"0.0a" floatValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #2", OFInvalidFormatException, [@"0 0" floatValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #1", | > > > > > > > > | | > > > > > > > > | 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 | EXPECT_EXCEPTION(@"Detect invalid chars in -[hexadecimalValue] #4", OFInvalidFormatException, [@"$ " hexadecimalValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #1", OFInvalidFormatException, [@"0.0a" floatValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #2", OFInvalidFormatException, [@"0 0" floatValue]) #ifdef HAVE_STRTOF_L /* * Only do this if we have strtof_l, as the locale might allow the * comma. */ EXPECT_EXCEPTION(@"Detect invalid chars in -[floatValue] #3", OFInvalidFormatException, [@"0,0" floatValue]) #endif EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #1", OFInvalidFormatException, [@"0.0a" doubleValue]) EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #2", OFInvalidFormatException, [@"0 0" doubleValue]) #ifdef HAVE_STRTOD_L /* * Only do this if we have strtod_l, as the locale might allow the * comma. */ EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #3", OFInvalidFormatException, [@"0,0" doubleValue]) #endif EXPECT_EXCEPTION(@"Detect out of range in -[decimalValue]", OFOutOfRangeException, [@"12345678901234567890123456789012345678901234567890" @"12345678901234567890123456789012345678901234567890" decimalValue]) |
︙ | ︙ |