ObjFW  Check-in [0ad678f125]

Overview
Comment:Use strtof_l, strtod_l and asprintf_l if available

This avoids the hacks introduced in the previous commit, if those
functions are available.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0ad678f125615f5a39e51e3f1dd0a0ac6465bf58c8f2412641558341983182fd
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
504


505





506
507
508
509
510
511
512
	OF_DEALLOC_UNSUPPORTED
}
@end

@implementation OFString
+ (void)initialize
{
	if (self == [OFString class])


		placeholder.isa = [OFString_placeholder class];





}

+ alloc
{
	if (self == [OFString class])
		return (id)&placeholder;








|
>
>
|
>
>
>
>
>







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

512
513
514
515
516
517
518
519
520
	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;
		}

		/*

		 * Ugly hack to undo locale, as there is nothing such as
		 * asprintf_l in POSIX.
		 */
		if (!ctx->useLocale) {
			void *pool = objc_autoreleasePoolPush();
			char *tmp2;

			@try {
				OFMutableString *tmpStr = [OFMutableString







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>















>
|
|







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
532
533
534








535
536
537
538
539
540
541
	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",
	    OFInvalidFormatException, [@"0.0a" floatValue])
	EXPECT_EXCEPTION(@"Detect invalid chars in -[doubleValue] #2",
	    OFInvalidFormatException, [@"0 0" floatValue])









	EXPECT_EXCEPTION(@"Detect out of range in -[decimalValue]",
	    OFOutOfRangeException,
	    [@"12345678901234567890123456789012345678901234567890"
	     @"12345678901234567890123456789012345678901234567890"
	    decimalValue])








>
>
>
>
>
>
>
>


|

|
>
>
>
>
>
>
>
>







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])