Skip to content

Commit 27181e3

Browse files
committed
ICU-22435 Add C API for Locale
See #2531
1 parent 81a6edb commit 27181e3

14 files changed

+633
-4
lines changed

icu4c/source/common/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,7 @@ cc_library(
609609
"uloc.cpp",
610610
"uloc_tag.cpp",
611611
"uloc_keytype.cpp",
612+
"ulocale.cpp",
612613
"ulocbuilder.cpp",
613614
"uresbund.cpp",
614615
"uresdata.cpp",

icu4c/source/common/common.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@
186186
<ClCompile Include="ucat.cpp" />
187187
<ClCompile Include="uloc.cpp" />
188188
<ClCompile Include="uloc_tag.cpp" />
189+
<ClCompile Include="ulocale.cpp" />
189190
<ClCompile Include="ures_cnv.cpp" />
190191
<ClCompile Include="uresbund.cpp" />
191192
<ClCompile Include="uresdata.cpp" />

icu4c/source/common/common.vcxproj.filters

+6
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,9 @@
376376
<ClCompile Include="uloc_tag.cpp">
377377
<Filter>locales &amp; resources</Filter>
378378
</ClCompile>
379+
<ClCompile Include="ulocale.cpp">
380+
<Filter>locales &amp; resources</Filter>
381+
</ClCompile>
379382
<ClCompile Include="ures_cnv.cpp">
380383
<Filter>locales &amp; resources</Filter>
381384
</ClCompile>
@@ -1153,6 +1156,9 @@
11531156
<CustomBuild Include="unicode\uloc.h">
11541157
<Filter>locales &amp; resources</Filter>
11551158
</CustomBuild>
1159+
<CustomBuild Include="unicode\ulocale.h">
1160+
<Filter>locales &amp; resources</Filter>
1161+
</CustomBuild>
11561162
<CustomBuild Include="unicode\ures.h">
11571163
<Filter>locales &amp; resources</Filter>
11581164
</CustomBuild>

icu4c/source/common/common_uwp.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@
320320
<ClCompile Include="ucat.cpp" />
321321
<ClCompile Include="uloc.cpp" />
322322
<ClCompile Include="uloc_tag.cpp" />
323+
<ClCompile Include="ulocale.cpp" />
323324
<ClCompile Include="ures_cnv.cpp" />
324325
<ClCompile Include="uresbund.cpp" />
325326
<ClCompile Include="uresdata.cpp" />

icu4c/source/common/sources.txt

+1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ ulist.cpp
139139
uloc.cpp
140140
uloc_keytype.cpp
141141
uloc_tag.cpp
142+
ulocale.cpp
142143
ulocbuilder.cpp
143144
umapfile.cpp
144145
umath.cpp

icu4c/source/common/ulocale.cpp

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// © 2023 and later: Unicode, Inc. and others.
2+
// License & terms of use: http://www.unicode.org/copyright.html
3+
//
4+
#include "unicode/errorcode.h"
5+
#include "unicode/stringpiece.h"
6+
#include "unicode/utypes.h"
7+
#include "unicode/ustring.h"
8+
#include "unicode/ulocale.h"
9+
#include "unicode/locid.h"
10+
11+
#include "charstr.h"
12+
#include "cmemory.h"
13+
14+
U_NAMESPACE_USE
15+
#define EXTERNAL(i) (reinterpret_cast<ULocale*>(i))
16+
#define CONST_INTERNAL(e) (reinterpret_cast<const icu::Locale*>(e))
17+
#define INTERNAL(e) (reinterpret_cast<icu::Locale*>(e))
18+
19+
ULocale*
20+
ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err) {
21+
CharString str(length < 0 ? StringPiece(localeID) : StringPiece(localeID, length), *err);
22+
if (U_FAILURE(*err)) return nullptr;
23+
return EXTERNAL(icu::Locale::createFromName(str.data()).clone());
24+
}
25+
26+
ULocale*
27+
ulocale_openForLanguageTag(const char* tag, int32_t length, UErrorCode* err) {
28+
Locale l = icu::Locale::forLanguageTag(length < 0 ? StringPiece(tag) : StringPiece(tag, length), *err);
29+
if (U_FAILURE(*err)) return nullptr;
30+
return EXTERNAL(l.clone());
31+
}
32+
33+
void
34+
ulocale_close(ULocale* locale) {
35+
delete INTERNAL(locale);
36+
}
37+
38+
#define IMPL_ULOCALE_STRING_GETTER(N1, N2) \
39+
const char* ulocale_get ## N1(const ULocale* locale) { \
40+
if (locale == nullptr) return nullptr; \
41+
return CONST_INTERNAL(locale)->get ## N2(); \
42+
}
43+
44+
#define IMPL_ULOCALE_STRING_IDENTICAL_GETTER(N) IMPL_ULOCALE_STRING_GETTER(N, N)
45+
46+
#define IMPL_ULOCALE_GET_KEYWORD_VALUE(N) \
47+
int32_t ulocale_get ##N ( \
48+
const ULocale* locale, const char* keyword, int32_t keywordLength, \
49+
char* valueBuffer, int32_t bufferCapacity, UErrorCode *err) { \
50+
if (U_FAILURE(*err)) return 0; \
51+
if (locale == nullptr) { \
52+
*err = U_ILLEGAL_ARGUMENT_ERROR; \
53+
return 0; \
54+
} \
55+
CheckedArrayByteSink sink(valueBuffer, bufferCapacity); \
56+
CONST_INTERNAL(locale)->get ## N( \
57+
keywordLength < 0 ? StringPiece(keyword) : StringPiece(keyword, keywordLength), \
58+
sink, *err); \
59+
if (U_FAILURE(*err)) return 0; \
60+
if (sink.Overflowed()) { \
61+
*err = U_BUFFER_OVERFLOW_ERROR; \
62+
return sink.NumberOfBytesAppended()+1; \
63+
} \
64+
int32_t len = sink.NumberOfBytesWritten(); \
65+
if (len < bufferCapacity) valueBuffer[len] = '\0'; \
66+
return len; \
67+
}
68+
69+
#define IMPL_ULOCALE_GET_KEYWORDS(N) \
70+
UEnumeration* ulocale_get ## N(const ULocale* locale, UErrorCode *err) { \
71+
if (U_FAILURE(*err)) return nullptr; \
72+
if (locale == nullptr) { \
73+
*err = U_ILLEGAL_ARGUMENT_ERROR; \
74+
return nullptr; \
75+
} \
76+
return uenum_openFromStringEnumeration( \
77+
CONST_INTERNAL(locale)->create ## N(*err), err); \
78+
}
79+
80+
IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Language)
81+
IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Script)
82+
IMPL_ULOCALE_STRING_GETTER(Region, Country)
83+
IMPL_ULOCALE_STRING_IDENTICAL_GETTER(Variant)
84+
IMPL_ULOCALE_STRING_GETTER(LocaleID, Name)
85+
IMPL_ULOCALE_STRING_IDENTICAL_GETTER(BaseName)
86+
IMPL_ULOCALE_GET_KEYWORD_VALUE(KeywordValue)
87+
IMPL_ULOCALE_GET_KEYWORD_VALUE(UnicodeKeywordValue)
88+
IMPL_ULOCALE_GET_KEYWORDS(Keywords)
89+
IMPL_ULOCALE_GET_KEYWORDS(UnicodeKeywords)
90+
91+
bool ulocale_isBogus(const ULocale* locale) {
92+
if (locale == nullptr) return false;
93+
return CONST_INTERNAL(locale)->isBogus();
94+
}
95+
96+
/*eof*/

icu4c/source/common/ulocbuilder.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@
1414
using icu::CheckedArrayByteSink;
1515
using icu::StringPiece;
1616

17-
#define EXTERNAL(i) ((ULocaleBuilder*)(i))
18-
#define INTERNAL(e) ((icu::LocaleBuilder*)(e))
17+
#define EXTERNAL(i) (reinterpret_cast<ULocaleBuilder*>(i))
18+
#define INTERNAL(e) (reinterpret_cast<icu::LocaleBuilder*>(e))
19+
#define CONST_INTERNAL(e) (reinterpret_cast<const icu::LocaleBuilder*>(e))
1920

2021
ULocaleBuilder* ulocbld_open() {
2122
return EXTERNAL(new icu::LocaleBuilder());
@@ -141,5 +142,5 @@ UBool ulocbld_copyErrorTo(const ULocaleBuilder* builder, UErrorCode *outErrorCod
141142
*outErrorCode = U_ILLEGAL_ARGUMENT_ERROR;
142143
return true;
143144
}
144-
return INTERNAL(builder)->copyErrorTo(*outErrorCode);
145+
return CONST_INTERNAL(builder)->copyErrorTo(*outErrorCode);
145146
}

icu4c/source/common/unicode/ulocale.h

+229
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// © 2023 and later: Unicode, Inc. and others.
2+
// License & terms of use: http://www.unicode.org/copyright.html
3+
4+
#ifndef ULOCALE_H
5+
#define ULOCALE_H
6+
7+
#include "unicode/localpointer.h"
8+
#include "unicode/uenum.h"
9+
#include "unicode/utypes.h"
10+
11+
/**
12+
* \file
13+
* \brief C API: Locale ID functionality similar to C++ class Locale
14+
*/
15+
16+
#ifndef U_HIDE_DRAFT_API
17+
/**
18+
* Opaque C service object type for the locale API
19+
* @draft ICU 74
20+
*/
21+
struct ULocale;
22+
23+
/**
24+
* C typedef for struct ULocale.
25+
* @draft ICU 74
26+
*/
27+
typedef struct ULocale ULocale;
28+
29+
/**
30+
* Constructs an ULocale from the locale ID.
31+
* The created ULocale should be destroyed by calling
32+
* ulocale_close();
33+
* @param localeID the locale, a const char * pointer (need not be terminated when
34+
* the length is non-negative)
35+
* @param length the length of the locale; if negative, then the locale need to be
36+
* null terminated.
37+
* @param err the error code
38+
* @return the locale.
39+
*
40+
* @draft ICU 74
41+
*/
42+
U_CAPI ULocale* U_EXPORT2
43+
ulocale_openForLocaleID(const char* localeID, int32_t length, UErrorCode* err);
44+
45+
/**
46+
* Constructs an ULocale from the provided IETF BCP 47 language tag.
47+
* The created ULocale should be destroyed by calling
48+
* ulocale_close();
49+
* @param tag the language tag, defined as IETF BCP 47 language tag, const
50+
* char* pointer (need not be terminated when the length is non-negative)
51+
* @param length the length of the tag; if negative, then the tag need to be
52+
* null terminated.
53+
* @param err the error code
54+
* @return the locale.
55+
*
56+
* @draft ICU 74
57+
*/
58+
U_CAPI ULocale* U_EXPORT2
59+
ulocale_openForLanguageTag(const char* tag, int32_t length, UErrorCode* err);
60+
61+
/**
62+
* Close the locale and destroy it's internal states.
63+
*
64+
* @param locale the locale
65+
* @draft ICU 74
66+
*/
67+
U_CAPI void U_EXPORT2
68+
ulocale_close(ULocale* locale);
69+
70+
/**
71+
* Returns the locale's ISO-639 language code.
72+
*
73+
* @param locale the locale
74+
* @return the language code of the locale.
75+
* @draft ICU 74
76+
*/
77+
U_CAPI const char* U_EXPORT2
78+
ulocale_getLanguage(const ULocale* locale);
79+
80+
/**
81+
* Returns the locale's ISO-15924 abbreviation script code.
82+
*
83+
* @param locale the locale
84+
* @return A pointer to the script.
85+
* @draft ICU 74
86+
*/
87+
U_CAPI const char* U_EXPORT2
88+
ulocale_getScript(const ULocale* locale);
89+
90+
/**
91+
* Returns the locale's ISO-3166 region code.
92+
*
93+
* @param locale the locale
94+
* @return A pointer to the region.
95+
* @draft ICU 74
96+
*/
97+
U_CAPI const char* U_EXPORT2
98+
ulocale_getRegion(const ULocale* locale);
99+
100+
/**
101+
* Returns the locale's variant code.
102+
*
103+
* @param locale the locale
104+
* @return A pointer to the variant.
105+
* @draft ICU 74
106+
*/
107+
U_CAPI const char* U_EXPORT2
108+
ulocale_getVariant(const ULocale* locale);
109+
110+
/**
111+
* Returns the programmatic name of the entire locale, with the language,
112+
* country and variant separated by underbars. If a field is missing, up
113+
* to two leading underbars will occur. Example: "en", "de_DE", "en_US_WIN",
114+
* "de__POSIX", "fr__MAC", "__MAC", "_MT", "_FR_EURO"
115+
*
116+
* @param locale the locale
117+
* @return A pointer to "name".
118+
* @draft ICU 74
119+
*/
120+
U_CAPI const char* U_EXPORT2
121+
ulocale_getLocaleID(const ULocale* locale);
122+
123+
/**
124+
* Returns the programmatic name of the entire locale as ulocale_getLocaleID()
125+
* would return, but without keywords.
126+
*
127+
* @param locale the locale
128+
* @return A pointer to "base name".
129+
* @draft ICU 74
130+
*/
131+
U_CAPI const char* U_EXPORT2
132+
ulocale_getBaseName(const ULocale* locale);
133+
134+
/**
135+
* Gets the bogus state. Locale object can be bogus if it doesn't exist
136+
*
137+
* @param locale the locale
138+
* @return false if it is a real locale, true if it is a bogus locale
139+
* @draft ICU 74
140+
*/
141+
U_CAPI bool U_EXPORT2
142+
ulocale_isBogus(const ULocale* locale);
143+
144+
/**
145+
* Gets the list of keywords for the specified locale.
146+
*
147+
* @param locale the locale
148+
* @param err the error code
149+
* @return pointer to UEnumeration, or nullptr if there are no keywords.
150+
* Client must call uenum_close() to dispose the returned value.
151+
* @draft ICU 74
152+
*/
153+
U_CAPI UEnumeration* U_EXPORT2
154+
ulocale_getKeywords(const ULocale* locale, UErrorCode *err);
155+
156+
/**
157+
* Gets the list of unicode keywords for the specified locale.
158+
*
159+
* @param locale the locale
160+
* @param err the error code
161+
* @return pointer to UEnumeration, or nullptr if there are no keywords.
162+
* Client must call uenum_close() to dispose the returned value.
163+
* @draft ICU 74
164+
*/
165+
U_CAPI UEnumeration* U_EXPORT2
166+
ulocale_getUnicodeKeywords(const ULocale* locale, UErrorCode *err);
167+
168+
/**
169+
* Gets the value for a keyword.
170+
*
171+
* This uses legacy keyword=value pairs, like "collation=phonebook".
172+
*
173+
* @param locale the locale
174+
* @param keyword the keyword, a const char * pointer (need not be
175+
* terminated when the length is non-negative)
176+
* @param keywordLength the length of the keyword; if negative, then the
177+
* keyword need to be null terminated.
178+
* @param valueBuffer The buffer to receive the value.
179+
* @param valueBufferCapacity The capacity of receiving valueBuffer.
180+
* @param err the error code
181+
* @draft ICU 74
182+
*/
183+
U_CAPI int32_t U_EXPORT2
184+
ulocale_getKeywordValue(
185+
const ULocale* locale, const char* keyword, int32_t keywordLength,
186+
char* valueBuffer, int32_t valueBufferCapacity, UErrorCode *err);
187+
188+
/**
189+
* Gets the Unicode value for a Unicode keyword.
190+
*
191+
* This uses Unicode key-value pairs, like "co-phonebk".
192+
*
193+
* @param locale the locale
194+
* @param keyword the Unicode keyword, a const char * pointer (need not be
195+
* terminated when the length is non-negative)
196+
* @param keywordLength the length of the Unicode keyword; if negative,
197+
* then the keyword need to be null terminated.
198+
* @param valueBuffer The buffer to receive the Unicode value.
199+
* @param valueBufferCapacity The capacity of receiving valueBuffer.
200+
* @param err the error code
201+
* @draft ICU 74
202+
*/
203+
U_CAPI int32_t U_EXPORT2
204+
ulocale_getUnicodeKeywordValue(
205+
const ULocale* locale, const char* keyword, int32_t keywordLength,
206+
char* valueBuffer, int32_t valueBufferCapacity, UErrorCode *err);
207+
208+
#if U_SHOW_CPLUSPLUS_API
209+
210+
U_NAMESPACE_BEGIN
211+
212+
/**
213+
* \class LocalULocalePointer
214+
* "Smart pointer" class, closes a ULocale via ulocale_close().
215+
* For most methods see the LocalPointerBase base class.
216+
*
217+
* @see LocalPointerBase
218+
* @see LocalPointer
219+
* @draft ICU 74
220+
*/
221+
U_DEFINE_LOCAL_OPEN_POINTER(LocalULocalePointer, ULocale, ulocale_close);
222+
223+
U_NAMESPACE_END
224+
225+
#endif /* U_SHOW_CPLUSPLUS_API */
226+
227+
#endif /* U_HIDE_DRAFT_API */
228+
229+
#endif /*_ULOCALE */

0 commit comments

Comments
 (0)