2013-01-16 13:15:38 -05:00
/*
2019-08-02 23:10:55 -04:00
* Copyright ( C ) 2009 - 2016 Paul Davis < paul @ linuxaudiosystems . com >
* Copyright ( C ) 2016 - 2017 Robin Gareus < robin @ gareus . org >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2013-01-16 13:15:38 -05:00
2009-10-28 17:36:40 -04:00
# include <stdlib.h>
# include <string.h>
2016-05-05 14:02:23 -04:00
# include <assert.h>
2009-10-28 17:36:40 -04:00
# include <locale.h>
2016-05-07 06:15:12 -04:00
# include "pbd/compose.h"
# include "pbd/debug.h"
2016-05-05 14:29:28 -04:00
# include "pbd/error.h"
2016-05-07 06:15:12 -04:00
# include "pbd/locale_guard.h"
2009-10-28 17:36:40 -04:00
using namespace PBD ;
2016-07-14 11:35:55 -04:00
/* Neither C nor C++ pick up a user's preferred locale choice without the
* application actively taking steps to make this happen .
*
* For C : setlocale ( LC_ALL , " " ) ;
* For C + + ( assuming that the C version was called ) :
* std : : locale : : global ( std : : locale ( setlocale ( LC_ALL , 0 ) ) ) ;
*
* The application needs to make these calls , probably in main ( ) .
2016-05-05 14:02:23 -04:00
*
* Setting the C + + locale will change the C locale , but not the other way ' round .
* and some plugin may change either behind our back .
*/
2015-01-18 10:43:05 -05:00
2016-05-05 14:02:23 -04:00
LocaleGuard : : LocaleGuard ( )
2016-07-14 11:35:55 -04:00
: old_c_locale ( 0 )
2016-05-05 14:02:23 -04:00
{
2016-07-14 11:35:55 -04:00
/* A LocaleGuard object ensures that the
* LC_NUMERIC / std : : locale : : numeric aspect of the C and C + + locales are
* set to " C " during its lifetime , so that printf / iostreams use a
* portable format for numeric output ( i . e . 1234.5 is always 1234.5 and
* not sometimes 1234 , 5 , as it would be in fr or de locales )
*/
char const * const current_c_locale = setlocale ( LC_NUMERIC , 0 ) ;
if ( strcmp ( " C " , current_c_locale ) ! = 0 ) {
old_c_locale = strdup ( current_c_locale ) ;
2017-04-20 16:11:50 -04:00
setlocale ( LC_NUMERIC , " C " ) ;
pre_cpp_locale = std : : locale ( ) ;
DEBUG_TRACE ( DEBUG : : Locale , string_compose ( " LG: change C locale from '%1' => 'C' (C++ locale is %2) \n " , old_c_locale , pre_cpp_locale . name ( ) ) ) ;
2016-05-05 14:29:28 -04:00
}
2009-10-28 17:36:40 -04:00
}
LocaleGuard : : ~ LocaleGuard ( )
{
2016-07-14 11:35:55 -04:00
char const * current_c_locale = setlocale ( LC_NUMERIC , 0 ) ;
std : : locale current_cpp_locale ;
2010-03-30 11:18:43 -04:00
2016-07-14 11:35:55 -04:00
if ( current_cpp_locale ! = pre_cpp_locale ) {
2017-04-20 16:11:50 -04:00
PBD : : warning < < string_compose ( " LocaleGuard: someone (a plugin) changed the C++ locale from \n \t %1 \n to \n \t %2 \n , expect non-portable session files. Decimal OK ? %3 " ,
2016-07-14 11:35:55 -04:00
old_cpp_locale . name ( ) , current_cpp_locale . name ( ) ,
( std : : use_facet < std : : numpunct < char > > ( std : : locale ( ) ) . decimal_point ( ) = = ' . ' ) )
< < endmsg ;
2016-07-18 10:56:19 -04:00
try {
/* this resets C & C++ locales */
std : : locale : : global ( old_cpp_locale ) ;
DEBUG_TRACE ( DEBUG : : Locale , string_compose ( " LG: restore C & C++ locale: '%1' \n " , std : : locale ( ) . name ( ) ) ) ;
} catch ( . . . ) {
/* see comments in the constructor regarding the
* exception .
*
* This should restore restore numeric handling back to
* the default ( which may reflect user
* preferences ) . This probably can ' t fail , because
* old_c_locale was already in use during the
* constructor for this object .
*
* Still . . . Apple . . . locale support . . . just sayin ' . . . .
*/
setlocale ( LC_NUMERIC , old_c_locale ) ;
DEBUG_TRACE ( DEBUG : : Locale , string_compose ( " LG: C++ locale API failed, restore C locale from %1 to \n '%2' \n (C++ is '%3') \n " , current_c_locale , old_c_locale , std : : locale ( ) . name ( ) ) ) ;
}
2016-07-14 11:35:55 -04:00
2017-04-20 16:11:50 -04:00
}
if ( old_c_locale & & ( strcmp ( current_c_locale , old_c_locale ) ! = 0 ) ) {
2016-07-14 11:35:55 -04:00
/* reset only the C locale */
setlocale ( LC_NUMERIC , old_c_locale ) ;
DEBUG_TRACE ( DEBUG : : Locale , string_compose ( " LG: restore C locale from %1 to \n '%2' \n (C++ is '%3') \n " , current_c_locale , old_c_locale , std : : locale ( ) . name ( ) ) ) ;
2016-05-05 14:02:23 -04:00
}
2016-07-14 11:35:55 -04:00
free ( const_cast < char * > ( old_c_locale ) ) ;
2009-10-28 17:36:40 -04:00
}