OSDN Git Service

Shell Extension for Windows 11 or later (5)
[winmerge-jp/winmerge-jp.git] / Src / locality.cpp
1 /** 
2  * @file  locality.cpp
3  *
4  * @brief Implementation of helper functions involving locale
5  */
6
7 #include "pch.h"
8 #include "locality.h"
9 #include <windows.h>
10 #include <Poco/Format.h>
11 #include <Poco/Debugger.h>
12 #include <Poco/Timestamp.h>
13
14 using Poco::format;
15 using Poco::Debugger;
16 using Poco::Timestamp;
17
18 namespace locality {
19
20 /**
21  * @brief Get numeric value from an LC_ entry in windows locale (NLS) database
22  */
23 static unsigned getLocaleUint(int lctype, int defval)
24 {
25         TCHAR buff[64];
26         if (!GetLocaleInfo(LOCALE_USER_DEFAULT, lctype, buff, sizeof(buff)/sizeof(buff[0])))
27                 return defval;
28         return _ttol(buff);
29         
30 }
31
32 /**
33  * @brief Get numeric value for LOCALE_SGROUPING
34  */
35 static unsigned GetLocaleGrouping(int defval)
36 {
37         TCHAR buff[64];
38         if (!GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, buff, sizeof(buff)/sizeof(buff[0])))
39                 return defval;
40         // handling for Indic 3;2
41         if (!_tcscmp(buff, _T("3;2;0")))
42                 return 32;
43         return _ttol(buff);
44 }
45
46 /**
47  * @brief Print an integer into a CString, in appropriate fashion for locale & user preferences
48  *
49  * NB: We are not converting digits from ASCII via LOCALE_SNATIVEDIGITS
50  *   So we always use ASCII digits, instead of, eg, the Chinese digits
51  *
52  * @param [in] n Number to convert.
53  * @return Converted string.
54  */
55 String NumToLocaleStr(int n)
56 {
57         TCHAR numbuff[34];
58         _ltot_s(n, numbuff, 10);
59         return GetLocaleStr(numbuff);
60 }
61
62 /**
63  * @brief Print an integer into a CString, in appropriate fashion for locale & user preferences
64  *
65  * NB: We are not converting digits from ASCII via LOCALE_SNATIVEDIGITS
66  *   So we always use ASCII digits, instead of, eg, the Chinese digits
67  *
68  * @param [in] n Number to convert.
69  * @return Converted string.
70  */
71 String NumToLocaleStr(int64_t n)
72 {
73         TCHAR numbuff[34];
74         _i64tot_s(n, numbuff, sizeof(numbuff)/sizeof(TCHAR), 10);
75         return GetLocaleStr(numbuff);
76 }
77
78 /**
79  * @brief Insert commas (or periods) into string, as appropriate for locale & preferences
80  *
81  * NB: We are not converting digits from ASCII via LOCALE_SNATIVEDIGITS
82  *   So we always use ASCII digits, instead of, eg, the Chinese digits
83  */
84 String GetLocaleStr(const TCHAR *str, int decimalDigits)
85 {
86         // Fill in currency format with locale info
87         // except we hardcode for no decimal
88         TCHAR DecimalSep[8];
89         TCHAR SepDefault[] = _T(".");
90         TCHAR ThousandSep[8];
91         NUMBERFMT NumFormat = { 0 };
92         NumFormat.NumDigits = decimalDigits; // LOCALE_IDIGITS
93         NumFormat.LeadingZero = getLocaleUint(LOCALE_ILZERO, 0);
94         NumFormat.Grouping = GetLocaleGrouping(3);
95         NumFormat.lpDecimalSep = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL, DecimalSep, 8) ? DecimalSep : SepDefault;
96         NumFormat.lpThousandSep = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, ThousandSep, 8) ? ThousandSep : SepDefault;
97         NumFormat.NegativeOrder = getLocaleUint(LOCALE_INEGNUMBER , 0);
98         String out;
99         out.resize(48);
100         LPTSTR outbuff = &*out.begin(); //GetBuffer(48);
101         int rt = GetNumberFormat(LOCALE_USER_DEFAULT // a predefined value for user locale
102                 , 0                // operation option (allow overrides)
103                 , str              // input number (see MSDN for legal chars)
104                 , &NumFormat           // formatting specifications
105                 , outbuff             // output buffer
106                 , 48
107                 );             // size of output buffer
108         if (rt)
109         {
110                 // rt includes terminating zero
111                 out.resize(rt - 1);
112         }
113         else
114         {
115                 Debugger::message(format("Error %d in NumToStr()\n", GetLastError()));
116                 out = str;
117         }
118         return out;
119 }
120
121 /**
122  * @brief Convert unix time to string to show in the GUI.
123  * @param [in] tim Time in seconds since 1.1.1970.
124  * @return Time as a string, proper to show in the GUI.
125  */
126 String TimeString(const int64_t * tim)
127 {
128         if (tim == nullptr) return _T("---");
129         
130         SYSTEMTIME sysTimeGlobal, sysTime;
131         FILETIME ft;
132         Timestamp t(*tim * Timestamp::resolution());
133
134         if (t == 0)
135                 return String();
136         t.toFileTimeNP((unsigned int&)ft.dwLowDateTime, (unsigned int&)ft.dwHighDateTime);
137         if (!FileTimeToSystemTime(&ft, &sysTimeGlobal) ||
138             !SystemTimeToTzSpecificLocalTime(nullptr, &sysTimeGlobal, &sysTime))
139                 return _T("---");
140
141         TCHAR buff[128];
142         int len = GetDateFormat(LOCALE_USER_DEFAULT, 0, &sysTime, nullptr, buff, sizeof(buff)/sizeof(buff[0]));
143         buff[len - 1] = ' ';
144         GetTimeFormat(LOCALE_USER_DEFAULT, 0, &sysTime, nullptr, buff + len, sizeof(buff)/sizeof(buff[0]) - len - 1);
145         return buff;
146 }
147
148 }; // namespace locality