uloc_tag.c revision 27f654740f2a26ad62a5c155af9199af9e69b889
1b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru**********************************************************************
350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho*   Copyright (C) 2009-2010, International Business Machines
4b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru**********************************************************************
6b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
7b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
8b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/utypes.h"
9b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/ures.h"
10b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/putil.h"
11b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "unicode/uloc.h"
12b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "ustr_imp.h"
13b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "cmemory.h"
14b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "cstring.h"
15b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#include "putilimp.h"
1650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#include "uinvchar.h"
17b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
18b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* struct holding a single variant */
19b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct VariantListEntry {
20b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char              *variant;
21b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    struct VariantListEntry *next;
22b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} VariantListEntry;
23b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
24b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* struct holding a single extension */
25b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct ExtensionListEntry {
26b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char                  *key;
27b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char                  *value;
28b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    struct ExtensionListEntry   *next;
29b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} ExtensionListEntry;
30b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
31b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAXEXTLANG 3
32b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct ULanguageTag {
33b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char                *buf;   /* holding parsed subtags */
34b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *language;
35b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *extlang[MAXEXTLANG];
36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *script;
37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *region;
38b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry    *variants;
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry  *extensions;
40b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *privateuse;
41b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *grandfathered;
42b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} ULanguageTag;
43b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
44b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MINLEN 2
45b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define SEP '-'
46b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define PRIVATEUSE 'x'
47b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LDMLEXT 'u'
48b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
49b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_SEP '_'
50b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_EXT_SEP '@'
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_KEYWORD_SEP ';'
52b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_KEY_TYPE_SEP '='
53b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
54b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define ISALPHA(c) (((c)>='A' && (c)<='Z') || ((c)>='a' && (c)<='z'))
55b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define ISNUMERIC(c) ((c)>='0' && (c)<='9')
56b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
57b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char* EMPTY = "";
58b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char* LANG_UND = "und";
59b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char* PRIVATEUSE_KEY = "x";
6027f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char* _POSIX = "_POSIX";
6127f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char* POSIX_KEY = "va";
6227f654740f2a26ad62a5c155af9199af9e69b889clairehostatic const char* POSIX_VALUE = "posix";
63b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
64b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LANG_UND_LEN 3
65b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
66b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char* GRANDFATHERED[] = {
67b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*  grandfathered   preferred */
68b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "art-lojban",   "jbo",
69b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "cel-gaulish",  "",
70b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "en-GB-oed",    "",
71b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-ami",        "ami",
72b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-bnn",        "bnn",
73b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-default",    "",
74b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-enochian",   "",
75b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-hak",        "hak",
76b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-klingon",    "tlh",
77b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-lux",        "lb",
78b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-mingo",      "",
79b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-navajo",     "nv",
80b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-pwn",        "pwn",
81b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tao",        "tao",
82b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tay",        "tay",
83b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tsu",        "tsu",
84b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "no-bok",       "nb",
85b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "no-nyn",       "nn",
86b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-be-fr",    "sfb",
87b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-be-nl",    "vgt",
88b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-ch-de",    "sgg",
89b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-guoyu",     "cmn",
90b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-hakka",     "hak",
91b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-min",       "",
92b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-min-nan",   "nan",
93b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-xiang",     "hsn",
94b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    NULL,           NULL
95b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
96b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
97b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char* DEPRECATEDLANGS[] = {
98b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*  deprecated  new */
99b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "iw",       "he",
100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "ji",       "yi",
101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "in",       "id",
102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    NULL,       NULL
103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* These ultag_ functions may be exposed as APIs later
109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic ULanguageTag*
114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status);
115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_close(ULanguageTag* langtag);
118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getLanguage(const ULanguageTag* langtag);
121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getJDKLanguage(const ULanguageTag* langtag);
125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlang(const ULanguageTag* langtag, int32_t idx);
129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlangSize(const ULanguageTag* langtag);
132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getScript(const ULanguageTag* langtag);
135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getRegion(const ULanguageTag* langtag);
138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariant(const ULanguageTag* langtag, int32_t idx);
141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariantsSize(const ULanguageTag* langtag);
144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx);
147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx);
150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionsSize(const ULanguageTag* langtag);
153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getPrivateUse(const ULanguageTag* langtag);
156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getGrandfathered(const ULanguageTag* langtag);
160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Language subtag syntax validation functions
166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isAlphaString(const char* s, int32_t len) {
172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISALPHA(*(s + i))) {
175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isNumericString(const char* s, int32_t len) {
183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISNUMERIC(*(s + i))) {
186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isAlphaNumericString(const char* s, int32_t len) {
194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISALPHA(*(s + i)) && !ISNUMERIC(*(s + i))) {
197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLanguageSubtag(const char* s, int32_t len) {
205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * language      = 2*3ALPHA            ; shortest ISO 639 code
207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                 ["-" extlang]       ; sometimes followed by
208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                                     ;   extended language subtags
209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 4ALPHA              ; or reserved for future use
210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 5*8ALPHA            ; or registered language subtag
211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
21350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 2 && len <= 8 && _isAlphaString(s, len)) {
216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtlangSubtag(const char* s, int32_t len) {
223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extlang       = 3ALPHA              ; selected ISO 639 codes
225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                 *2("-" 3ALPHA)      ; permanently reserved
226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
22850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 3 && _isAlphaString(s, len)) {
231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isScriptSubtag(const char* s, int32_t len) {
238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * script        = 4ALPHA              ; ISO 15924 code
240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
24250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 4 && _isAlphaString(s, len)) {
245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isRegionSubtag(const char* s, int32_t len) {
252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * region        = 2ALPHA              ; ISO 3166-1 code
254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 3DIGIT              ; UN M.49 code
255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
25750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 2 && _isAlphaString(s, len)) {
260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 3 && _isNumericString(s, len)) {
263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isVariantSubtag(const char* s, int32_t len) {
270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * variant       = 5*8alphanum         ; registered variants
272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / (DIGIT 3alphanum)
273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
27550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 5 && len <= 8 && _isAlphaString(s, len)) {
278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 4 && ISNUMERIC(*s) && _isAlphaNumericString(s + 1, 3)) {
281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSingleton(const char* s, int32_t len) {
288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extension     = singleton 1*("-" (2*8alphanum))
290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
29250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 1 && ISALPHA(*s) && (uprv_tolower(*s) != PRIVATEUSE)) {
295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSubtag(const char* s, int32_t len) {
302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extension     = singleton 1*("-" (2*8alphanum))
304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
30650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 2 && len <= 8 && _isAlphaNumericString(s, len)) {
309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
311b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
312b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
313b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSubtags(const char* s, int32_t len) {
316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *p = s;
317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pSubtag = NULL;
318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
319b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
32050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while ((p - s) < len) {
324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*p == SEP) {
325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (pSubtag == NULL) {
326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
32850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!_isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag))) {
329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = NULL;
332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (pSubtag == NULL) {
333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = p;
334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p++;
336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pSubtag == NULL) {
338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return FALSE;
339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
34050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return _isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag));
341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isPrivateuseValueSubtag(const char* s, int32_t len) {
345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * privateuse    = "x" 1*("-" (1*8alphanum))
347b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
34950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 1 && len <= 8 && _isAlphaNumericString(s, len)) {
352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isPrivateuseValueSubtags(const char* s, int32_t len) {
359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *p = s;
360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pSubtag = NULL;
361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
36350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while ((p - s) < len) {
367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*p == SEP) {
368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (pSubtag == NULL) {
369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
37150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!_isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag))) {
372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = NULL;
375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (pSubtag == NULL) {
376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = p;
377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p++;
379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pSubtag == NULL) {
381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return FALSE;
382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
38350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag));
384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLDMLKey(const char* s, int32_t len) {
388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
38950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 2 && _isAlphaNumericString(s, len)) {
392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLDMLType(const char* s, int32_t len) {
399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
40050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 3 && len <= 8 && _isAlphaNumericString(s, len)) {
403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Helper functions
412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_addVariantToList(VariantListEntry **first, VariantListEntry *var) {
418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool bAdded = TRUE;
419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (*first == NULL) {
421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        var->next = NULL;
422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *first = var;
423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *prev, *cur;
425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t cmp;
426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* reorder variants in alphabetical order */
428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        prev = NULL;
429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = *first;
430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cur == NULL) {
432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                prev->next = var;
433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var->next = NULL;
434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
43650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            cmp = uprv_compareInvCharsAsAscii(var->variant, cur->variant);
437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp < 0) {
438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (prev == NULL) {
439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *first = var;
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    prev->next = var;
442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var->next = cur;
444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp == 0) {
447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* duplicated variant */
448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bAdded = FALSE;
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            prev = cur;
452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            cur = cur->next;
453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return bAdded;
457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool localeToBCP) {
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool bAdded = TRUE;
463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (*first == NULL) {
465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ext->next = NULL;
466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *first = ext;
467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *prev, *cur;
469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t cmp;
470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* reorder variants in alphabetical order */
472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        prev = NULL;
473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = *first;
474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cur == NULL) {
476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                prev->next = ext;
477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ext->next = NULL;
478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (localeToBCP) {
481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* special handling for locale to bcp conversion */
482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t len, curlen;
483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
48450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(ext->key);
48550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                curlen = (int32_t)uprv_strlen(cur->key);
486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (len == 1 && curlen == 1) {
488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (*(ext->key) == *(cur->key)) {
489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = 0;
490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (*(ext->key) == PRIVATEUSE) {
491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = 1;
492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (*(cur->key) == PRIVATEUSE) {
493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = -1;
494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = *(ext->key) - *(cur->key);
496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else if (len == 1) {
498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    cmp = *(ext->key) - LDMLEXT;
499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else if (curlen == 1) {
500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    cmp = LDMLEXT - *(cur->key);
501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
50250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
50550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp < 0) {
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (prev == NULL) {
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *first = ext;
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    prev->next = ext;
512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ext->next = cur;
514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp == 0) {
517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* duplicated extension key */
518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bAdded = FALSE;
519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            prev = cur;
522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            cur = cur->next;
523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return bAdded;
527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_initializeULanguageTag(ULanguageTag* langtag) {
531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->buf = NULL;
534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->language = EMPTY;
536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < MAXEXTLANG; i++) {
537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        langtag->extlang[i] = NULL;
538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->script = EMPTY;
541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->region = EMPTY;
542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->variants = NULL;
544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->extensions = NULL;
545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->grandfathered = EMPTY;
547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->privateuse = EMPTY;
548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
55050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define KEYTYPEDATA     "keyTypeData"
55150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define KEYMAP          "keyMap"
55250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define TYPEMAP         "typeMap"
55350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define TYPEALIAS       "typeAlias"
554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_BCP47_SUBTAG_LEN    9   /* including null terminator */
555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_LDML_KEY_LEN        22
556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_LDML_TYPE_LEN       32
557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
559b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_ldmlKeyToBCP47(const char* key, int32_t keyLen,
560b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char* bcpKey, int32_t bcpKeyCapacity,
561b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UErrorCode *status) {
562b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
563b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
564b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
567b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const UChar *uBcpKey;
569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t bcpKeyLen;
570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
57250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
58950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
59050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, KEYMAP, rb, status);
591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
597b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uBcpKey = ures_getStringByKey(rb, keyBuf, &bcpKeyLen, &tmpStatus);
598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(tmpStatus)) {
599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpKey, bcpKeyBuf, bcpKeyLen);
600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpKeyBuf[bcpKeyLen] = 0;
601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpKeyLen;
602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (_isLDMLKey(key, keyLen)) {
604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(bcpKeyBuf, key, keyLen);
605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bcpKeyBuf[keyLen] = 0;
606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            resultLen = keyLen;
607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* mapping not availabe */
609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
614b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
615b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
616b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpKey, bcpKeyBuf, uprv_min(resultLen, bcpKeyCapacity));
619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(bcpKey, bcpKeyCapacity, resultLen, status);
620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
622b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
623b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_bcp47ToLDMLKey(const char* bcpKey, int32_t bcpKeyLen,
624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char* key, int32_t keyCapacity,
625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UErrorCode *status) {
626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
627b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
628b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
630b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *resKey = NULL;
63150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *mapData;
632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
633b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpKeyLen < 0) {
63450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        bcpKeyLen = (int32_t)uprv_strlen(bcpKey);
635b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
636b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpKeyLen >= sizeof(bcpKeyBuf)) {
638b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
640b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpKeyBuf, bcpKey, bcpKeyLen);
643b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bcpKeyBuf[bcpKeyLen] = 0;
644b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
645b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
646b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < bcpKeyLen; i++) {
647b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpKeyBuf[i] = uprv_tolower(bcpKeyBuf[i]);
648b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
649b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
65050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
65150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, KEYMAP, rb, status);
652b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
653b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
654b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
655b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
656b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
65750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    mapData = ures_getNextResource(rb, NULL, status);
658b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (U_SUCCESS(*status)) {
659b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const UChar *uBcpKey;
660b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char tmpBcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t tmpBcpKeyLen;
662b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
66350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uBcpKey = ures_getString(mapData, &tmpBcpKeyLen, status);
664b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
665b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
666b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
667b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpKey, tmpBcpKeyBuf, tmpBcpKeyLen);
668b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpBcpKeyBuf[tmpBcpKeyLen] = 0;
66950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(bcpKeyBuf, tmpBcpKeyBuf) == 0) {
670b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* found a matching BCP47 key */
67150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resKey = ures_getKey(mapData);
67250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resultLen = (int32_t)uprv_strlen(resKey);
673b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
674b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
675b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ures_hasNext(rb)) {
676b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
677b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
67850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getNextResource(rb, mapData, status);
679b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
68050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(mapData);
681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
683b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
684b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
685b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (resKey == NULL) {
688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resKey = bcpKeyBuf;
689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpKeyLen;
690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
691b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(key, resKey, uprv_min(resultLen, keyCapacity));
693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(key, keyCapacity, resultLen, status);
694b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
697b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_ldmlTypeToBCP47(const char* key, int32_t keyLen,
698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 const char* type, int32_t typeLen,
699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 char* bcpType, int32_t bcpTypeCapacity,
700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 UErrorCode *status) {
70150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb, *keyTypeData, *typeMapForKey;
702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char typeBuf[MAX_LDML_TYPE_LEN];
704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
70850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *uBcpType, *uCanonicalType;
70950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t bcpTypeLen, canonicalTypeLen;
710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool isTimezone = FALSE;
711b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
712b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
71350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
714b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
715b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
720b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
723b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
726b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
72750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        isTimezone = TRUE;
729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (typeLen < 0) {
73250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeLen = (int32_t)uprv_strlen(type);
733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
734b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (typeLen >= sizeof(typeBuf)) {
735b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
73950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (isTimezone) {
74050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        /* replace '/' with ':' */
74150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        for (i = 0; i < typeLen; i++) {
74250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (*(type + i) == '/') {
74350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                typeBuf[i] = ':';
74450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
74550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                typeBuf[i] = *(type + i);
74650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
747b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
74850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeBuf[typeLen] = 0;
74950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        type = &typeBuf[0];
750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
75250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    keyTypeData = ures_openDirect(NULL, KEYTYPEDATA, status);
75350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_getByKey(keyTypeData, TYPEMAP, NULL, status);
754b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
75650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_close(keyTypeData);
757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
76050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    typeMapForKey = ures_getByKey(rb, keyBuf, NULL, &tmpStatus);
76150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    uBcpType = ures_getStringByKey(typeMapForKey, type, &bcpTypeLen, &tmpStatus);
762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(tmpStatus)) {
763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
764b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpTypeLen;
765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
76650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        /* is this type alias? */
76750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        tmpStatus = U_ZERO_ERROR;
76850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(keyTypeData, TYPEALIAS, rb, &tmpStatus);
76950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(rb, keyBuf, rb, &tmpStatus);
77050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uCanonicalType = ures_getStringByKey(rb, type, &canonicalTypeLen, &tmpStatus);
77150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(tmpStatus)) {
77250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            u_UCharsToChars(uCanonicalType, typeBuf, canonicalTypeLen);
77350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (isTimezone) {
77450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* replace '/' with ':' */
77550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                for (i = 0; i < canonicalTypeLen; i++) {
77650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (typeBuf[i] == '/') {
77750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        typeBuf[i] = ':';
77850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
77950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
78050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
78150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            typeBuf[canonicalTypeLen] = 0;
78250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
78350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            /* look up the canonical type */
78450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            uBcpType = ures_getStringByKey(typeMapForKey, typeBuf, &bcpTypeLen, &tmpStatus);
78550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_SUCCESS(tmpStatus)) {
78650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
78750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                resultLen = bcpTypeLen;
78850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
78950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
79050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
79150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (_isLDMLType(type, typeLen)) {
79250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                uprv_memcpy(bcpTypeBuf, type, typeLen);
79350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                resultLen = typeLen;
79450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
79550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* mapping not availabe */
79650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *status = U_ILLEGAL_ARGUMENT_ERROR;
79750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = tmpStatus;
801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
80350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(typeMapForKey);
80450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(keyTypeData);
805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
806b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
809b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpType, bcpTypeBuf, uprv_min(resultLen, bcpTypeCapacity));
811b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(bcpType, bcpTypeCapacity, resultLen, status);
812b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
813b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
814b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
815b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_bcp47ToLDMLType(const char* key, int32_t keyLen,
816b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 const char* bcpType, int32_t bcpTypeLen,
817b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 char* type, int32_t typeCapacity,
818b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 UErrorCode *status) {
819b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
820b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
821b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
822b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
823b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
824b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *resType = NULL;
82550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *mapData;
826b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
827b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t copyLen;
828b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
829b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
83050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
831b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
832b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
833b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
834b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
835b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
836b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
837b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
838b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
839b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
840b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
841b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
842b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
843b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
844b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
845b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
846b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
847b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpTypeLen < 0) {
84850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        bcpTypeLen = (int32_t)uprv_strlen(bcpType);
849b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
850b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
851b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpTypeLen >= sizeof(bcpTypeBuf)) {
852b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
853b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
854b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
855b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
856b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpTypeBuf, bcpType, bcpTypeLen);
857b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bcpTypeBuf[bcpTypeLen] = 0;
858b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
859b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
860b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < bcpTypeLen; i++) {
861b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpTypeBuf[i] = uprv_tolower(bcpTypeBuf[i]);
862b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
863b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
86450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
86550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, TYPEMAP, rb, status);
866b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
867b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
868b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
869b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
870b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
871b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_getByKey(rb, keyBuf, rb, &tmpStatus);
87250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    mapData = ures_getNextResource(rb, NULL, &tmpStatus);
873b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (U_SUCCESS(tmpStatus)) {
874b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const UChar *uBcpType;
875b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char tmpBcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
876b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t tmpBcpTypeLen;
877b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
87850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uBcpType = ures_getString(mapData, &tmpBcpTypeLen, &tmpStatus);
879b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(tmpStatus)) {
880b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
881b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
882b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpType, tmpBcpTypeBuf, tmpBcpTypeLen);
883b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpBcpTypeBuf[tmpBcpTypeLen] = 0;
88450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(bcpTypeBuf, tmpBcpTypeBuf) == 0) {
885b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* found a matching BCP47 type */
88650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resType = ures_getKey(mapData);
88750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resultLen = (int32_t)uprv_strlen(resType);
888b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
889b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
890b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ures_hasNext(rb)) {
891b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
892b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
89350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getNextResource(rb, mapData, &tmpStatus);
894b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
89550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(mapData);
896b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
897b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
898b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) && tmpStatus != U_MISSING_RESOURCE_ERROR) {
899b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = tmpStatus;
900b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
901b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
902b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
903b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (resType == NULL) {
904b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resType = bcpTypeBuf;
905b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpTypeLen;
906b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
907b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
908b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    copyLen = uprv_min(resultLen, typeCapacity);
909b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(type, resType, copyLen);
910b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
91150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
912b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (i = 0; i < copyLen; i++) {
913b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*(type + i) == ':') {
914b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(type + i) = '/';
915b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
916b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
917b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
918b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
919b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(type, typeCapacity, resultLen, status);
920b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
921b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
922b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
923b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
924b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_LANG_CAPACITY];
925b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
926b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len, i;
927b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
928b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
929b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
930b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
931b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
932b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
933b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getLanguage(localeID, buf, sizeof(buf), &tmpStatus);
934b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
935b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
936b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
937b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
939b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        len = 0;
940b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
941b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
942b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Note: returned language code is in lower case letters */
943b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
944b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 0) {
945b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
946b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
947b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
948b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += LANG_UND_LEN;
949b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else if (!_isLanguageSubtag(buf, len)) {
950b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid language code */
951b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
952b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
953b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
954b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
955b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
956b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
957b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
958b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += LANG_UND_LEN;
959b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
960b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* resolve deprecated */
961b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (i = 0; DEPRECATEDLANGS[i] != NULL; i += 2) {
96250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) {
963b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]);
96450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(buf);
965b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
966b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
967b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
968b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
969b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
970b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
971b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += len;
972b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
973b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
974b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
975b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
976b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
977b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
978b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendScriptToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
979b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_SCRIPT_CAPACITY];
980b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
98150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t len;
982b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
983b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
984b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
985b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
986b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
987b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
988b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getScript(localeID, buf, sizeof(buf), &tmpStatus);
989b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
990b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
991b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
992b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
993b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
994b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
995b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
996b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
997b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!_isScriptSubtag(buf, len)) {
998b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid script code */
999b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (strict) {
1000b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1001b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1002b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1003b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1004b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1005b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(appendAt + reslen) = SEP;
1006b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1007b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1008b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1009b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1010b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
1011b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1012b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1013b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1014b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1015b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1016b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1017b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1018b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1019b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
1020b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendRegionToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
1021b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_COUNTRY_CAPACITY];
1022b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
102350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t len;
1024b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1025b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1026b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1027b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1028b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1029b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1030b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getCountry(localeID, buf, sizeof(buf), &tmpStatus);
1031b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1032b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1033b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1034b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1035b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1036b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1037b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1038b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
1039b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!_isRegionSubtag(buf, len)) {
1040b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid region code */
1041b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (strict) {
1042b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1043b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1044b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1045b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1046b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1047b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(appendAt + reslen) = SEP;
1048b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1049b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1050b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1051b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1052b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
1053b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1054b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1055b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1056b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1057b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1058b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1059b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1060b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1061b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
106227f654740f2a26ad62a5c155af9199af9e69b889claireho_appendVariantsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool *hadPosix, UErrorCode* status) {
1063b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_FULLNAME_CAPACITY];
1064b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
1065b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len, i;
1066b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1067b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1068b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1069b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1070b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1071b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1072b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
1073b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1074b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1075b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1076b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1077b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1078b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1079b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1080b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
1081b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *p, *pVar;
1082b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UBool bNext = TRUE;
1083b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *var;
1084b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *varFirst = NULL;
1085b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1086b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pVar = NULL;
1087b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = buf;
1088b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (bNext) {
1089b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
1090b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (*p == 0) {
1091b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    bNext = FALSE;
1092b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1093b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *p = 0; /* terminate */
1094b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1095b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pVar == NULL) {
1096b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1097b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1098b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1099b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* ignore empty variant */
1101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
110250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    /* ICU uses upper case letters for variants, but
110350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                       the canonical format is lowercase in BCP47 */
1104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    for (i = 0; *(pVar + i) != 0; i++) {
1105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(pVar + i) = uprv_tolower(*(pVar + i));
1106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* validate */
1109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (_isVariantSubtag(pVar, -1)) {
111027f654740f2a26ad62a5c155af9199af9e69b889claireho                        if (uprv_strcmp(pVar,POSIX_VALUE)) {
111127f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* emit the variant to the list */
111227f654740f2a26ad62a5c155af9199af9e69b889claireho                            var = uprv_malloc(sizeof(VariantListEntry));
111327f654740f2a26ad62a5c155af9199af9e69b889claireho                            if (var == NULL) {
111427f654740f2a26ad62a5c155af9199af9e69b889claireho                                *status = U_MEMORY_ALLOCATION_ERROR;
1115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                                break;
1116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            }
111727f654740f2a26ad62a5c155af9199af9e69b889claireho                            var->variant = pVar;
111827f654740f2a26ad62a5c155af9199af9e69b889claireho                            if (!_addVariantToList(&varFirst, var)) {
111927f654740f2a26ad62a5c155af9199af9e69b889claireho                                /* duplicated variant */
112027f654740f2a26ad62a5c155af9199af9e69b889claireho                                uprv_free(var);
112127f654740f2a26ad62a5c155af9199af9e69b889claireho                                if (strict) {
112227f654740f2a26ad62a5c155af9199af9e69b889claireho                                    *status = U_ILLEGAL_ARGUMENT_ERROR;
112327f654740f2a26ad62a5c155af9199af9e69b889claireho                                    break;
112427f654740f2a26ad62a5c155af9199af9e69b889claireho                                }
112527f654740f2a26ad62a5c155af9199af9e69b889claireho                            }
112627f654740f2a26ad62a5c155af9199af9e69b889claireho                        } else {
112727f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* Special handling for POSIX variant, need to remember that we had it and then */
112827f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* treat it like an extension later. */
112927f654740f2a26ad62a5c155af9199af9e69b889claireho                            *hadPosix = TRUE;
1130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (strict) {
1132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* reset variant starting position */
1137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pVar = NULL;
1138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else if (pVar == NULL) {
1139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pVar = p;
1140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
1142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_SUCCESS(*status)) {
1145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (varFirst != NULL) {
1146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t varLen;
1147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* write out sorted/validated/normalized variants to the target */
1149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var = varFirst;
1150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                while (var != NULL) {
1151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(appendAt + reslen) = SEP;
1153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
115550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    varLen = (int32_t)uprv_strlen(var->variant);
1156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_memcpy(appendAt + reslen, var->variant, uprv_min(varLen, capacity - reslen));
1158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen += varLen;
1160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    var = var->next;
1161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* clean up */
1166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        var = varFirst;
1167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (var != NULL) {
1168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            VariantListEntry *tmpVar = var->next;
1169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(var);
1170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            var = tmpVar;
1171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
1174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
118327f654740f2a26ad62a5c155af9199af9e69b889claireho_appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool hadPosix, UErrorCode* status) {
1184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UEnumeration *keywordEnum = NULL;
1186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keywordEnum = uloc_openKeywords(localeID, status);
118927f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_FAILURE(*status) && !hadPosix) {
1190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uenum_close(keywordEnum);
1191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
119327f654740f2a26ad62a5c155af9199af9e69b889claireho    if (keywordEnum != NULL || hadPosix) {
1194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* reorder extensions */
1195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t len;
1196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const char *key;
1197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *firstExt = NULL;
1198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *ext;
1199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char extBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *pExtBuf = extBuf;
1201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t extBufCapacity = sizeof(extBuf);
1202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const char *bcpKey, *bcpValue;
1203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UErrorCode tmpStatus = U_ZERO_ERROR;
1204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t keylen;
1205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UBool isLDMLKeyword;
1206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
1208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            key = uenum_next(keywordEnum, NULL, status);
1209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (key == NULL) {
1210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStatus);
1213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(tmpStatus)) {
1214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (strict) {
1215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* ignore this keyword */
1219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                tmpStatus = U_ZERO_ERROR;
1220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
122350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            keylen = (int32_t)uprv_strlen(key);
1224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            isLDMLKeyword = (keylen > 1);
1225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (isLDMLKeyword) {
1227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t modKeyLen;
1228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* transform key and value to bcp47 style */
1230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                modKeyLen = _ldmlKeyToBCP47(key, keylen, pExtBuf, extBufCapacity, &tmpStatus);
1231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    tmpStatus = U_ZERO_ERROR;
1237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    continue;
1238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpKey = pExtBuf;
1241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtBuf += (modKeyLen + 1);
1242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                extBufCapacity -= (modKeyLen + 1);
1243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                len = _ldmlTypeToBCP47(key, keylen, buf, len, pExtBuf, extBufCapacity, &tmpStatus);
1245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    tmpStatus = U_ZERO_ERROR;
1251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    continue;
1252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpValue = pExtBuf;
1254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtBuf += (len + 1);
1255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                extBufCapacity -= (len + 1);
1256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
1257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (*key == PRIVATEUSE) {
1258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (!_isPrivateuseValueSubtags(buf, len)) {
1259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (strict) {
1260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            *status = U_ILLEGAL_ARGUMENT_ERROR;
1261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        continue;
1264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (!_isExtensionSingleton(key, keylen) || !_isExtensionSubtags(buf, len)) {
1267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (strict) {
1268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            *status = U_ILLEGAL_ARGUMENT_ERROR;
1269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        continue;
1272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpKey = key;
1275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if ((len + 1) < extBufCapacity) {
1276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_memcpy(pExtBuf, buf, len);
1277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    bcpValue = pExtBuf;
1278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pExtBuf += len;
1280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pExtBuf = 0;
1282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pExtBuf++;
1283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    extBufCapacity -= (len + 1);
1285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* create ExtensionListEntry */
1292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext = uprv_malloc(sizeof(ExtensionListEntry));
1293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (ext == NULL) {
1294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_MEMORY_ALLOCATION_ERROR;
1295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext->key = bcpKey;
1298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext->value = bcpValue;
1299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (!_addExtensionToList(&firstExt, ext, TRUE)) {
1301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_free(ext);
1302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (strict) {
1303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
130827f654740f2a26ad62a5c155af9199af9e69b889claireho
130927f654740f2a26ad62a5c155af9199af9e69b889claireho        /* Special handling for POSIX variant - add the keywords for POSIX */
131027f654740f2a26ad62a5c155af9199af9e69b889claireho        if (hadPosix) {
131127f654740f2a26ad62a5c155af9199af9e69b889claireho            /* create ExtensionListEntry for POSIX */
131227f654740f2a26ad62a5c155af9199af9e69b889claireho            ext = uprv_malloc(sizeof(ExtensionListEntry));
131327f654740f2a26ad62a5c155af9199af9e69b889claireho            if (ext == NULL) {
131427f654740f2a26ad62a5c155af9199af9e69b889claireho                *status = U_MEMORY_ALLOCATION_ERROR;
131527f654740f2a26ad62a5c155af9199af9e69b889claireho            }
131627f654740f2a26ad62a5c155af9199af9e69b889claireho            ext->key = POSIX_KEY;
131727f654740f2a26ad62a5c155af9199af9e69b889claireho            ext->value = POSIX_VALUE;
131827f654740f2a26ad62a5c155af9199af9e69b889claireho
131927f654740f2a26ad62a5c155af9199af9e69b889claireho            if (!_addExtensionToList(&firstExt, ext, TRUE)) {
132027f654740f2a26ad62a5c155af9199af9e69b889claireho                uprv_free(ext);
132127f654740f2a26ad62a5c155af9199af9e69b889claireho            }
132227f654740f2a26ad62a5c155af9199af9e69b889claireho        }
132327f654740f2a26ad62a5c155af9199af9e69b889claireho
1324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_SUCCESS(*status) && (firstExt != NULL)) {
1325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            UBool startLDMLExtension = FALSE;
1326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* write out the sorted BCP47 extensions and private use */
1328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext = firstExt;
1329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            while (ext != NULL) {
133050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if ((int32_t)uprv_strlen(ext->key) > 1 && !startLDMLExtension) {
1331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* write LDML singleton extension */
1332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(appendAt + reslen) = SEP;
1334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
1336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(appendAt + reslen) = LDMLEXT;
1338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
1340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    startLDMLExtension = TRUE;
1341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < capacity) {
1344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = SEP;
1345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen++;
134750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(ext->key);
1348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < capacity) {
1349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_memcpy(appendAt + reslen, ext->key, uprv_min(len, capacity - reslen));
1350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen += len;
1352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < capacity) {
1353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = SEP;
1354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen++;
135650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(ext->value);
1357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < capacity) {
1358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_memcpy(appendAt + reslen, ext->value, uprv_min(len, capacity - reslen));
1359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen += len;
1361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ext = ext->next;
1363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* clean up */
1366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ext = firstExt;
1367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (ext != NULL) {
1368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ExtensionListEntry *tmpExt = ext->next;
1369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(ext);
1370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext = tmpExt;
1371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uenum_close(keywordEnum);
1374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
1376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(appendAt, capacity, reslen, status);
1381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/**
1384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Append keywords parsed from LDML extension value
1385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * e.g. "u-ca-gregory-co-trad" -> {calendar = gregorian} {collation = traditional}
1386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Note: char* buf is used for storing keywords
1387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
1388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
138927f654740f2a26ad62a5c155af9199af9e69b889claireho_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, char* buf, int32_t bufSize, UBool *posixVariant, UErrorCode *status) {
1390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *p, *pNext, *pSep;
1391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pBcpKey, *pBcpType;
1392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pKey, *pType;
1393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t bcpKeyLen = 0, bcpTypeLen;
1394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwd, *nextKwd;
1395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwdFirst = NULL;
1396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t bufIdx = 0;
1397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t  len;
1398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pNext = ldmlext;
1400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pBcpKey = pBcpType = NULL;
1401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (pNext) {
1402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = pSep = pNext;
1403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* locate next separator char */
1405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*pSep) {
1406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*pSep == SEP) {
1407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSep++;
1410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*pSep == 0) {
1412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* last subtag */
1413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = NULL;
1414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = pSep + 1;
1416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (pBcpKey == NULL) {
1419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pBcpKey = p;
142050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            bcpKeyLen = (int32_t)(pSep - p);
1421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pBcpType = p;
142350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            bcpTypeLen = (int32_t)(pSep - p);
1424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* BCP key to locale key */
1426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            len = _bcp47ToLDMLKey(pBcpKey, bcpKeyLen, buf + bufIdx, bufSize - bufIdx - 1, status);
1427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(*status)) {
1428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                goto cleanup;
1429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pKey = buf + bufIdx;
1431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bufIdx += len;
1432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(buf + bufIdx) = 0;
1433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bufIdx++;
1434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* BCP type to locale type */
1436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            len = _bcp47ToLDMLType(pKey, -1, pBcpType, bcpTypeLen, buf + bufIdx, bufSize - bufIdx - 1, status);
1437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(*status)) {
1438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                goto cleanup;
1439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pType = buf + bufIdx;
1441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bufIdx += len;
1442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(buf + bufIdx) = 0;
1443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bufIdx++;
1444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
144527f654740f2a26ad62a5c155af9199af9e69b889claireho            /* Special handling for u-va-posix, since we want to treat this as a variant, not */
144627f654740f2a26ad62a5c155af9199af9e69b889claireho            /* as a keyword.                                                                  */
1447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
144827f654740f2a26ad62a5c155af9199af9e69b889claireho            if ( !uprv_strcmp(pKey,POSIX_KEY) && !uprv_strcmp(pType,POSIX_VALUE) ) {
144927f654740f2a26ad62a5c155af9199af9e69b889claireho                *posixVariant = TRUE;
145027f654740f2a26ad62a5c155af9199af9e69b889claireho            } else {
145127f654740f2a26ad62a5c155af9199af9e69b889claireho                /* create an ExtensionListEntry for this keyword */
145227f654740f2a26ad62a5c155af9199af9e69b889claireho                kwd = uprv_malloc(sizeof(ExtensionListEntry));
145327f654740f2a26ad62a5c155af9199af9e69b889claireho                if (kwd == NULL) {
145427f654740f2a26ad62a5c155af9199af9e69b889claireho                    *status = U_MEMORY_ALLOCATION_ERROR;
145527f654740f2a26ad62a5c155af9199af9e69b889claireho                    goto cleanup;
145627f654740f2a26ad62a5c155af9199af9e69b889claireho                }
1457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
145827f654740f2a26ad62a5c155af9199af9e69b889claireho                kwd->key = pKey;
145927f654740f2a26ad62a5c155af9199af9e69b889claireho                kwd->value = pType;
146027f654740f2a26ad62a5c155af9199af9e69b889claireho
146127f654740f2a26ad62a5c155af9199af9e69b889claireho                if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
146227f654740f2a26ad62a5c155af9199af9e69b889claireho                    *status = U_ILLEGAL_ARGUMENT_ERROR;
146327f654740f2a26ad62a5c155af9199af9e69b889claireho                    uprv_free(kwd);
146427f654740f2a26ad62a5c155af9199af9e69b889claireho                    goto cleanup;
146527f654740f2a26ad62a5c155af9199af9e69b889claireho                }
1466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* for next pair */
1469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pBcpKey = NULL;
1470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pBcpType = NULL;
1471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pBcpKey != NULL) {
1475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
1476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        goto cleanup;
1477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        nextKwd = kwd->next;
1482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        _addExtensionToList(appendTo, kwd, FALSE);
1483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = nextKwd;
1484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return;
1487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querucleanup:
1489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        nextKwd = kwd->next;
1492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(kwd);
1493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = nextKwd;
1494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
1499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendKeywords(ULanguageTag* langtag, char* appendAt, int32_t capacity, UErrorCode* status) {
1500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i, n;
1502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len;
1503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwdFirst = NULL;
1504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwd;
1505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *key, *type;
1506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char kwdBuf[ULOC_KEYWORDS_CAPACITY];
150727f654740f2a26ad62a5c155af9199af9e69b889claireho    UBool posixVariant = FALSE;
1508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getExtensionsSize(langtag);
1514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* resolve locale keywords and reordering keys */
1516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < n; i++) {
1517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        key = ultag_getExtensionKey(langtag, i);
1518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        type = ultag_getExtensionValue(langtag, i);
1519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*key == LDMLEXT) {
152027f654740f2a26ad62a5c155af9199af9e69b889claireho            _appendLDMLExtensionAsKeywords(type, &kwdFirst, kwdBuf, sizeof(kwdBuf), &posixVariant, status);
1521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(*status)) {
1522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd = uprv_malloc(sizeof(ExtensionListEntry));
1526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (kwd == NULL) {
1527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_MEMORY_ALLOCATION_ERROR;
1528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd->key = key;
1531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd->value = type;
1532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
1533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_free(kwd);
1534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(*status)) {
1541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        type = ultag_getPrivateUse(langtag);
154250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if ((int32_t)uprv_strlen(type) > 0) {
1543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* add private use as a keyword */
1544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd = uprv_malloc(sizeof(ExtensionListEntry));
1545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (kwd == NULL) {
1546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_MEMORY_ALLOCATION_ERROR;
1547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
1548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                kwd->key = PRIVATEUSE_KEY;
1549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                kwd->value = type;
1550b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
1551b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_free(kwd);
1552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
155827f654740f2a26ad62a5c155af9199af9e69b889claireho    /* If a POSIX variant was in the extensions, write it out before writing the keywords. */
155927f654740f2a26ad62a5c155af9199af9e69b889claireho
156027f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(*status) && posixVariant) {
156127f654740f2a26ad62a5c155af9199af9e69b889claireho        len = (int32_t) uprv_strlen(_POSIX);
156227f654740f2a26ad62a5c155af9199af9e69b889claireho        if (reslen < capacity) {
156327f654740f2a26ad62a5c155af9199af9e69b889claireho            uprv_memcpy(appendAt + reslen, _POSIX, uprv_min(len, capacity - reslen));
156427f654740f2a26ad62a5c155af9199af9e69b889claireho        }
156527f654740f2a26ad62a5c155af9199af9e69b889claireho        reslen += len;
156627f654740f2a26ad62a5c155af9199af9e69b889claireho    }
156727f654740f2a26ad62a5c155af9199af9e69b889claireho
1568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(*status) && kwdFirst != NULL) {
1569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the sorted keywords */
1570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = kwdFirst;
1571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (kwd != NULL) {
1572b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (kwd == kwdFirst) {
1574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* '@' */
1575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = LOCALE_EXT_SEP;
1576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* ';' */
1578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = LOCALE_KEYWORD_SEP;
1579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* key */
158450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            len = (int32_t)uprv_strlen(kwd->key);
1585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, kwd->key, uprv_min(len, capacity - reslen));
1587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1589b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1590b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* '=' */
1591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(appendAt + reslen) = LOCALE_KEY_TYPE_SEP;
1593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* type */
159750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            len = (int32_t)uprv_strlen(kwd->value);
1598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, kwd->value, uprv_min(len, capacity - reslen));
1600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd = kwd->next;
1604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* clean up */
1608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *tmpKwd = kwd->next;
1611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(kwd);
1612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = tmpKwd;
1613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1614b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1615b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1616b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(appendAt, capacity, reslen, status);
1620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1622b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
1623b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
1624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
1625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* ultag_ functions
1626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
1627b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
1628b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
1629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1630b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* Bit flags used by the parser */
1631b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LANG 0x0001
1632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTL 0x0002
1633b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define SCRT 0x0004
1634b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define REGN 0x0008
1635b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define VART 0x0010
1636b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTS 0x0020
1637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTV 0x0040
1638b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define PRIV 0x0080
1639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1640b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic ULanguageTag*
1641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status) {
1642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ULanguageTag *t;
1643b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char *tagBuf;
1644b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int16_t next;
1645b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char *pSubtag, *pNext, *pLastGoodPosition;
1646b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t subtagLen;
1647b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t extlangIdx;
1648b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *pExtension;
164950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    char *pExtValueSubtag, *pExtValueSubtagEnd;
1650b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
1651b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool isLDMLExtension, reqLDMLType;
1652b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1653b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (parsedLen != NULL) {
1654b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *parsedLen = 0;
1655b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1656b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1657b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1658b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
1659b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1660b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagLen < 0) {
166250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        tagLen = (int32_t)uprv_strlen(tag);
1663b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1664b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1665b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* copy the entire string */
1666b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tagBuf = (char*)uprv_malloc(tagLen + 1);
1667b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagBuf == NULL) {
1668b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
1669b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
1670b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1671b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(tagBuf, tag, tagLen);
1672b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    *(tagBuf + tagLen) = 0;
1673b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1674b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* create a ULanguageTag */
1675b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    t = (ULanguageTag*)uprv_malloc(sizeof(ULanguageTag));
1676b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    _initializeULanguageTag(t);
1677b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    t->buf = tagBuf;
1678b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (t == NULL) {
1679b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(tagBuf);
1680b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
1681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
1682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1683b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1684b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagLen < MINLEN) {
1685b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* the input tag is too short - return empty ULanguageTag */
1686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return t;
1687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* check if the tag is grandfathered */
1690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; GRANDFATHERED[i] != NULL; i += 2) {
169150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (T_CString_stricmp(GRANDFATHERED[i], tagBuf) == 0) {
1692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* a grandfathered tag is always longer than its preferred mapping */
1693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_strcpy(t->buf, GRANDFATHERED[i + 1]);
1694b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            t->language = t->buf;
1695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (parsedLen != NULL) {
1696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *parsedLen = tagLen;
1697b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return t;
1699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1701b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
1703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * langtag      =   language
1704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" script]
1705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" region]
1706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  *("-" variant)
1707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  *("-" extension)
1708b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" privateuse]
1709b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
1710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1711b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    next = LANG | PRIV;
1712b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pNext = pLastGoodPosition = tagBuf;
1713b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    extlangIdx = 0;
1714b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pExtension = NULL;
171550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    pExtValueSubtag = NULL;
1716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pExtValueSubtagEnd = NULL;
1717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    isLDMLExtension = FALSE;
1718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reqLDMLType = FALSE;
1719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1720b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (pNext) {
1721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *pSep;
1722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1723b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pSubtag = pNext;
1724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* locate next separator char */
1726b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pSep = pSubtag;
1727b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*pSep) {
1728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*pSep == SEP) {
1729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSep++;
1732b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*pSep == 0) {
1734b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* last subtag */
1735b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = NULL;
1736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = pSep + 1;
1738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
173950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        subtagLen = (int32_t)(pSep - pSubtag);
1740b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1741b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & LANG) {
1742b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isLanguageSubtag(pSubtag, subtagLen)) {
1743b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;  /* terminate */
174450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->language = T_CString_toLowerCase(pSubtag);
1745b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1746b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
1747b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
1748b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1749b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTL) {
1752b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtlangSubtag(pSubtag, subtagLen)) {
1753b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
175450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->extlang[extlangIdx++] = T_CString_toLowerCase(pSubtag);
1755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
1757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (extlangIdx < 3) {
1758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
1759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1760b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    next = SCRT | REGN | VART | EXTS | PRIV;
1761b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1764b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & SCRT) {
1766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isScriptSubtag(pSubtag, subtagLen)) {
176750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                char *p = pSubtag;
176850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
1769b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
177050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
177150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* to title case */
177250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *p = uprv_toupper(*p);
177350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                p++;
177450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                for (; *p; p++) {
177550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    *p = uprv_tolower(*p);
177650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
177750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
1778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                t->script = pSubtag;
1779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
1781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = REGN | VART | EXTS | PRIV;
1782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1785b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & REGN) {
1786b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isRegionSubtag(pSubtag, subtagLen)) {
1787b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
178850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->region = T_CString_toUpperCase(pSubtag);
1789b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1790b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
1791b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = VART | EXTS | PRIV;
1792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1795b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & VART) {
1796b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isVariantSubtag(pSubtag, subtagLen)) {
1797b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                VariantListEntry *var;
1798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UBool isAdded;
1799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var = (VariantListEntry*)uprv_malloc(sizeof(VariantListEntry));
1801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (var == NULL) {
1802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_MEMORY_ALLOCATION_ERROR;
1803b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto error;
1804b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
180650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                var->variant = T_CString_toUpperCase(pSubtag);
1807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                isAdded = _addVariantToList(&(t->variants), var);
1808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (!isAdded) {
1809b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* duplicated variant entry */
1810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_free(var);
1811b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1812b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1813b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
1814b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = VART | EXTS | PRIV;
1815b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1816b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1817b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1818b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTS) {
1819b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtensionSingleton(pSubtag, subtagLen)) {
1820b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension != NULL) {
182150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
1822b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* the previous extension is incomplete */
1823b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
182450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension = NULL;
1825b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1826b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1827b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1828b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* terminate the previous extension value */
1829b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pExtValueSubtagEnd = 0;
183050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
1831b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1832b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* insert the extension to the list */
1833b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
1834b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pLastGoodPosition = pExtValueSubtagEnd;
1835b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
1836b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* stop parsing here */
1837b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
1838b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pExtension = NULL;
1839b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1840b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1841b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1842b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (isLDMLExtension && reqLDMLType) {
1843b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* incomplete LDML extension key and type pair */
1844b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pExtension = NULL;
1845b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1846b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1847b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1848b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
184950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                isLDMLExtension = (uprv_tolower(*pSubtag) == LDMLEXT);
1850b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1851b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* create a new extension */
1852b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtension = uprv_malloc(sizeof(ExtensionListEntry));
1853b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension == NULL) {
1854b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_MEMORY_ALLOCATION_ERROR;
1855b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto error;
1856b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1857b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
185850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                pExtension->key = T_CString_toLowerCase(pSubtag);
1859b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtension->value = NULL;   /* will be set later */
1860b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1861b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /*
186250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                 * reset the start and the end location of extension value
1863b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 * subtags for this extension
1864b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 */
186550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                pExtValueSubtag = NULL;
1866b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtValueSubtagEnd = NULL;
1867b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1868b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = EXTV;
1869b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1870b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1871b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1872b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTV) {
1873b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtensionSubtag(pSubtag, subtagLen)) {
1874b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (isLDMLExtension) {
1875b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reqLDMLType) {
1876b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* already saw an LDML key */
1877b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (!_isLDMLType(pSubtag, subtagLen)) {
1878b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            /* stop parsing here and let the valid LDML extension key/type
1879b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                               pairs processed by the code out of this while loop */
1880b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1881b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1882b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pExtValueSubtagEnd = pSep;
1883b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        reqLDMLType = FALSE;
1884b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        next = EXTS | EXTV | PRIV;
1885b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
1886b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* LDML key */
1887b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (!_isLDMLKey(pSubtag, subtagLen)) {
1888b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            /* stop parsing here and let the valid LDML extension key/type
1889b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                               pairs processed by the code out of this while loop */
1890b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1891b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1892b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        reqLDMLType = TRUE;
1893b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        next = EXTV;
1894b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1895b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1896b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* Mark the end of this subtag */
1897b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pExtValueSubtagEnd = pSep;
1898b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    next = EXTS | EXTV | PRIV;
1899b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1900b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
190150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (pExtValueSubtag == NULL) {
1902b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* if the start postion of this extension's value is not yet,
1903b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                       this one is the first value subtag */
190450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    pExtValueSubtag = pSubtag;
1905b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1906b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1907b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1908b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1909b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & PRIV) {
191050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (uprv_tolower(*pSubtag) == PRIVATEUSE) {
1911b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char *pPrivuseVal;
1912b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1913b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension != NULL) {
1914b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* Process the last extension */
191550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
1916b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* the previous extension is incomplete */
1917b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
191850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension = NULL;
1919b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1920b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
1921b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* terminate the previous extension value */
1922b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *pExtValueSubtagEnd = 0;
192350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
1924b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1925b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* insert the extension to the list */
1926b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
1927b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pLastGoodPosition = pExtValueSubtagEnd;
1928b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pExtension = NULL;
1929b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        } else {
1930b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* stop parsing here */
1931b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            uprv_free(pExtension);
1932b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pExtension = NULL;
1933b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1934b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1935b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1936b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1937b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* The rest of part will be private use value subtags */
1939b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pNext == NULL) {
1940b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* empty private use subtag */
1941b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1942b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1943b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* back up the private use value start position */
1944b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pPrivuseVal = pNext;
1945b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1946b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* validate private use value subtags */
1947b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                while (pNext) {
1948b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pSubtag = pNext;
1949b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pSep = pSubtag;
1950b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    while (*pSep) {
1951b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (*pSep == SEP) {
1952b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1953b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1954b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pSep++;
1955b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1956b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (*pSep == 0) {
1957b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* last subtag */
1958b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pNext = NULL;
1959b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
1960b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pNext = pSep + 1;
1961b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
196250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    subtagLen = (int32_t)(pSep - pSubtag);
1963b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1964b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (_isPrivateuseValueSubtag(pSubtag, subtagLen)) {
1965b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pLastGoodPosition = pSep;
1966b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
1967b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1968b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1969b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1970b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pLastGoodPosition - pPrivuseVal > 0) {
1971b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pLastGoodPosition = 0;
197250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    t->privateuse = T_CString_toLowerCase(pPrivuseVal);
1973b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1974b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* No more subtags, exiting the parse loop */
1975b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1976b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1977b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
1978b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1979b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* If we fell through here, it means this subtag is illegal - quit parsing */
1980b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        break;
1981b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1982b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1983b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pExtension != NULL) {
1984b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* Process the last extension */
198550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
1986b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* the previous extension is incomplete */
1987b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(pExtension);
1988b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1989b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* terminate the previous extension value */
1990b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *pExtValueSubtagEnd = 0;
199150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
1992b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* insert the extension to the list */
1993b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
1994b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pExtValueSubtagEnd;
1995b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
1996b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_free(pExtension);
1997b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1998b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1999b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2000b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2001b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (parsedLen != NULL) {
200250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        *parsedLen = (int32_t)(pLastGoodPosition - t->buf);
2003b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2004b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2005b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return t;
2006b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2007b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruerror:
2008b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(t);
2009b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return NULL;
2010b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2011b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2012b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
2013b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_close(ULanguageTag* langtag) {
2014b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2015b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag == NULL) {
2016b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
2017b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2018b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2019b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(langtag->buf);
2020b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2021b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag->variants) {
2022b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *curVar = langtag->variants;
2023b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (curVar) {
2024b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            VariantListEntry *nextVar = curVar->next;
2025b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(curVar);
2026b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            curVar = nextVar;
2027b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2028b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2029b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2030b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag->extensions) {
2031b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *curExt = langtag->extensions;
2032b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (curExt) {
2033b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ExtensionListEntry *nextExt = curExt->next;
2034b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(curExt);
2035b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            curExt = nextExt;
2036b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2037b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2038b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2039b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(langtag);
2040b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2041b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2042b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2043b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getLanguage(const ULanguageTag* langtag) {
2044b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->language;
2045b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2046b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2047b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
2048b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2049b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getJDKLanguage(const ULanguageTag* langtag) {
2050b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
2051b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; DEPRECATEDLANGS[i] != NULL; i += 2) {
205250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(DEPRECATEDLANGS[i], langtag->language) == 0) {
2053b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return DEPRECATEDLANGS[i + 1];
2054b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2055b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2056b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->language;
2057b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2058b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
2059b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2060b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2061b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlang(const ULanguageTag* langtag, int32_t idx) {
2062b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (idx >= 0 && idx < MAXEXTLANG) {
2063b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return langtag->extlang[idx];
2064b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2065b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return NULL;
2066b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2067b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2068b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2069b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlangSize(const ULanguageTag* langtag) {
2070b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2071b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
2072b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < MAXEXTLANG; i++) {
2073b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (langtag->extlang[i]) {
2074b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            size++;
2075b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2076b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2077b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2078b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2079b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2080b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2081b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getScript(const ULanguageTag* langtag) {
2082b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->script;
2083b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2084b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2085b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2086b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getRegion(const ULanguageTag* langtag) {
2087b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->region;
2088b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2089b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2090b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2091b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariant(const ULanguageTag* langtag, int32_t idx) {
2092b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *var = NULL;
2093b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry *cur = langtag->variants;
2094b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2095b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2096b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2097b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            var = cur->variant;
2098b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2099b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return var;
2104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariantsSize(const ULanguageTag* langtag) {
2108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry *cur = langtag->variants;
2110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (TRUE) {
2111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (cur == NULL) {
2112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        size++;
2115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx) {
2122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *key = NULL;
2123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            key = cur->key;
2128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return key;
2134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx) {
2138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *val = NULL;
2139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            val = cur->value;
2144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return val;
2150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionsSize(const ULanguageTag* langtag) {
2154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (TRUE) {
2157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (cur == NULL) {
2158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        size++;
2161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getPrivateUse(const ULanguageTag* langtag) {
2168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->privateuse;
2169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
2172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getGrandfathered(const ULanguageTag* langtag) {
2174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->grandfathered;
2175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
2177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Locale/BCP47 conversion APIs, exposed as uloc_*
2183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
2186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_DRAFT int32_t U_EXPORT2
2187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruuloc_toLanguageTag(const char* localeID,
2188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   char* langtag,
2189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   int32_t langtagCapacity,
2190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   UBool strict,
2191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   UErrorCode* status) {
2192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* char canonical[ULOC_FULLNAME_CAPACITY]; */ /* See #6822 */
2193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char canonical[256];
2194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
2195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
219627f654740f2a26ad62a5c155af9199af9e69b889claireho    UBool hadPosix = FALSE;
2197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "".  See #6835 */
2199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    canonical[0] = 0;
2200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (uprv_strlen(localeID) > 0) {
2201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uloc_canonicalize(localeID, canonical, sizeof(canonical), &tmpStatus);
2202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (tmpStatus != U_ZERO_ERROR) {
2203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
2204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
2205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendLanguageToLanguageTag(canonical, langtag, langtagCapacity, strict, status);
2209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendScriptToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
2210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendRegionToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
221127f654740f2a26ad62a5c155af9199af9e69b889claireho    reslen += _appendVariantsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, &hadPosix, status);
221227f654740f2a26ad62a5c155af9199af9e69b889claireho    reslen += _appendKeywordsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, hadPosix, status);
2213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
2215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste QueruU_DRAFT int32_t U_EXPORT2
2219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruuloc_forLanguageTag(const char* langtag,
2220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    char* localeID,
2221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    int32_t localeIDCapacity,
2222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    int32_t* parsedLength,
2223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    UErrorCode* status) {
2224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ULanguageTag *lt;
2225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
2226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *subtag, *p;
2227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len;
2228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i, n;
2229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool noRegion = TRUE;
2230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    lt = ultag_parse(langtag, -1, parsedLength, status);
2232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
2233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
2234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* language */
2237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getExtlangSize(lt) > 0 ? ultag_getExtlang(lt, 0) : ultag_getLanguage(lt);
223850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(subtag, LANG_UND) != 0) {
223950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(subtag);
2240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (len > 0) {
2241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(localeID, subtag, uprv_min(len, localeIDCapacity - reslen));
2243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
2245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* script */
2249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getScript(lt);
225050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    len = (int32_t)uprv_strlen(subtag);
2251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
2252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < localeIDCapacity) {
2253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(localeID + reslen) = LOCALE_SEP;
2254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen++;
2256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the script in title case */
2258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = subtag;
2259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*p) {
2260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (p == subtag) {
2262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = uprv_toupper(*p);
2263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
2264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = *p;
2265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
2269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* region */
2273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getRegion(lt);
227450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    len = (int32_t)uprv_strlen(subtag);
2275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
2276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < localeIDCapacity) {
2277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(localeID + reslen) = LOCALE_SEP;
2278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen++;
2280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the retion in upper case */
2281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = subtag;
2282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*p) {
2283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = uprv_toupper(*p);
2285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
2288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        noRegion = FALSE;
2290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* variants */
2293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getVariantsSize(lt);
2294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (n > 0) {
2295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (noRegion) {
2296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = LOCALE_SEP;
2298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (i = 0; i < n; i++) {
2303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            subtag = ultag_getVariant(lt, i);
2304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = LOCALE_SEP;
2306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* write out the variant in upper case */
2309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p = subtag;
2310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            while (*p) {
2311b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < localeIDCapacity) {
2312b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = uprv_toupper(*p);
2313b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen++;
2315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                p++;
2316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2319b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2320b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* keywords */
2321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getExtensionsSize(lt);
2322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getPrivateUse(lt);
2323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (n > 0 || uprv_strlen(subtag) > 0) {
2324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen == 0) {
2325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* need a language */
2326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(localeID + reslen, LANG_UND, uprv_min(LANG_UND_LEN, localeIDCapacity - reslen));
2328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += LANG_UND_LEN;
2330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        len = _appendKeywords(lt, localeID + reslen, localeIDCapacity - reslen, status);
2332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += len;
2333b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ultag_close(lt);
2336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(localeID, localeIDCapacity, reslen, status);
2337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2340