/** * @file llresmgr.cpp * @brief Localized resource manager * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ // NOTE: this is a MINIMAL implementation. The interface will remain, but the implementation will // (when the time is right) become dynamic and probably use external files. #include "linden_common.h" #include "llresmgr.h" #include "llfontgl.h" #include "llerror.h" #include "llstring.h" LLResMgr::LLResMgr() { // Set default setLocale( LLLOCALE_USA ); } void LLResMgr::setLocale( LLLOCALE_ID locale_id ) { mLocale = locale_id; } char LLResMgr::getDecimalPoint() const { char decimal = localeconv()->decimal_point[0]; return decimal; } char LLResMgr::getThousandsSeparator() const { char separator = localeconv()->thousands_sep[0]; return separator; } char LLResMgr::getMonetaryDecimalPoint() const { char decimal = localeconv()->mon_decimal_point[0]; return decimal; } char LLResMgr::getMonetaryThousandsSeparator() const { char separator = localeconv()->mon_thousands_sep[0]; return separator; } // Sets output to a string of integers with monetary separators inserted according to the locale. std::string LLResMgr::getMonetaryString( S32 input ) const { std::string output; LLLocale locale(LLLocale::USER_LOCALE); struct lconv *conv = localeconv(); char* negative_sign = conv->negative_sign; char separator = getMonetaryThousandsSeparator(); char* grouping = conv->mon_grouping; // Note on mon_grouping: // Specifies a string that defines the size of each group of digits in formatted monetary quantities. // The operand for the mon_grouping keyword consists of a sequence of semicolon-separated integers. // Each integer specifies the number of digits in a group. The initial integer defines the size of // the group immediately to the left of the decimal delimiter. The following integers define succeeding // groups to the left of the previous group. If the last integer is not -1, the size of the previous // group (if any) is repeatedly used for the remainder of the digits. If the last integer is -1, no // further grouping is performed. // Note: we assume here that the currency symbol goes on the left. (Hey, it's Lindens! We can just decide.) bool negative = (input < 0 ); bool negative_before = negative && (conv->n_sign_posn != 2); bool negative_after = negative && (conv->n_sign_posn == 2); std::string digits = llformat("%u", abs(input)); if( !grouping || !grouping[0] ) { if( negative_before ) { output.append( negative_sign ); } output.append( digits ); if( negative_after ) { output.append( negative_sign ); } return output; } S32 groupings[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; S32 cur_group; for( cur_group = 0; grouping[ cur_group ]; cur_group++ ) { if( grouping[ cur_group ] != ';' ) { groupings[cur_group] = grouping[ cur_group ]; } cur_group++; if( groupings[cur_group] < 0 ) { break; } } S32 group_count = cur_group; char reversed_output[20] = ""; /* Flawfinder: ignore */ char forward_output[20] = ""; /* Flawfinder: ignore */ S32 output_pos = 0; cur_group = 0; S32 pos = static_cast(digits.size()) - 1; S32 count_within_group = 0; while( (pos >= 0) && (groupings[cur_group] >= 0) ) { count_within_group++; if( count_within_group > groupings[cur_group] ) { count_within_group = 1; reversed_output[ output_pos++ ] = separator; if( (cur_group + 1) >= group_count ) { break; } else if( groupings[cur_group + 1] > 0 ) { cur_group++; } } reversed_output[ output_pos++ ] = digits[pos--]; } while( pos >= 0 ) { reversed_output[ output_pos++ ] = digits[pos--]; } reversed_output[ output_pos ] = '\0'; forward_output[ output_pos ] = '\0'; for( S32 i = 0; i < output_pos; i++ ) { forward_output[ output_pos - 1 - i ] = reversed_output[ i ]; } if( negative_before ) { output.append( negative_sign ); } output.append( forward_output ); if( negative_after ) { output.append( negative_sign ); } return output; } void LLResMgr::getIntegerString( std::string& output, S32 input ) const { // handle special case of input value being zero if (input == 0) { output = "0"; return; } // *NOTE: this method does not handle negative input integers correctly S32 fraction = 0; std::string fraction_string; S32 remaining_count = input; while(remaining_count > 0) { fraction = (remaining_count) % 1000; if (!output.empty()) { if (fraction == remaining_count) { fraction_string = llformat_to_utf8("%d%c", fraction, getThousandsSeparator()); } else { fraction_string = llformat_to_utf8("%3.3d%c", fraction, getThousandsSeparator()); } output = fraction_string + output; } else { if (fraction == remaining_count) { fraction_string = llformat("%d", fraction); } else { fraction_string = llformat("%3.3d", fraction); } output = fraction_string; } remaining_count /= 1000; } } #if LL_WINDOWS const std::string LLLocale::USER_LOCALE("English_United States.1252");// = LLStringUtil::null; const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252"); #elif LL_DARWIN const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");// = LLStringUtil::null; const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1"); #else // LL_LINUX likes this const std::string LLLocale::USER_LOCALE("en_US.utf8"); const std::string LLLocale::SYSTEM_LOCALE("C"); #endif LLLocale::LLLocale(const std::string& locale_string) { mPrevLocaleString = setlocale( LC_ALL, NULL ); char* new_locale_string = setlocale( LC_ALL, locale_string.c_str()); if ( new_locale_string == NULL) { LL_WARNS_ONCE("LLLocale") << "Failed to set locale " << locale_string << LL_ENDL; setlocale(LC_ALL, SYSTEM_LOCALE.c_str()); } //else //{ // LL_INFOS() << "Set locale to " << new_locale_string << LL_ENDL; //} } LLLocale::~LLLocale() { setlocale( LC_ALL, mPrevLocaleString.c_str() ); }