33 * \brief Property class definition
44 * \see mlt_property_s
55 *
6- * Copyright (C) 2003-2024 Meltytech, LLC
6+ * Copyright (C) 2003-2025 Meltytech, LLC
77 *
88 * This library is free software; you can redistribute it and/or
99 * modify it under the terms of the GNU Lesser General Public
3737#include <stdlib.h>
3838#include <string.h>
3939
40+ // Platforms with native strtod_l support
41+ #if defined(__GLIBC__ ) || defined(__APPLE__ ) || (defined(HAVE_STRTOD_L ) && !defined(__OpenBSD__ ))
42+ #define HAVE_LOCALE_STRTOD_L 1
43+ #endif
44+
45+ // Platforms requiring manual locale handling (excluding Windows)
46+ #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
47+ && !defined(__OpenBSD__ )
48+ #define NEED_LOCALE_SAVE_RESTORE 1
49+ #endif
50+
4051/** Bit pattern used internally to indicated representations available.
4152*/
4253
@@ -318,8 +329,7 @@ static int time_clock_to_frames(mlt_property self, const char *s, double fps, ml
318329 s = copy ;
319330 pos = strrchr (s , ':' );
320331
321- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
322- && !defined(__OpenBSD__ )
332+ #ifdef NEED_LOCALE_SAVE_RESTORE
323333 char * orig_localename = NULL ;
324334 if (locale ) {
325335 // Protect damaging the global locale from a temporary locale on another thread.
@@ -334,7 +344,7 @@ static int time_clock_to_frames(mlt_property self, const char *s, double fps, ml
334344#endif
335345
336346 if (pos ) {
337- #if defined( __GLIBC__ ) || defined( __APPLE__ ) || defined( HAVE_STRTOD_L ) && !defined( __OpenBSD__ )
347+ #ifdef HAVE_LOCALE_STRTOD_L
338348 if (locale )
339349 seconds = strtod_l (pos + 1 , NULL , locale );
340350 else
@@ -350,16 +360,15 @@ static int time_clock_to_frames(mlt_property self, const char *s, double fps, ml
350360 minutes = atoi (s );
351361 }
352362 } else {
353- #if defined( __GLIBC__ ) || defined( __APPLE__ ) || defined( HAVE_STRTOD_L ) && !defined( __OpenBSD__ )
363+ #ifdef HAVE_LOCALE_STRTOD_L
354364 if (locale )
355365 seconds = strtod_l (s , NULL , locale );
356366 else
357367#endif
358368 seconds = strtod (s , NULL );
359369 }
360370
361- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
362- && !defined(__OpenBSD__ )
371+ #ifdef NEED_LOCALE_SAVE_RESTORE
363372 if (locale ) {
364373 // Restore the current locale
365374 setlocale (LC_NUMERIC , orig_localename );
@@ -513,22 +522,47 @@ int mlt_property_get_int(mlt_property self, double fps, mlt_locale_t locale)
513522static double mlt_property_atof (mlt_property self , double fps , mlt_locale_t locale )
514523{
515524 const char * value = self -> prop_string ;
525+ #ifdef NEED_LOCALE_SAVE_RESTORE
526+ char * orig_localename = NULL ;
527+ #endif
516528
517529 if (fps > 0 && strchr (value , ':' )) {
530+ #ifdef NEED_LOCALE_SAVE_RESTORE
531+ if (locale ) {
532+ // Protect damaging the global locale from a temporary locale on another thread.
533+ pthread_mutex_lock (& self -> mutex );
534+
535+ // Get the current locale
536+ orig_localename = strdup (setlocale (LC_NUMERIC , NULL ));
537+
538+ // Set the new locale
539+ setlocale (LC_NUMERIC , locale );
540+ }
541+ #endif
542+ double result ;
518543 if (strchr (value , '.' ) || strchr (value , ',' ))
519- return time_clock_to_frames (self , value , fps , locale );
544+ result = time_clock_to_frames (self , value , fps , locale );
520545 else
521- return time_code_to_frames (self , value , fps );
546+ result = time_code_to_frames (self , value , fps );
547+
548+ #ifdef NEED_LOCALE_SAVE_RESTORE
549+ if (locale ) {
550+ // Restore the current locale
551+ setlocale (LC_NUMERIC , orig_localename );
552+ free (orig_localename );
553+ pthread_mutex_unlock (& self -> mutex );
554+ }
555+ #endif
556+ return result ;
522557 } else {
523558 char * end = NULL ;
524559 double result ;
525560
526- #if defined( __GLIBC__ ) || defined( __APPLE__ ) || defined( HAVE_STRTOD_L ) && !defined( __OpenBSD__ )
561+ #ifdef HAVE_LOCALE_STRTOD_L
527562 if (locale )
528563 result = strtod_l (value , & end , locale );
529564 else
530565#elif !defined(_WIN32 )
531- char * orig_localename = NULL ;
532566 if (locale ) {
533567 // Protect damaging the global locale from a temporary locale on another thread.
534568 pthread_mutex_lock (& self -> mutex );
@@ -545,8 +579,7 @@ static double mlt_property_atof(mlt_property self, double fps, mlt_locale_t loca
545579 if (end && end [0 ] == '%' )
546580 result /= 100.0 ;
547581
548- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
549- && !defined(__OpenBSD__ )
582+ #ifdef NEED_LOCALE_SAVE_RESTORE
550583 if (locale ) {
551584 // Restore the current locale
552585 setlocale (LC_NUMERIC , orig_localename );
@@ -1156,13 +1189,15 @@ int mlt_property_is_numeric(mlt_property self, mlt_locale_t locale)
11561189 // If not already numeric but string is numeric.
11571190 if ((!result && self -> types & mlt_prop_string ) && self -> prop_string ) {
11581191 char * p = NULL ;
1192+ #ifdef NEED_LOCALE_SAVE_RESTORE
1193+ char * orig_localename = NULL ;
1194+ #endif
11591195
1160- #if defined( __GLIBC__ ) || defined( __APPLE__ ) || defined( HAVE_STRTOD_L ) && !defined( __OpenBSD__ )
1196+ #ifdef HAVE_LOCALE_STRTOD_L
11611197 if (locale )
11621198 strtod_l (self -> prop_string , & p , locale );
11631199 else
11641200#elif !defined(_WIN32 )
1165- char * orig_localename = NULL ;
11661201 if (locale ) {
11671202 // Protect damaging the global locale from a temporary locale on another thread.
11681203 pthread_mutex_lock (& self -> mutex );
@@ -1177,8 +1212,7 @@ int mlt_property_is_numeric(mlt_property self, mlt_locale_t locale)
11771212
11781213 strtod (self -> prop_string , & p );
11791214
1180- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
1181- && !defined(__OpenBSD__ )
1215+ #ifdef NEED_LOCALE_SAVE_RESTORE
11821216 if (locale ) {
11831217 // Restore the current locale
11841218 setlocale (LC_NUMERIC , orig_localename );
@@ -1893,8 +1927,7 @@ mlt_rect mlt_property_get_rect(mlt_property self, mlt_locale_t locale)
18931927 char * p = NULL ;
18941928 int count = 0 ;
18951929
1896- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
1897- && !defined(__OpenBSD__ )
1930+ #ifdef NEED_LOCALE_SAVE_RESTORE
18981931 char * orig_localename = NULL ;
18991932 if (locale ) {
19001933 // Protect damaging the global locale from a temporary locale on another thread.
@@ -1910,7 +1943,7 @@ mlt_rect mlt_property_get_rect(mlt_property self, mlt_locale_t locale)
19101943
19111944 while (* value ) {
19121945 double temp ;
1913- #if defined( __GLIBC__ ) || defined( __APPLE__ ) || defined( HAVE_STRTOD_L ) && !defined( __OpenBSD__ )
1946+ #ifdef HAVE_LOCALE_STRTOD_L
19141947 if (locale )
19151948 temp = strtod_l (value , & p , locale );
19161949 else
@@ -1951,8 +1984,7 @@ mlt_rect mlt_property_get_rect(mlt_property self, mlt_locale_t locale)
19511984 count ++ ;
19521985 }
19531986
1954- #if !defined(__GLIBC__ ) && !defined(__APPLE__ ) && !defined(_WIN32 ) && !defined(HAVE_STRTOD_L ) \
1955- && !defined(__OpenBSD__ )
1987+ #ifdef NEED_LOCALE_SAVE_RESTORE
19561988 if (locale ) {
19571989 // Restore the current locale
19581990 setlocale (LC_NUMERIC , orig_localename );
0 commit comments