lllocale.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /**
  2. * @file lllocale.cpp
  3. * @brief Localized resource manager
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "linden_common.h"
  33. #include <locale.h>
  34. #include "lllocale.h"
  35. #include "llstring.h"
  36. #if LL_WINDOWS
  37. const std::string LLLocale::USER_LOCALE("English_United States.1252");
  38. const std::string LLLocale::SYSTEM_LOCALE("English_United States.1252");
  39. #elif LL_DARWIN
  40. const std::string LLLocale::USER_LOCALE("en_US.iso8859-1");
  41. const std::string LLLocale::SYSTEM_LOCALE("en_US.iso8859-1");
  42. #else // LL_LINUX likes this
  43. const std::string LLLocale::USER_LOCALE("en_US.utf8");
  44. const std::string LLLocale::SYSTEM_LOCALE("C");
  45. #endif
  46. //static
  47. std::string LLLocale::sPrevFailedLocaleString;
  48. LLLocale::LLLocale(const std::string& locale_string)
  49. {
  50. mPrevLocaleString = setlocale(LC_ALL, NULL);
  51. char* new_locale_string = setlocale(LC_ALL, locale_string.c_str());
  52. if (new_locale_string == NULL && sPrevFailedLocaleString != locale_string)
  53. {
  54. llwarns << "Failed to set locale " << locale_string << llendl;
  55. setlocale(LC_ALL, SYSTEM_LOCALE.c_str());
  56. sPrevFailedLocaleString = locale_string;
  57. }
  58. else
  59. {
  60. LL_DEBUGS("Locale") << "Set locale to " << new_locale_string << llendl;
  61. }
  62. }
  63. LLLocale::~LLLocale()
  64. {
  65. setlocale(LC_ALL, mPrevLocaleString.c_str());
  66. }
  67. //static
  68. char LLLocale::getDecimalPoint()
  69. {
  70. char decimal = localeconv()->decimal_point[0];
  71. #if LL_DARWIN
  72. // On the Mac, locale support is broken before 10.4, which causes things to
  73. // go all pear-shaped.
  74. if (decimal == 0)
  75. {
  76. decimal = '.';
  77. }
  78. #endif
  79. return decimal;
  80. }
  81. //static
  82. char LLLocale::getThousandsSeparator()
  83. {
  84. char separator = localeconv()->thousands_sep[0];
  85. #if LL_DARWIN
  86. // On the Mac, locale support is broken before 10.4, which causes things to
  87. // go all pear-shaped.
  88. if (separator == 0)
  89. {
  90. separator = ',';
  91. }
  92. #endif
  93. return separator;
  94. }
  95. //static
  96. char LLLocale::getMonetaryDecimalPoint()
  97. {
  98. char decimal = localeconv()->mon_decimal_point[0];
  99. #if LL_DARWIN
  100. // On the Mac, locale support is broken before 10.4, which causes things to
  101. // go all pear-shaped.
  102. if (decimal == 0)
  103. {
  104. decimal = '.';
  105. }
  106. #endif
  107. return decimal;
  108. }
  109. //static
  110. char LLLocale::getMonetaryThousandsSeparator()
  111. {
  112. char separator = localeconv()->mon_thousands_sep[0];
  113. #if LL_DARWIN
  114. // On the Mac, locale support is broken before 10.4, which causes things to
  115. // go all pear-shaped.
  116. if (separator == 0)
  117. {
  118. separator = ',';
  119. }
  120. #endif
  121. return separator;
  122. }
  123. // Sets output to a string of integers with monetary separators inserted
  124. // according to the locale.
  125. //static
  126. std::string LLLocale::getMonetaryString(S32 input)
  127. {
  128. std::string output;
  129. LLLocale locale(LLLocale::USER_LOCALE);
  130. struct lconv* conv = localeconv();
  131. #if LL_DARWIN
  132. // On the Mac, locale support is broken before 10.4, which causes things to
  133. // go all pear-shaped.
  134. // Fake up a conv structure with some reasonable values for the fields this
  135. // function uses.
  136. struct lconv fakeconv;
  137. char fake_neg[2] = "-";
  138. char fake_mon_group[4] = "\x03\x03\x00"; // commas every 3 digits
  139. if (conv->negative_sign[0] == 0) // Real locales all seem to have something here...
  140. {
  141. fakeconv = *conv; // start with what's there.
  142. fakeconv.negative_sign = fake_neg;
  143. fakeconv.mon_grouping = fake_mon_group;
  144. fakeconv.n_sign_posn = 1; // negative sign before the string
  145. conv = &fakeconv;
  146. }
  147. #endif
  148. char* negative_sign = conv->negative_sign;
  149. char separator = getMonetaryThousandsSeparator();
  150. char* grouping = conv->mon_grouping;
  151. // Note on mon_grouping:
  152. // Specifies a string that defines the size of each group of digits in
  153. // formatted monetary quantities. The operand for the mon_grouping keyword
  154. // consists of a sequence of semicolon-separated integers. Each integer
  155. // specifies the number of digits in a group. The initial integer defines
  156. // the size of the group immediately to the left of the decimal delimiter.
  157. // The following integers define succeeding groups to the left of the
  158. // previous group. If the last integer is not -1, the size of the previous
  159. // group (if any) is repeatedly used for the remainder of the digits. If
  160. // the last integer is -1, no further grouping is performed.
  161. // Note: we assume here that the currency symbol goes on the left.
  162. bool negative = (input < 0);
  163. bool negative_before = negative && (conv->n_sign_posn != 2);
  164. bool negative_after = negative && (conv->n_sign_posn == 2);
  165. std::string digits = llformat("%u", abs(input));
  166. if (!grouping || !grouping[0])
  167. {
  168. if (negative_before)
  169. {
  170. output.append(negative_sign);
  171. }
  172. output.append(digits);
  173. if (negative_after)
  174. {
  175. output.append(negative_sign);
  176. }
  177. return output;
  178. }
  179. S32 groupings[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  180. S32 cur_group;
  181. for (cur_group = 0; grouping[cur_group]; ++cur_group)
  182. {
  183. if (grouping[cur_group] != ';')
  184. {
  185. groupings[cur_group] = grouping[cur_group];
  186. }
  187. cur_group++;
  188. if (groupings[cur_group] < 0)
  189. {
  190. break;
  191. }
  192. }
  193. S32 group_count = cur_group;
  194. char reversed_output[20] = "";
  195. char forward_output[20] = "";
  196. S32 output_pos = 0;
  197. cur_group = 0;
  198. S32 pos = digits.size() - 1;
  199. S32 count_within_group = 0;
  200. while (pos >= 0 && (groupings[cur_group] >= 0))
  201. {
  202. count_within_group++;
  203. if (count_within_group > groupings[cur_group])
  204. {
  205. count_within_group = 1;
  206. reversed_output[output_pos++] = separator;
  207. if (cur_group + 1 >= group_count)
  208. {
  209. break;
  210. }
  211. else
  212. if (groupings[cur_group + 1] > 0)
  213. {
  214. cur_group++;
  215. }
  216. }
  217. reversed_output[output_pos++] = digits[pos--];
  218. }
  219. while (pos >= 0)
  220. {
  221. reversed_output[output_pos++] = digits[pos--];
  222. }
  223. reversed_output[output_pos] = '\0';
  224. forward_output[output_pos] = '\0';
  225. for (S32 i = 0; i < output_pos; ++i)
  226. {
  227. forward_output[output_pos - 1 - i] = reversed_output[i];
  228. }
  229. if (negative_before)
  230. {
  231. output.append(negative_sign);
  232. }
  233. output.append(forward_output);
  234. if (negative_after)
  235. {
  236. output.append(negative_sign);
  237. }
  238. return output;
  239. }
  240. //static
  241. void LLLocale::getIntegerString(std::string& output, S32 input)
  242. {
  243. output.clear();
  244. std::string fraction_string;
  245. while (input > 0)
  246. {
  247. S32 fraction = input % 1000;
  248. if (!output.empty())
  249. {
  250. if (fraction == input)
  251. {
  252. fraction_string = llformat("%d%c", fraction,
  253. getThousandsSeparator());
  254. }
  255. else
  256. {
  257. fraction_string = llformat("%3.3d%c", fraction,
  258. getThousandsSeparator());
  259. }
  260. output = fraction_string + output;
  261. }
  262. else
  263. {
  264. if (fraction == input)
  265. {
  266. fraction_string = llformat("%d", fraction);
  267. }
  268. else
  269. {
  270. fraction_string = llformat("%3.3d", fraction);
  271. }
  272. output = fraction_string;
  273. }
  274. input /= 1000;
  275. }
  276. }