1b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru**********************************************************************
3103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius*   Copyright (C) 2009-2012, 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"
17b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "ulocimp.h"
1854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#include "uassert.h"
1954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
2054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius#define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof((array)[0]))
21b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
22b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* struct holding a single variant */
23b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct VariantListEntry {
24b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char              *variant;
25b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    struct VariantListEntry *next;
26b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} VariantListEntry;
27b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
28b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho/* struct holding a single attribute value */
29b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehotypedef struct AttributeListEntry {
30b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const char              *attribute;
31b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    struct AttributeListEntry *next;
32b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho} AttributeListEntry;
33b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
34b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* struct holding a single extension */
35b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct ExtensionListEntry {
36b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char                  *key;
37b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char                  *value;
38b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    struct ExtensionListEntry   *next;
39b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} ExtensionListEntry;
40b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
41b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAXEXTLANG 3
42b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querutypedef struct ULanguageTag {
43b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char                *buf;   /* holding parsed subtags */
44b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *language;
45b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *extlang[MAXEXTLANG];
46b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *script;
47b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *region;
48b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry    *variants;
49b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry  *extensions;
50b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *privateuse;
51b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char          *grandfathered;
52b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru} ULanguageTag;
53b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
54b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MINLEN 2
55b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define SEP '-'
56b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define PRIVATEUSE 'x'
57b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LDMLEXT 'u'
58b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
59b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_SEP '_'
60b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_EXT_SEP '@'
61b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_KEYWORD_SEP ';'
62b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LOCALE_KEY_TYPE_SEP '='
63b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
64103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius#define ISALPHA(c) uprv_isASCIILetter(c)
65b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define ISNUMERIC(c) ((c)>='0' && (c)<='9')
66b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
6754dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char EMPTY[] = "";
6854dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char LANG_UND[] = "und";
6954dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char PRIVATEUSE_KEY[] = "x";
7054dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char _POSIX[] = "_POSIX";
7154dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char POSIX_KEY[] = "va";
7254dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char POSIX_VALUE[] = "posix";
7354dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char LOCALE_ATTRIBUTE_KEY[] = "attribute";
7454dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char PRIVUSE_VARIANT_PREFIX[] = "lvariant";
7554dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char LOCALE_TYPE_YES[] = "yes";
76b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
77b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LANG_UND_LEN 3
78b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
7954dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char* const GRANDFATHERED[] = {
80b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*  grandfathered   preferred */
81b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "art-lojban",   "jbo",
82b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "cel-gaulish",  "xtg-x-cel-gaulish",
83b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "en-GB-oed",    "en-GB-x-oed",
84b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-ami",        "ami",
85b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-bnn",        "bnn",
86b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "i-default",    "en-x-i-default",
87b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "i-enochian",   "und-x-i-enochian",
88b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-hak",        "hak",
89b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-klingon",    "tlh",
90b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-lux",        "lb",
91b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "i-mingo",      "see-x-i-mingo",
92b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-navajo",     "nv",
93b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-pwn",        "pwn",
94b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tao",        "tao",
95b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tay",        "tay",
96b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "i-tsu",        "tsu",
97b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "no-bok",       "nb",
98b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "no-nyn",       "nn",
99b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-be-fr",    "sfb",
100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-be-nl",    "vgt",
101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "sgn-ch-de",    "sgg",
102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-guoyu",     "cmn",
103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-hakka",     "hak",
104b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    "zh-min",       "nan-x-zh-min",
105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-min-nan",   "nan",
106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "zh-xiang",     "hsn",
107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    NULL,           NULL
108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
11054dcd9b6a06071f647dac967e9e267abb9410720Craig Corneliusstatic const char DEPRECATEDLANGS[][4] = {
111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*  deprecated  new */
112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "iw",       "he",
113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    "ji",       "yi",
11454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    "in",       "id"
115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru};
116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* These ultag_ functions may be exposed as APIs later
121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic ULanguageTag*
126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status);
127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_close(ULanguageTag* langtag);
130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getLanguage(const ULanguageTag* langtag);
133b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getJDKLanguage(const ULanguageTag* langtag);
137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlang(const ULanguageTag* langtag, int32_t idx);
141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlangSize(const ULanguageTag* langtag);
144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getScript(const ULanguageTag* langtag);
147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getRegion(const ULanguageTag* langtag);
150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariant(const ULanguageTag* langtag, int32_t idx);
153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariantsSize(const ULanguageTag* langtag);
156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx);
159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx);
162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionsSize(const ULanguageTag* langtag);
165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getPrivateUse(const ULanguageTag* langtag);
168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getGrandfathered(const ULanguageTag* langtag);
172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Language subtag syntax validation functions
178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
183b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isAlphaString(const char* s, int32_t len) {
184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISALPHA(*(s + i))) {
187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
188b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isNumericString(const char* s, int32_t len) {
195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISNUMERIC(*(s + i))) {
198b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isAlphaNumericString(const char* s, int32_t len) {
206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < len; i++) {
208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ISALPHA(*(s + i)) && !ISNUMERIC(*(s + i))) {
209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return FALSE;
210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return TRUE;
213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLanguageSubtag(const char* s, int32_t len) {
217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * language      = 2*3ALPHA            ; shortest ISO 639 code
219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                 ["-" extlang]       ; sometimes followed by
220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                                     ;   extended language subtags
221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 4ALPHA              ; or reserved for future use
222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 5*8ALPHA            ; or registered language subtag
223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
22550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 2 && len <= 8 && _isAlphaString(s, len)) {
228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtlangSubtag(const char* s, int32_t len) {
235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extlang       = 3ALPHA              ; selected ISO 639 codes
237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                 *2("-" 3ALPHA)      ; permanently reserved
238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
24050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 3 && _isAlphaString(s, len)) {
243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isScriptSubtag(const char* s, int32_t len) {
250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * script        = 4ALPHA              ; ISO 15924 code
252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
25450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 4 && _isAlphaString(s, len)) {
257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isRegionSubtag(const char* s, int32_t len) {
264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * region        = 2ALPHA              ; ISO 3166-1 code
266b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / 3DIGIT              ; UN M.49 code
267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
26950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 2 && _isAlphaString(s, len)) {
272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 3 && _isNumericString(s, len)) {
275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isVariantSubtag(const char* s, int32_t len) {
282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * variant       = 5*8alphanum         ; registered variants
284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *               / (DIGIT 3alphanum)
285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
28750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
289b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (len >= 5 && len <= 8 && _isAlphaNumericString(s, len)) {
290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 4 && ISNUMERIC(*s) && _isAlphaNumericString(s + 1, 3)) {
293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
299b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho_isPrivateuseVariantSubtag(const char* s, int32_t len) {
300b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    /*
301b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho     * variant       = 1*8alphanum         ; registered variants
302b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho     *               / (DIGIT 3alphanum)
303b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho     */
304b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (len < 0) {
305b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        len = (int32_t)uprv_strlen(s);
306b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
307b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (len >= 1 && len <= 8 && _isAlphaNumericString(s, len)) {
308b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return TRUE;
309b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
310b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return FALSE;
311b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
312b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
313b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UBool
314b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSingleton(const char* s, int32_t len) {
315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extension     = singleton 1*("-" (2*8alphanum))
317b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
318b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
31950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
320b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
321b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 1 && ISALPHA(*s) && (uprv_tolower(*s) != PRIVATEUSE)) {
322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
325b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSubtag(const char* s, int32_t len) {
329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
330b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * extension     = singleton 1*("-" (2*8alphanum))
331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
33350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 2 && len <= 8 && _isAlphaNumericString(s, len)) {
336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
338b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isExtensionSubtags(const char* s, int32_t len) {
343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *p = s;
344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pSubtag = NULL;
345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
34750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while ((p - s) < len) {
351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*p == SEP) {
352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (pSubtag == NULL) {
353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
35550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!_isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag))) {
356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = NULL;
359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (pSubtag == NULL) {
360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = p;
361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p++;
363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pSubtag == NULL) {
365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return FALSE;
366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
36750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return _isExtensionSubtag(pSubtag, (int32_t)(p - pSubtag));
368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isPrivateuseValueSubtag(const char* s, int32_t len) {
372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * privateuse    = "x" 1*("-" (1*8alphanum))
374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
37650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 1 && len <= 8 && _isAlphaNumericString(s, len)) {
379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isPrivateuseValueSubtags(const char* s, int32_t len) {
386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *p = s;
387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *pSubtag = NULL;
388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
39050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while ((p - s) < len) {
394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*p == SEP) {
395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (pSubtag == NULL) {
396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
39850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (!_isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag))) {
399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                return FALSE;
400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = NULL;
402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else if (pSubtag == NULL) {
403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSubtag = p;
404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p++;
406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pSubtag == NULL) {
408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return FALSE;
409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
41050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return _isPrivateuseValueSubtag(pSubtag, (int32_t)(p - pSubtag));
411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLDMLKey(const char* s, int32_t len) {
415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
41650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 2 && _isAlphaNumericString(s, len)) {
419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_isLDMLType(const char* s, int32_t len) {
426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len < 0) {
42750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(s);
428b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len >= 3 && len <= 8 && _isAlphaNumericString(s, len)) {
430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return TRUE;
431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return FALSE;
433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Helper functions
439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_addVariantToList(VariantListEntry **first, VariantListEntry *var) {
445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool bAdded = TRUE;
446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (*first == NULL) {
448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        var->next = NULL;
449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *first = var;
450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *prev, *cur;
452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t cmp;
453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
454b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        /* variants order should be preserved */
455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        prev = NULL;
456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = *first;
457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cur == NULL) {
459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                prev->next = var;
460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var->next = NULL;
461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
463b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            /* Checking for duplicate variant */
46550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            cmp = uprv_compareInvCharsAsAscii(var->variant, cur->variant);
466b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (cmp == 0) {
467b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                /* duplicated variant */
468b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                bAdded = FALSE;
469b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                break;
470b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
471b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            prev = cur;
472b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cur = cur->next;
473b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
474b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
475b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
476b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return bAdded;
477b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
478b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
479b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic UBool
480b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho_addAttributeToList(AttributeListEntry **first, AttributeListEntry *attr) {
481b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool bAdded = TRUE;
482b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
483b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (*first == NULL) {
484b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        attr->next = NULL;
485b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        *first = attr;
486b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    } else {
487b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        AttributeListEntry *prev, *cur;
488b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int32_t cmp;
489b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
490b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        /* reorder variants in alphabetical order */
491b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        prev = NULL;
492b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        cur = *first;
493b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        while (TRUE) {
494b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (cur == NULL) {
495b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                prev->next = attr;
496b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                attr->next = NULL;
497b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                break;
498b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
499b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            cmp = uprv_compareInvCharsAsAscii(attr->attribute, cur->attribute);
500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp < 0) {
501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (prev == NULL) {
502b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    *first = attr;
503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
504b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    prev->next = attr;
505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
506b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                attr->next = cur;
507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp == 0) {
510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* duplicated variant */
511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bAdded = FALSE;
512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            prev = cur;
515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            cur = cur->next;
516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return bAdded;
520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic UBool
524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_addExtensionToList(ExtensionListEntry **first, ExtensionListEntry *ext, UBool localeToBCP) {
525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool bAdded = TRUE;
526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (*first == NULL) {
528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ext->next = NULL;
529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *first = ext;
530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *prev, *cur;
532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t cmp;
533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* reorder variants in alphabetical order */
535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        prev = NULL;
536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = *first;
537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cur == NULL) {
539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                prev->next = ext;
540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ext->next = NULL;
541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (localeToBCP) {
544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* special handling for locale to bcp conversion */
545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t len, curlen;
546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
54750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(ext->key);
54850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                curlen = (int32_t)uprv_strlen(cur->key);
549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
550b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (len == 1 && curlen == 1) {
551b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (*(ext->key) == *(cur->key)) {
552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = 0;
553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (*(ext->key) == PRIVATEUSE) {
554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = 1;
555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (*(cur->key) == PRIVATEUSE) {
556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = -1;
557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        cmp = *(ext->key) - *(cur->key);
559b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
560b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else if (len == 1) {
561b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    cmp = *(ext->key) - LDMLEXT;
562b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else if (curlen == 1) {
563b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    cmp = LDMLEXT - *(cur->key);
564b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
56550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
567b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
56850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                cmp = uprv_compareInvCharsAsAscii(ext->key, cur->key);
569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp < 0) {
571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (prev == NULL) {
572b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *first = ext;
573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    prev->next = ext;
575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                ext->next = cur;
577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (cmp == 0) {
580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* duplicated extension key */
581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bAdded = FALSE;
582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            prev = cur;
585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            cur = cur->next;
586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
589b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return bAdded;
590b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_initializeULanguageTag(ULanguageTag* langtag) {
594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->buf = NULL;
597b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->language = EMPTY;
599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < MAXEXTLANG; i++) {
600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        langtag->extlang[i] = NULL;
601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->script = EMPTY;
604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->region = EMPTY;
605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->variants = NULL;
607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->extensions = NULL;
608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->grandfathered = EMPTY;
610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    langtag->privateuse = EMPTY;
611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
612b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
61350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define KEYTYPEDATA     "keyTypeData"
61450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define KEYMAP          "keyMap"
61550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define TYPEMAP         "typeMap"
61650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho#define TYPEALIAS       "typeAlias"
617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_BCP47_SUBTAG_LEN    9   /* including null terminator */
618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_LDML_KEY_LEN        22
619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define MAX_LDML_TYPE_LEN       32
620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
622b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_ldmlKeyToBCP47(const char* key, int32_t keyLen,
623b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char* bcpKey, int32_t bcpKeyCapacity,
624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UErrorCode *status) {
625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
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    UErrorCode tmpStatus = U_ZERO_ERROR;
631b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const UChar *uBcpKey;
632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t bcpKeyLen;
633b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
634b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
63550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
636b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
638b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
639b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
640b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
643b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
644b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
645b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
646b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
647b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
648b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
649b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
650b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
651b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
65250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
65350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, KEYMAP, rb, status);
654b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
655b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
656b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
657b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
658b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
659b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
660b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uBcpKey = ures_getStringByKey(rb, keyBuf, &bcpKeyLen, &tmpStatus);
661b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(tmpStatus)) {
662b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpKey, bcpKeyBuf, bcpKeyLen);
663b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpKeyBuf[bcpKeyLen] = 0;
664b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpKeyLen;
665b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
666b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (_isLDMLKey(key, keyLen)) {
667b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(bcpKeyBuf, key, keyLen);
668b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bcpKeyBuf[keyLen] = 0;
669b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            resultLen = keyLen;
670b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
671b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* mapping not availabe */
672b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
673b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
674b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
675b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
676b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
677b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
678b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
679b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
680b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpKey, bcpKeyBuf, uprv_min(resultLen, bcpKeyCapacity));
682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(bcpKey, bcpKeyCapacity, resultLen, status);
683b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
684b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
685b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_bcp47ToLDMLKey(const char* bcpKey, int32_t bcpKeyLen,
687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char* key, int32_t keyCapacity,
688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UErrorCode *status) {
689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
691b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *resKey = NULL;
69450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *mapData;
695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpKeyLen < 0) {
69750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        bcpKeyLen = (int32_t)uprv_strlen(bcpKey);
698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpKeyLen >= sizeof(bcpKeyBuf)) {
701b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpKeyBuf, bcpKey, bcpKeyLen);
706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bcpKeyBuf[bcpKeyLen] = 0;
707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
708b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
709b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < bcpKeyLen; i++) {
710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpKeyBuf[i] = uprv_tolower(bcpKeyBuf[i]);
711b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
712b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
71350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
71450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, KEYMAP, rb, status);
715b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
72050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    mapData = ures_getNextResource(rb, NULL, status);
721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (U_SUCCESS(*status)) {
722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const UChar *uBcpKey;
723b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char tmpBcpKeyBuf[MAX_BCP47_SUBTAG_LEN];
724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t tmpBcpKeyLen;
725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
72650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uBcpKey = ures_getString(mapData, &tmpBcpKeyLen, status);
727b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpKey, tmpBcpKeyBuf, tmpBcpKeyLen);
731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpBcpKeyBuf[tmpBcpKeyLen] = 0;
73250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(bcpKeyBuf, tmpBcpKeyBuf) == 0) {
733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* found a matching BCP47 key */
73450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resKey = ures_getKey(mapData);
73550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resultLen = (int32_t)uprv_strlen(resKey);
736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ures_hasNext(rb)) {
739b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
740b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
74150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getNextResource(rb, mapData, status);
742b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
74350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(mapData);
744b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
745b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
746b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
747b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
748b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
749b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (resKey == NULL) {
751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resKey = bcpKeyBuf;
752b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpKeyLen;
753b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
754b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(key, resKey, uprv_min(resultLen, keyCapacity));
756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(key, keyCapacity, resultLen, status);
757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
760b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_ldmlTypeToBCP47(const char* key, int32_t keyLen,
761b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 const char* type, int32_t typeLen,
762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 char* bcpType, int32_t bcpTypeCapacity,
763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 UErrorCode *status) {
76450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *rb, *keyTypeData, *typeMapForKey;
765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char typeBuf[MAX_LDML_TYPE_LEN];
767b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char bcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
768b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
769b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
770b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
77150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    const UChar *uBcpType, *uCanonicalType;
77250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t bcpTypeLen, canonicalTypeLen;
773b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool isTimezone = FALSE;
774b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
775b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
77650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
777b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
785b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
786b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
787b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
788b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
789b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
79050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
791b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        isTimezone = TRUE;
792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (typeLen < 0) {
79550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeLen = (int32_t)uprv_strlen(type);
796b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
797b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (typeLen >= sizeof(typeBuf)) {
798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
80250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (isTimezone) {
80350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        /* replace '/' with ':' */
80450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        for (i = 0; i < typeLen; i++) {
80550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (*(type + i) == '/') {
80650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                typeBuf[i] = ':';
80750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
80850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                typeBuf[i] = *(type + i);
80950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
81150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        typeBuf[typeLen] = 0;
81250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        type = &typeBuf[0];
813b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
814b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
81550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    keyTypeData = ures_openDirect(NULL, KEYTYPEDATA, status);
81650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_getByKey(keyTypeData, TYPEMAP, NULL, status);
817b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
818b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
81950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_close(keyTypeData);
820b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
821b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
822b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
82350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    typeMapForKey = ures_getByKey(rb, keyBuf, NULL, &tmpStatus);
82450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    uBcpType = ures_getStringByKey(typeMapForKey, type, &bcpTypeLen, &tmpStatus);
825b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(tmpStatus)) {
826b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
827b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpTypeLen;
828b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
82950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        /* is this type alias? */
83050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        tmpStatus = U_ZERO_ERROR;
83150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(keyTypeData, TYPEALIAS, rb, &tmpStatus);
83250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getByKey(rb, keyBuf, rb, &tmpStatus);
83350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uCanonicalType = ures_getStringByKey(rb, type, &canonicalTypeLen, &tmpStatus);
83450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (U_SUCCESS(tmpStatus)) {
83550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            u_UCharsToChars(uCanonicalType, typeBuf, canonicalTypeLen);
83650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (isTimezone) {
83750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* replace '/' with ':' */
83850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                for (i = 0; i < canonicalTypeLen; i++) {
83950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (typeBuf[i] == '/') {
84050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        typeBuf[i] = ':';
84150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
84250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
84350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
84450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            typeBuf[canonicalTypeLen] = 0;
84550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
84650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            /* look up the canonical type */
84750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            uBcpType = ures_getStringByKey(typeMapForKey, typeBuf, &bcpTypeLen, &tmpStatus);
84850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (U_SUCCESS(tmpStatus)) {
84950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                u_UCharsToChars(uBcpType, bcpTypeBuf, bcpTypeLen);
85050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                resultLen = bcpTypeLen;
85150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
85250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
85350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (tmpStatus == U_MISSING_RESOURCE_ERROR) {
85450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (_isLDMLType(type, typeLen)) {
85550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                uprv_memcpy(bcpTypeBuf, type, typeLen);
85650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                resultLen = typeLen;
85750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            } else {
85850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* mapping not availabe */
85950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *status = U_ILLEGAL_ARGUMENT_ERROR;
86050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
861b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
862b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
863b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = tmpStatus;
864b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
865b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
86650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(typeMapForKey);
86750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(keyTypeData);
868b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
869b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
870b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
871b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
872b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
873b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpType, bcpTypeBuf, uprv_min(resultLen, bcpTypeCapacity));
874b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(bcpType, bcpTypeCapacity, resultLen, status);
875b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
876b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
877b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
878b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_bcp47ToLDMLType(const char* key, int32_t keyLen,
879b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 const char* bcpType, int32_t bcpTypeLen,
880b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 char* type, int32_t typeCapacity,
881b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 UErrorCode *status) {
882b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UResourceBundle *rb;
883b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char keyBuf[MAX_LDML_KEY_LEN];
884b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    char bcpTypeBuf[ULOC_KEYWORDS_CAPACITY]; /* ensure buffter is large enough for multiple values (e.g. buddhist-greg) */
885b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t resultLen = 0;
886b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t i, typeSize;
887b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *resType = NULL;
88850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    UResourceBundle *mapData;
889b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
890b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t copyLen;
891b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
892b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen < 0) {
89350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        keyLen = (int32_t)uprv_strlen(key);
894b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
895b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
896b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (keyLen >= sizeof(keyBuf)) {
897b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* no known valid LDML key exceeding 21 */
898b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
899b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
900b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
901b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(keyBuf, key, keyLen);
902b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keyBuf[keyLen] = 0;
903b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
904b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
905b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < keyLen; i++) {
906b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        keyBuf[i] = uprv_tolower(keyBuf[i]);
907b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
908b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
909b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
910b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (bcpTypeLen < 0) {
91150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        bcpTypeLen = (int32_t)uprv_strlen(bcpType);
912b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
913b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
914b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    typeSize = 0;
915b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    for (i = 0; i < bcpTypeLen; i++) {
916b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (bcpType[i] == SEP) {
917b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (typeSize >= MAX_BCP47_SUBTAG_LEN) {
918b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                *status = U_ILLEGAL_ARGUMENT_ERROR;
919b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                return 0;
920b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
921b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            typeSize = 0;
922b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        } else {
923b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            typeSize++;
924b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
925b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
926b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
927b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(bcpTypeBuf, bcpType, bcpTypeLen);
928b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    bcpTypeBuf[bcpTypeLen] = 0;
929b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
930b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* to lower case */
931b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < bcpTypeLen; i++) {
932b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        bcpTypeBuf[i] = uprv_tolower(bcpTypeBuf[i]);
933b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
934b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
93550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    rb = ures_openDirect(NULL, KEYTYPEDATA, status);
93650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_getByKey(rb, TYPEMAP, rb, status);
937b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ures_close(rb);
939b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
940b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
941b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
942b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_getByKey(rb, keyBuf, rb, &tmpStatus);
94350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    mapData = ures_getNextResource(rb, NULL, &tmpStatus);
944b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (U_SUCCESS(tmpStatus)) {
945b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const UChar *uBcpType;
946b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char tmpBcpTypeBuf[MAX_BCP47_SUBTAG_LEN];
947b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t tmpBcpTypeLen;
948b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
94950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        uBcpType = ures_getString(mapData, &tmpBcpTypeLen, &tmpStatus);
950b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(tmpStatus)) {
951b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
952b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
953b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        u_UCharsToChars(uBcpType, tmpBcpTypeBuf, tmpBcpTypeLen);
954b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        tmpBcpTypeBuf[tmpBcpTypeLen] = 0;
95550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(bcpTypeBuf, tmpBcpTypeBuf) == 0) {
956b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* found a matching BCP47 type */
95750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resType = ures_getKey(mapData);
95850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            resultLen = (int32_t)uprv_strlen(resType);
959b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
960b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
961b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!ures_hasNext(rb)) {
962b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
963b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
96450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ures_getNextResource(rb, mapData, &tmpStatus);
965b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
96650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ures_close(mapData);
967b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ures_close(rb);
968b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
969b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) && tmpStatus != U_MISSING_RESOURCE_ERROR) {
970b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = tmpStatus;
971b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
972b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
973b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
974b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (resType == NULL) {
975b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resType = bcpTypeBuf;
976b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        resultLen = bcpTypeLen;
977b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
978b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
979b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    copyLen = uprv_min(resultLen, typeCapacity);
980b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(type, resType, copyLen);
981b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
98250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(keyBuf, "timezone") == 0) {
983b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (i = 0; i < copyLen; i++) {
984b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*(type + i) == ':') {
985b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(type + i) = '/';
986b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
987b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
988b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
989b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
990b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(type, typeCapacity, resultLen, status);
991b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
992b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
993b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
994b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendLanguageToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
995b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_LANG_CAPACITY];
996b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
997b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len, i;
998b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
999b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1000b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1001b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1002b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1003b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1004b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getLanguage(localeID, buf, sizeof(buf), &tmpStatus);
1005b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1006b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1007b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1008b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1009b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1010b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        len = 0;
1011b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1012b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1013b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Note: returned language code is in lower case letters */
1014b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1015b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len == 0) {
1016b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
1017b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
1018b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1019b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += LANG_UND_LEN;
1020b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else if (!_isLanguageSubtag(buf, len)) {
1021b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid language code */
1022b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1023b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1024b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1025b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1026b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
1027b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, LANG_UND, uprv_min(LANG_UND_LEN, capacity - reslen));
1028b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1029b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += LANG_UND_LEN;
1030b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    } else {
1031b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* resolve deprecated */
103254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        for (i = 0; i < LENGTHOF(DEPRECATEDLANGS); i += 2) {
103350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (uprv_compareInvCharsAsAscii(buf, DEPRECATEDLANGS[i]) == 0) {
1034b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_strcpy(buf, DEPRECATEDLANGS[i + 1]);
103550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len = (int32_t)uprv_strlen(buf);
1036b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1037b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1038b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1039b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < capacity) {
1040b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
1041b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1042b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += len;
1043b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1044b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1045b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1046b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1047b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1048b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
1049b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendScriptToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
1050b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_SCRIPT_CAPACITY];
1051b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
105250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t len;
1053b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1054b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1055b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1056b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1057b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1058b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1059b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getScript(localeID, buf, sizeof(buf), &tmpStatus);
1060b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1061b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1062b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1063b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1064b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1065b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1066b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1067b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
1068b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!_isScriptSubtag(buf, len)) {
1069b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid script code */
1070b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (strict) {
1071b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1072b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1073b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1074b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1075b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1076b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(appendAt + reslen) = SEP;
1077b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1078b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1079b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1080b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1081b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
1082b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1083b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1084b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1085b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1086b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1087b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1088b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1089b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1090b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
1091b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendRegionToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UErrorCode* status) {
1092b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_COUNTRY_CAPACITY];
1093b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
109450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t len;
1095b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1096b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1097b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1098b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1099b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getCountry(localeID, buf, sizeof(buf), &tmpStatus);
1102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
1110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (!_isRegionSubtag(buf, len)) {
1111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* invalid region code */
1112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (strict) {
1113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
1117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1118b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(appendAt + reslen) = SEP;
1119b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(appendAt + reslen, buf, uprv_min(len, capacity - reslen));
1124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
1126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1128b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1129b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1130b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1131b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1132b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
113327f654740f2a26ad62a5c155af9199af9e69b889claireho_appendVariantsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool *hadPosix, UErrorCode* status) {
1134b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_FULLNAME_CAPACITY];
1135b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
1136b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len, i;
1137b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1138b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1139b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1140b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1141b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1143b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
1144b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (strict) {
1146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
1147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
1152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *p, *pVar;
1153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UBool bNext = TRUE;
1154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *var;
1155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *varFirst = NULL;
1156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pVar = NULL;
1158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = buf;
1159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (bNext) {
1160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
1161b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (*p == 0) {
1162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    bNext = FALSE;
1163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *p = 0; /* terminate */
1165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pVar == NULL) {
1167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* ignore empty variant */
1172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
117350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    /* ICU uses upper case letters for variants, but
117450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                       the canonical format is lowercase in BCP47 */
1175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    for (i = 0; *(pVar + i) != 0; i++) {
1176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(pVar + i) = uprv_tolower(*(pVar + i));
1177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* validate */
1180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (_isVariantSubtag(pVar, -1)) {
1181b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (uprv_strcmp(pVar,POSIX_VALUE) || len != uprv_strlen(POSIX_VALUE)) {
118227f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* emit the variant to the list */
118354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                            var = (VariantListEntry*)uprv_malloc(sizeof(VariantListEntry));
118427f654740f2a26ad62a5c155af9199af9e69b889claireho                            if (var == NULL) {
118527f654740f2a26ad62a5c155af9199af9e69b889claireho                                *status = U_MEMORY_ALLOCATION_ERROR;
1186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                                break;
1187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            }
118827f654740f2a26ad62a5c155af9199af9e69b889claireho                            var->variant = pVar;
118927f654740f2a26ad62a5c155af9199af9e69b889claireho                            if (!_addVariantToList(&varFirst, var)) {
119027f654740f2a26ad62a5c155af9199af9e69b889claireho                                /* duplicated variant */
119127f654740f2a26ad62a5c155af9199af9e69b889claireho                                uprv_free(var);
119227f654740f2a26ad62a5c155af9199af9e69b889claireho                                if (strict) {
119327f654740f2a26ad62a5c155af9199af9e69b889claireho                                    *status = U_ILLEGAL_ARGUMENT_ERROR;
119427f654740f2a26ad62a5c155af9199af9e69b889claireho                                    break;
119527f654740f2a26ad62a5c155af9199af9e69b889claireho                                }
119627f654740f2a26ad62a5c155af9199af9e69b889claireho                            }
119727f654740f2a26ad62a5c155af9199af9e69b889claireho                        } else {
119827f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* Special handling for POSIX variant, need to remember that we had it and then */
119927f654740f2a26ad62a5c155af9199af9e69b889claireho                            /* treat it like an extension later. */
120027f654740f2a26ad62a5c155af9199af9e69b889claireho                            *hadPosix = TRUE;
1201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else if (strict) {
1203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1205b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else if (_isPrivateuseValueSubtag(pVar, -1)) {
1206b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        /* Handle private use subtags separately */
1207b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
1208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* reset variant starting position */
1211b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pVar = NULL;
1212b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else if (pVar == NULL) {
1213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pVar = p;
1214b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1215b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
1216b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1217b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1218b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_SUCCESS(*status)) {
1219b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (varFirst != NULL) {
1220b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t varLen;
1221b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1222b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                /* write out validated/normalized variants to the target */
1223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var = varFirst;
1224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                while (var != NULL) {
1225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(appendAt + reslen) = SEP;
1227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
122950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    varLen = (int32_t)uprv_strlen(var->variant);
1230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_memcpy(appendAt + reslen, var->variant, uprv_min(varLen, capacity - reslen));
1232b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen += varLen;
1234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    var = var->next;
1235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* clean up */
1240b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        var = varFirst;
1241b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (var != NULL) {
1242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            VariantListEntry *tmpVar = var->next;
1243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(var);
1244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            var = tmpVar;
1245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
1248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1251b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    u_terminateChars(appendAt, capacity, reslen, status);
1253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
1254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
125727f654740f2a26ad62a5c155af9199af9e69b889claireho_appendKeywordsToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool hadPosix, UErrorCode* status) {
1258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char buf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1259103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    char attrBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY] = { 0 };
1260b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t attrBufLength = 0;
1261b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UBool isAttribute = FALSE;
1262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UEnumeration *keywordEnum = NULL;
1263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    keywordEnum = uloc_openKeywords(localeID, status);
126627f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_FAILURE(*status) && !hadPosix) {
1267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uenum_close(keywordEnum);
1268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1269b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
127027f654740f2a26ad62a5c155af9199af9e69b889claireho    if (keywordEnum != NULL || hadPosix) {
1271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* reorder extensions */
1272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t len;
1273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const char *key;
1274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *firstExt = NULL;
1275b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *ext;
1276b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        AttributeListEntry *firstAttr = NULL;
1277b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        AttributeListEntry *attr;
1278b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        char *attrValue;
1279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char extBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *pExtBuf = extBuf;
1281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t extBufCapacity = sizeof(extBuf);
1282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        const char *bcpKey, *bcpValue;
1283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UErrorCode tmpStatus = U_ZERO_ERROR;
1284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        int32_t keylen;
1285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        UBool isLDMLKeyword;
1286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (TRUE) {
1288b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            isAttribute = FALSE;
1289b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            key = uenum_next(keywordEnum, NULL, status);
1290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (key == NULL) {
1291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            len = uloc_getKeywordValue(localeID, key, buf, sizeof(buf), &tmpStatus);
1294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(tmpStatus)) {
1295b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (strict) {
1296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1299b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* ignore this keyword */
1300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                tmpStatus = U_ZERO_ERROR;
1301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
1302b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
130450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            keylen = (int32_t)uprv_strlen(key);
1305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            isLDMLKeyword = (keylen > 1);
1306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1307b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            /* special keyword used for representing Unicode locale attributes */
1308b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (uprv_strcmp(key, LOCALE_ATTRIBUTE_KEY) == 0) {
1309b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                isAttribute = TRUE;
1310b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (len > 0) {
1311b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    int32_t i = 0;
1312b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    while (TRUE) {
1313b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        attrBufLength = 0;
1314b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        for (; i < len; i++) {
1315b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (buf[i] != '-') {
1316b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                attrBuf[attrBufLength++] = buf[i];
1317b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            } else {
1318b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                i++;
1319b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                break;
1320b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
1321b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
1322b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (attrBufLength > 0) {
1323b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            attrBuf[attrBufLength] = 0;
1324b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1325b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        } else if (i >= len){
1326b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            break;
1327b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
1328b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1329b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        /* create AttributeListEntry */
133054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry));
1331b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (attr == NULL) {
1332b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            *status = U_MEMORY_ALLOCATION_ERROR;
1333b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            break;
1334b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
133554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        attrValue = (char*)uprv_malloc(attrBufLength + 1);
1336b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (attrValue == NULL) {
1337b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            *status = U_MEMORY_ALLOCATION_ERROR;
1338b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            break;
1339b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
1340b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        uprv_strcpy(attrValue, attrBuf);
1341b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        attr->attribute = attrValue;
1342b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1343b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (!_addAttributeToList(&firstAttr, attr)) {
1344b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            uprv_free(attr);
1345b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            uprv_free(attrValue);
1346b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (strict) {
1347b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                *status = U_ILLEGAL_ARGUMENT_ERROR;
1348b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                break;
1349b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
1350b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
1351b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1352b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1353b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else if (isLDMLKeyword) {
1354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                int32_t modKeyLen;
1355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* transform key and value to bcp47 style */
1357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                modKeyLen = _ldmlKeyToBCP47(key, keylen, pExtBuf, extBufCapacity, &tmpStatus);
1358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    tmpStatus = U_ZERO_ERROR;
1364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    continue;
1365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpKey = pExtBuf;
1368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtBuf += (modKeyLen + 1);
1369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                extBufCapacity -= (modKeyLen + 1);
1370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                len = _ldmlTypeToBCP47(key, keylen, buf, len, pExtBuf, extBufCapacity, &tmpStatus);
1372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (strict) {
1374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
1376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1377b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    tmpStatus = U_ZERO_ERROR;
1378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    continue;
1379b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1380b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpValue = pExtBuf;
1381b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtBuf += (len + 1);
1382b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                extBufCapacity -= (len + 1);
1383b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
1384b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (*key == PRIVATEUSE) {
1385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (!_isPrivateuseValueSubtags(buf, len)) {
1386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (strict) {
1387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            *status = U_ILLEGAL_ARGUMENT_ERROR;
1388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1390b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        continue;
1391b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1392b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1393b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (!_isExtensionSingleton(key, keylen) || !_isExtensionSubtags(buf, len)) {
1394b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (strict) {
1395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            *status = U_ILLEGAL_ARGUMENT_ERROR;
1396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
1397b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
1398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        continue;
1399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                bcpKey = key;
1402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if ((len + 1) < extBufCapacity) {
1403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_memcpy(pExtBuf, buf, len);
1404b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    bcpValue = pExtBuf;
1405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pExtBuf += len;
1407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pExtBuf = 0;
1409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pExtBuf++;
1410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1411b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    extBufCapacity -= (len + 1);
1412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
1413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1417b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1418b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (!isAttribute) {
1419b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                /* create ExtensionListEntry */
142054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                ext = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
1421b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (ext == NULL) {
1422b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    *status = U_MEMORY_ALLOCATION_ERROR;
1423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
1424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1425b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                ext->key = bcpKey;
1426b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                ext->value = bcpValue;
1427b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1428b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (!_addExtensionToList(&firstExt, ext, TRUE)) {
1429b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    uprv_free(ext);
1430b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (strict) {
1431b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1432b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
1433b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1434b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
143727f654740f2a26ad62a5c155af9199af9e69b889claireho
143827f654740f2a26ad62a5c155af9199af9e69b889claireho        /* Special handling for POSIX variant - add the keywords for POSIX */
143927f654740f2a26ad62a5c155af9199af9e69b889claireho        if (hadPosix) {
144027f654740f2a26ad62a5c155af9199af9e69b889claireho            /* create ExtensionListEntry for POSIX */
144154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            ext = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
144227f654740f2a26ad62a5c155af9199af9e69b889claireho            if (ext == NULL) {
144327f654740f2a26ad62a5c155af9199af9e69b889claireho                *status = U_MEMORY_ALLOCATION_ERROR;
1444b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                goto cleanup;
144527f654740f2a26ad62a5c155af9199af9e69b889claireho            }
144627f654740f2a26ad62a5c155af9199af9e69b889claireho            ext->key = POSIX_KEY;
144727f654740f2a26ad62a5c155af9199af9e69b889claireho            ext->value = POSIX_VALUE;
144827f654740f2a26ad62a5c155af9199af9e69b889claireho
144927f654740f2a26ad62a5c155af9199af9e69b889claireho            if (!_addExtensionToList(&firstExt, ext, TRUE)) {
145027f654740f2a26ad62a5c155af9199af9e69b889claireho                uprv_free(ext);
145127f654740f2a26ad62a5c155af9199af9e69b889claireho            }
145227f654740f2a26ad62a5c155af9199af9e69b889claireho        }
145327f654740f2a26ad62a5c155af9199af9e69b889claireho
1454b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_SUCCESS(*status) && (firstExt != NULL || firstAttr != NULL)) {
1455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            UBool startLDMLExtension = FALSE;
1456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1457b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            attr = firstAttr;
1458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext = firstExt;
1459b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            do {
1460b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (!startLDMLExtension && (ext && uprv_strlen(ext->key) > 1)) {
1461b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   /* write LDML singleton extension */
1462b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   if (reslen < capacity) {
1463b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                       *(appendAt + reslen) = SEP;
1464b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   }
1465b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   reslen++;
1466b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   if (reslen < capacity) {
1467b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                       *(appendAt + reslen) = LDMLEXT;
1468b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   }
1469b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   reslen++;
1470b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1471b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                   startLDMLExtension = TRUE;
1472b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1473b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1474b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                /* write out the sorted BCP47 attributes, extensions and private use */
1475b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (ext && (uprv_strlen(ext->key) == 1 || attr == NULL)) {
1476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *(appendAt + reslen) = SEP;
1478b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
1480b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    len = (int32_t)uprv_strlen(ext->key);
1481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (reslen < capacity) {
1482b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        uprv_memcpy(appendAt + reslen, ext->key, uprv_min(len, capacity - reslen));
1483b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1484b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    reslen += len;
1485b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (reslen < capacity) {
1486b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *(appendAt + reslen) = SEP;
1487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
1488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    reslen++;
1489b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    len = (int32_t)uprv_strlen(ext->value);
1490b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (reslen < capacity) {
1491b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        uprv_memcpy(appendAt + reslen, ext->value, uprv_min(len, capacity - reslen));
1492b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1493b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    reslen += len;
1494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1495b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    ext = ext->next;
1496b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else if (attr) {
1497b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    /* write the value for the attributes */
1498b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (reslen < capacity) {
1499b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *(appendAt + reslen) = SEP;
1500b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1501b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    reslen++;
1502b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    len = (int32_t)uprv_strlen(attr->attribute);
1503b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (reslen < capacity) {
1504b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        uprv_memcpy(appendAt + reslen, attr->attribute, uprv_min(len, capacity - reslen));
1505b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1506b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    reslen += len;
1507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1508b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    attr = attr->next;
1509b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1510b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } while (attr != NULL || ext != NULL);
1511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1512b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehocleanup:
1513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* clean up */
1514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ext = firstExt;
1515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (ext != NULL) {
1516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ExtensionListEntry *tmpExt = ext->next;
1517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(ext);
1518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ext = tmpExt;
1519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1521b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        attr = firstAttr;
1522b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        while (attr != NULL) {
1523b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            AttributeListEntry *tmpAttr = attr->next;
1524b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            char *pValue = (char *)attr->attribute;
1525b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uprv_free(pValue);
1526b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uprv_free(attr);
1527b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            attr = tmpAttr;
1528b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1529b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uenum_close(keywordEnum);
1531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (U_FAILURE(*status)) {
1533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
1534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(appendAt, capacity, reslen, status);
1538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/**
1541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Append keywords parsed from LDML extension value
1542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * e.g. "u-ca-gregory-co-trad" -> {calendar = gregorian} {collation = traditional}
1543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru * Note: char* buf is used for storing keywords
1544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru */
1545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
154627f654740f2a26ad62a5c155af9199af9e69b889claireho_appendLDMLExtensionAsKeywords(const char* ldmlext, ExtensionListEntry** appendTo, char* buf, int32_t bufSize, UBool *posixVariant, UErrorCode *status) {
154754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    const char *pTag;   /* beginning of current subtag */
154854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    const char *pKwds;  /* beginning of key-type pairs */
154954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    UBool variantExists = *posixVariant;
155054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
155154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    ExtensionListEntry *kwdFirst = NULL;    /* first LDML keyword */
1552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwd, *nextKwd;
155354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
155454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    AttributeListEntry *attrFirst = NULL;   /* first attribute */
155554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    AttributeListEntry *attr, *nextAttr;
155654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
155754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t len;
1558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t bufIdx = 0;
155954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
156054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    char attrBuf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
156154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t attrBufIdx = 0;
1562b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1563b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    /* Reset the posixVariant value */
1564b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    *posixVariant = FALSE;
1565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
156654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    pTag = ldmlext;
156754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    pKwds = NULL;
1568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
156954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    /* Iterate through u extension attributes */
157054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    while (*pTag) {
1571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* locate next separator char */
157254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++);
157354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
157454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (_isLDMLKey(pTag, len)) {
157554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            pKwds = pTag;
157654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            break;
1577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
157854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
157954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* add this attribute to the list */
158054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        attr = (AttributeListEntry*)uprv_malloc(sizeof(AttributeListEntry));
158154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (attr == NULL) {
158254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_MEMORY_ALLOCATION_ERROR;
158354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
1584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
158654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (len < (int32_t)sizeof(attrBuf) - attrBufIdx) {
158754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            uprv_memcpy(&attrBuf[attrBufIdx], pTag, len);
158854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            attrBuf[attrBufIdx + len] = 0;
158954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            attr->attribute = &attrBuf[attrBufIdx];
159054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            attrBufIdx += (len + 1);
1591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
159254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_ILLEGAL_ARGUMENT_ERROR;
159354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
159454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
1595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
159654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (!_addAttributeToList(&attrFirst, attr)) {
159754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_ILLEGAL_ARGUMENT_ERROR;
159854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            uprv_free(attr);
159954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
160054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
1601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
160254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* next tag */
160354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        pTag += len;
160454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (*pTag) {
160554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* next to the separator */
160654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            pTag++;
160754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
160854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
160954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
161054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (attrFirst) {
161154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* emit attributes as an LDML keyword, e.g. attribute=attr1-attr2 */
161254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
161354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (attrBufIdx > bufSize) {
161454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* attrBufIdx == <total length of attribute subtag> + 1 */
161554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_ILLEGAL_ARGUMENT_ERROR;
161654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
161754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
161854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
161954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
162054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (kwd == NULL) {
162154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_MEMORY_ALLOCATION_ERROR;
162254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
162354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
162454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
162554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        kwd->key = LOCALE_ATTRIBUTE_KEY;
162654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        kwd->value = buf;
162754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
162854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* attribute subtags sorted in alphabetical order as type */
162954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        attr = attrFirst;
163054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        while (attr != NULL) {
163154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            nextAttr = attr->next;
163254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
163354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* buffer size check is done above */
163454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (attr != attrFirst) {
163554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                *(buf + bufIdx) = SEP;
163654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                bufIdx++;
1637b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
163854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
163954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            len = uprv_strlen(attr->attribute);
164054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            uprv_memcpy(buf + bufIdx, attr->attribute, len);
1641b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            bufIdx += len;
1642b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
164354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            attr = nextAttr;
164454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
164554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        *(buf + bufIdx) = 0;
164654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        bufIdx++;
164754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
164854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
164954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            *status = U_ILLEGAL_ARGUMENT_ERROR;
165054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            uprv_free(kwd);
165154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            goto cleanup;
165254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
1653b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
165454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* once keyword entry is created, delete the attribute list */
165554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        attr = attrFirst;
165654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        while (attr != NULL) {
165754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            nextAttr = attr->next;
165854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            uprv_free(attr);
165954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            attr = nextAttr;
166054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        }
166154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        attrFirst = NULL;
166254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
166354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
166454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (pKwds) {
166554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        const char *pBcpKey = NULL;     /* u extenstion key subtag */
166654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        const char *pBcpType = NULL;    /* beginning of u extension type subtag(s) */
166754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        int32_t bcpKeyLen = 0;
166854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        int32_t bcpTypeLen = 0;
166954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        UBool isDone = FALSE;
167054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
167154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        pTag = pKwds;
167254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        /* BCP47 representation of LDML key/type pairs */
167354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        while (!isDone) {
167454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            const char *pNextBcpKey = NULL;
167554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            int32_t nextBcpKeyLen;
167654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            UBool emitKeyword = FALSE;
167754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
167854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (*pTag) {
167954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* locate next separator char */
168054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                for (len = 0; *(pTag + len) && *(pTag + len) != SEP; len++);
168154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
168254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (_isLDMLKey(pTag, len)) {
168354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    if (pBcpKey) {
168454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        emitKeyword = TRUE;
168554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        pNextBcpKey = pTag;
168654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        nextBcpKeyLen = len;
168754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    } else {
168854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        pBcpKey = pTag;
168954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        bcpKeyLen = len;
169054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    }
169154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                } else {
169254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    U_ASSERT(pBcpKey != NULL);
169354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* within LDML type subtags */
169454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    if (pBcpType) {
169554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        bcpTypeLen += (len + 1);
169654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    } else {
169754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        pBcpType = pTag;
169854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        bcpTypeLen = len;
169954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    }
170054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                }
170154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
170254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* next tag */
170354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pTag += len;
170454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (*pTag) {
170554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* next to the separator */
170654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    pTag++;
170754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                }
170827f654740f2a26ad62a5c155af9199af9e69b889claireho            } else {
170954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* processing last one */
171054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                emitKeyword = TRUE;
171154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                isDone = TRUE;
171254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            }
171354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
171454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (emitKeyword) {
171554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                const char *pKey = NULL;    /* LDML key */
171654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                const char *pType = NULL;   /* LDML type */
171754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
171854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                U_ASSERT(pBcpKey != NULL);
171954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
172054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* u extension key to LDML key */
172154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                len = _bcp47ToLDMLKey(pBcpKey, bcpKeyLen, buf + bufIdx, bufSize - bufIdx - 1, status);
172254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (U_FAILURE(*status)) {
172327f654740f2a26ad62a5c155af9199af9e69b889claireho                    goto cleanup;
172427f654740f2a26ad62a5c155af9199af9e69b889claireho                }
172554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pKey = buf + bufIdx;
172654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                bufIdx += len;
172754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                *(buf + bufIdx) = 0;
172854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                bufIdx++;
172954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
173054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (pBcpType) {
173154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* BCP type to locale type */
173254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    len = _bcp47ToLDMLType(pKey, -1, pBcpType, bcpTypeLen, buf + bufIdx, bufSize - bufIdx - 1, status);
173354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    if (U_FAILURE(*status)) {
173454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        goto cleanup;
173554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    }
173654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    pType = buf + bufIdx;
173754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    bufIdx += len;
173854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    *(buf + bufIdx) = 0;
173954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    bufIdx++;
174054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                } else {
174154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* typeless - default type value is "yes" */
174254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    pType = LOCALE_TYPE_YES;
174354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                }
174454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
174554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* Special handling for u-va-posix, since we want to treat this as a variant,
174654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                   not as a keyword */
174754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (!variantExists && !uprv_strcmp(pKey, POSIX_KEY) && !uprv_strcmp(pType, POSIX_VALUE) ) {
174854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    *posixVariant = TRUE;
174954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                } else {
175054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* create an ExtensionListEntry for this keyword */
175154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
175254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    if (kwd == NULL) {
175354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        *status = U_MEMORY_ALLOCATION_ERROR;
175454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        goto cleanup;
175554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    }
1756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
175754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    kwd->key = pKey;
175854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    kwd->value = pType;
175927f654740f2a26ad62a5c155af9199af9e69b889claireho
176054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
176154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        *status = U_ILLEGAL_ARGUMENT_ERROR;
176254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        uprv_free(kwd);
176354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        goto cleanup;
176454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    }
176527f654740f2a26ad62a5c155af9199af9e69b889claireho                }
1766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
176754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pBcpKey = pNextBcpKey;
176854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                bcpKeyLen = pNextBcpKey != NULL ? nextBcpKeyLen : 0;
176954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pBcpType = NULL;
177054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                bcpTypeLen = 0;
177154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            }
1772b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1773b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1774b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1775b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1776b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1777b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        nextKwd = kwd->next;
1778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        _addExtensionToList(appendTo, kwd, FALSE);
1779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = nextKwd;
1780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return;
1783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querucleanup:
178554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    attr = attrFirst;
178654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    while (attr != NULL) {
178754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        nextAttr = attr->next;
178854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        uprv_free(attr);
178954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        attr = nextAttr;
179054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    }
179154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
1792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        nextKwd = kwd->next;
1795b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(kwd);
1796b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = nextKwd;
1797b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
1802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru_appendKeywords(ULanguageTag* langtag, char* appendAt, int32_t capacity, UErrorCode* status) {
1803b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
1804b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i, n;
1805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len;
1806b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwdFirst = NULL;
1807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *kwd;
1808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *key, *type;
1809b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    char *kwdBuf = NULL;
1810b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t kwdBufLength = capacity;
181127f654740f2a26ad62a5c155af9199af9e69b889claireho    UBool posixVariant = FALSE;
1812b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1813b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1814b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1815b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1816b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
181754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    kwdBuf = (char*)uprv_malloc(kwdBufLength);
1818b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (kwdBuf == NULL) {
1819b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        *status = U_MEMORY_ALLOCATION_ERROR;
1820b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
1821b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1822b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1823b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    /* Determine if variants already exists */
1824b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (ultag_getVariantsSize(langtag)) {
1825b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        posixVariant = TRUE;
1826b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1827b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1828b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getExtensionsSize(langtag);
1829b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1830b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* resolve locale keywords and reordering keys */
1831b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < n; i++) {
1832b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        key = ultag_getExtensionKey(langtag, i);
1833b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        type = ultag_getExtensionValue(langtag, i);
1834b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*key == LDMLEXT) {
1835b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            _appendLDMLExtensionAsKeywords(type, &kwdFirst, kwdBuf, kwdBufLength, &posixVariant, status);
1836b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (U_FAILURE(*status)) {
1837b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1838b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1839b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
184054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
1841b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (kwd == NULL) {
1842b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_MEMORY_ALLOCATION_ERROR;
1843b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1844b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1845b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd->key = key;
1846b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            kwd->value = type;
1847b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
1848b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_free(kwd);
1849b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_ILLEGAL_ARGUMENT_ERROR;
1850b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
1851b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1852b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1853b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1854b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1855b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_SUCCESS(*status)) {
1856b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        type = ultag_getPrivateUse(langtag);
185750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if ((int32_t)uprv_strlen(type) > 0) {
1858b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* add private use as a keyword */
185954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            kwd = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
1860b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (kwd == NULL) {
1861b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *status = U_MEMORY_ALLOCATION_ERROR;
1862b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
1863b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                kwd->key = PRIVATEUSE_KEY;
1864b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                kwd->value = type;
1865b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (!_addExtensionToList(&kwdFirst, kwd, FALSE)) {
1866b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_free(kwd);
1867b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_ILLEGAL_ARGUMENT_ERROR;
1868b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1869b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1870b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
1871b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1872b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
187327f654740f2a26ad62a5c155af9199af9e69b889claireho    /* If a POSIX variant was in the extensions, write it out before writing the keywords. */
187427f654740f2a26ad62a5c155af9199af9e69b889claireho
187527f654740f2a26ad62a5c155af9199af9e69b889claireho    if (U_SUCCESS(*status) && posixVariant) {
187627f654740f2a26ad62a5c155af9199af9e69b889claireho        len = (int32_t) uprv_strlen(_POSIX);
187727f654740f2a26ad62a5c155af9199af9e69b889claireho        if (reslen < capacity) {
187827f654740f2a26ad62a5c155af9199af9e69b889claireho            uprv_memcpy(appendAt + reslen, _POSIX, uprv_min(len, capacity - reslen));
187927f654740f2a26ad62a5c155af9199af9e69b889claireho        }
188027f654740f2a26ad62a5c155af9199af9e69b889claireho        reslen += len;
188127f654740f2a26ad62a5c155af9199af9e69b889claireho    }
188227f654740f2a26ad62a5c155af9199af9e69b889claireho
188354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (U_SUCCESS(*status) && kwdFirst != NULL) {
1884b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the sorted keywords */
1885b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool firstValue = TRUE;
1886b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = kwdFirst;
1887b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        do {
1888b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < capacity) {
1889b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (firstValue) {
1890b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* '@' */
1891b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = LOCALE_EXT_SEP;
1892b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    firstValue = FALSE;
189354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                } else {
1894b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* ';' */
1895b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(appendAt + reslen) = LOCALE_KEYWORD_SEP;
1896b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
1897b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
1898b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
1899b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
190054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* key */
190154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            len = (int32_t)uprv_strlen(kwd->key);
190254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (reslen < capacity) {
190354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                uprv_memcpy(appendAt + reslen, kwd->key, uprv_min(len, capacity - reslen));
190454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            }
190554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            reslen += len;
1906b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
190754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* '=' */
190854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (reslen < capacity) {
190954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                *(appendAt + reslen) = LOCALE_KEY_TYPE_SEP;
191054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            }
191154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            reslen++;
1912b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
191354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            /* type */
191454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            len = (int32_t)uprv_strlen(kwd->value);
191554dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            if (reslen < capacity) {
191654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                uprv_memcpy(appendAt + reslen, kwd->value, uprv_min(len, capacity - reslen));
1917b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
191854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            reslen += len;
191954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
192054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            kwd = kwd->next;
192154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        } while (kwd);
1922b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1923b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1924b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* clean up */
1925b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    kwd = kwdFirst;
1926b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (kwd != NULL) {
1927b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *tmpKwd = kwd->next;
1928b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(kwd);
1929b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        kwd = tmpKwd;
1930b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1931b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1932b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    uprv_free(kwdBuf);
1933b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1934b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
1935b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
1936b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
1937b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1938b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(appendAt, capacity, reslen, status);
1939b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
1940b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
1941b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2clairehostatic int32_t
1942b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho_appendPrivateuseToLanguageTag(const char* localeID, char* appendAt, int32_t capacity, UBool strict, UBool hadPosix, UErrorCode* status) {
1943b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    char buf[ULOC_FULLNAME_CAPACITY];
1944b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    char tmpAppend[ULOC_FULLNAME_CAPACITY];
1945b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    UErrorCode tmpStatus = U_ZERO_ERROR;
1946b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t len, i;
1947b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    int32_t reslen = 0;
1948b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1949b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(*status)) {
1950b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
1951b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1952b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1953b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    len = uloc_getVariant(localeID, buf, sizeof(buf), &tmpStatus);
1954b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_FAILURE(tmpStatus) || tmpStatus == U_STRING_NOT_TERMINATED_WARNING) {
1955b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (strict) {
1956b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            *status = U_ILLEGAL_ARGUMENT_ERROR;
1957b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
1958b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        return 0;
1959b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
1960b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1961b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (len > 0) {
1962b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        char *p, *pPriv;
1963b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool bNext = TRUE;
1964b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool firstValue = TRUE;
1965b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool writeValue;
1966b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1967b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        pPriv = NULL;
1968b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        p = buf;
1969b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        while (bNext) {
1970b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            writeValue = FALSE;
1971b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (*p == SEP || *p == LOCALE_SEP || *p == 0) {
1972b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (*p == 0) {
1973b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    bNext = FALSE;
1974b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                } else {
1975b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    *p = 0; /* terminate */
1976b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
1977b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (pPriv != NULL) {
1978b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    /* Private use in the canonical format is lowercase in BCP47 */
1979b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    for (i = 0; *(pPriv + i) != 0; i++) {
1980b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *(pPriv + i) = uprv_tolower(*(pPriv + i));
1981b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1982b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1983b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    /* validate */
1984b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (_isPrivateuseValueSubtag(pPriv, -1)) {
1985b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (firstValue) {
1986b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (!_isVariantSubtag(pPriv, -1)) {
1987b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                writeValue = TRUE;
1988b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
1989b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        } else {
1990b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            writeValue = TRUE;
1991b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
1992b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else if (strict) {
1993b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *status = U_ILLEGAL_ARGUMENT_ERROR;
1994b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
1995b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else {
1996b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
1997b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
1998b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
1999b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (writeValue) {
2000b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (reslen < capacity) {
2001b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            tmpAppend[reslen++] = SEP;
2002b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
2003b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2004b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (firstValue) {
2005b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (reslen < capacity) {
2006b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                tmpAppend[reslen++] = *PRIVATEUSE_KEY;
2007b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
2008b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2009b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (reslen < capacity) {
2010b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                tmpAppend[reslen++] = SEP;
2011b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
2012b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2013b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            len = (int32_t)uprv_strlen(PRIVUSE_VARIANT_PREFIX);
2014b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (reslen < capacity) {
2015b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                uprv_memcpy(tmpAppend + reslen, PRIVUSE_VARIANT_PREFIX, uprv_min(len, capacity - reslen));
2016b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
2017b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            reslen += len;
2018b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2019b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            if (reslen < capacity) {
2020b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                                tmpAppend[reslen++] = SEP;
2021b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            }
2022b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2023b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            firstValue = FALSE;
2024b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
2025b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2026b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        len = (int32_t)uprv_strlen(pPriv);
2027b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (reslen < capacity) {
2028b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            uprv_memcpy(tmpAppend + reslen, pPriv, uprv_min(len, capacity - reslen));
2029b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
2030b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        reslen += len;
2031b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
2032b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
2033b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                /* reset private use starting position */
2034b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                pPriv = NULL;
2035b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            } else if (pPriv == NULL) {
2036b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                pPriv = p;
2037b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
2038b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            p++;
2039b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
2040b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2041b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (U_FAILURE(*status)) {
2042b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            return 0;
2043b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
2044b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
2045b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2046b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (U_SUCCESS(*status)) {
2047b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        len = reslen;
2048b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (reslen < capacity) {
2049b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uprv_memcpy(appendAt, tmpAppend, uprv_min(len, capacity - reslen));
2050b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
2051b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
2052b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2053b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    u_terminateChars(appendAt, capacity, reslen, status);
2054b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2055b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    return reslen;
2056b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho}
2057b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2058b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2059b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2060b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2061b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* ultag_ functions
2062b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2063b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2064b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
2065b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2066b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/* Bit flags used by the parser */
2067b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define LANG 0x0001
2068b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTL 0x0002
2069b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define SCRT 0x0004
2070b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define REGN 0x0008
2071b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define VART 0x0010
2072b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTS 0x0020
2073b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define EXTV 0x0040
2074b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#define PRIV 0x0080
2075b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2076b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic ULanguageTag*
2077b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_parse(const char* tag, int32_t tagLen, int32_t* parsedLen, UErrorCode* status) {
2078b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ULanguageTag *t;
2079b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char *tagBuf;
2080b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int16_t next;
2081b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char *pSubtag, *pNext, *pLastGoodPosition;
2082b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t subtagLen;
2083b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t extlangIdx;
2084b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *pExtension;
208550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    char *pExtValueSubtag, *pExtValueSubtagEnd;
2086b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
20878393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    UBool privateuseVar = FALSE;
208854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t grandfatheredLen = 0;
2089b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2090b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (parsedLen != NULL) {
2091b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *parsedLen = 0;
2092b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2093b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2094b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
2095b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
2096b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2097b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2098b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagLen < 0) {
209950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        tagLen = (int32_t)uprv_strlen(tag);
2100b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2101b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2102b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* copy the entire string */
2103b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    tagBuf = (char*)uprv_malloc(tagLen + 1);
2104b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagBuf == NULL) {
2105b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
2106b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
2107b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2108b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_memcpy(tagBuf, tag, tagLen);
2109b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    *(tagBuf + tagLen) = 0;
2110b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2111b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* create a ULanguageTag */
2112b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    t = (ULanguageTag*)uprv_malloc(sizeof(ULanguageTag));
2113b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (t == NULL) {
2114b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uprv_free(tagBuf);
2115b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
2116b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return NULL;
2117b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2118b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    _initializeULanguageTag(t);
2119b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    t->buf = tagBuf;
2120b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2121b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (tagLen < MINLEN) {
2122b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* the input tag is too short - return empty ULanguageTag */
2123b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return t;
2124b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2125b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2126b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* check if the tag is grandfathered */
2127b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; GRANDFATHERED[i] != NULL; i += 2) {
2128103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        if (uprv_stricmp(GRANDFATHERED[i], tagBuf) == 0) {
212954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            int32_t newTagLength;
213054dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius
213154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            grandfatheredLen = tagLen;  /* back up for output parsedLen */
213254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            newTagLength = uprv_strlen(GRANDFATHERED[i+1]);
2133b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (tagLen < newTagLength) {
2134b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                uprv_free(tagBuf);
2135b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                tagBuf = (char*)uprv_malloc(newTagLength + 1);
2136b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (tagBuf == NULL) {
2137b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    *status = U_MEMORY_ALLOCATION_ERROR;
2138b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    return NULL;
2139b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
2140b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                t->buf = tagBuf;
2141b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                tagLen = newTagLength;
2142b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2143b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uprv_strcpy(t->buf, GRANDFATHERED[i + 1]);
2144b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            break;
2145b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2146b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2147b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2148b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /*
2149b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     * langtag      =   language
2150b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" script]
2151b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" region]
2152b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  *("-" variant)
2153b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  *("-" extension)
2154b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     *                  ["-" privateuse]
2155b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru     */
2156b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2157b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    next = LANG | PRIV;
2158b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pNext = pLastGoodPosition = tagBuf;
2159b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    extlangIdx = 0;
2160b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pExtension = NULL;
216150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    pExtValueSubtag = NULL;
2162b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    pExtValueSubtagEnd = NULL;
2163b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2164b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (pNext) {
2165b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        char *pSep;
2166b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2167b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pSubtag = pNext;
2168b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2169b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* locate next separator char */
2170b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        pSep = pSubtag;
2171b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*pSep) {
2172b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (*pSep == SEP) {
2173b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
2174b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2175b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pSep++;
2176b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2177b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (*pSep == 0) {
2178b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* last subtag */
2179b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = NULL;
2180b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
2181b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            pNext = pSep + 1;
2182b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
218350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        subtagLen = (int32_t)(pSep - pSubtag);
2184b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2185b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & LANG) {
2186b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isLanguageSubtag(pSubtag, subtagLen)) {
2187b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;  /* terminate */
218850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->language = T_CString_toLowerCase(pSubtag);
2189b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2190b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
2191b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
2192b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2193b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2194b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2195b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTL) {
2196b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtlangSubtag(pSubtag, subtagLen)) {
2197b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
219850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->extlang[extlangIdx++] = T_CString_toLowerCase(pSubtag);
2199b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2200b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
2201b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (extlangIdx < 3) {
2202b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    next = EXTL | SCRT | REGN | VART | EXTS | PRIV;
2203b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
2204b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    next = SCRT | REGN | VART | EXTS | PRIV;
2205b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2206b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2207b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2208b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2209b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & SCRT) {
2210b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isScriptSubtag(pSubtag, subtagLen)) {
221150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                char *p = pSubtag;
221250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
2213b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
221450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
221550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* to title case */
221650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                *p = uprv_toupper(*p);
221750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                p++;
221850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                for (; *p; p++) {
221950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    *p = uprv_tolower(*p);
222050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
222150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
2222b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                t->script = pSubtag;
2223b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2224b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
2225b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = REGN | VART | EXTS | PRIV;
2226b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2227b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2228b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2229b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & REGN) {
2230b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isRegionSubtag(pSubtag, subtagLen)) {
2231b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
223250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                t->region = T_CString_toUpperCase(pSubtag);
2233b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2234b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
2235b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = VART | EXTS | PRIV;
2236b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2237b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2238b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2239b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & VART) {
2240b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (_isVariantSubtag(pSubtag, subtagLen) ||
2241b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho               (privateuseVar && _isPrivateuseVariantSubtag(pSubtag, subtagLen))) {
2242b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                VariantListEntry *var;
2243b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                UBool isAdded;
2244b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2245b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                var = (VariantListEntry*)uprv_malloc(sizeof(VariantListEntry));
2246b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (var == NULL) {
2247b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_MEMORY_ALLOCATION_ERROR;
2248b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto error;
2249b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2250b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
225150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                var->variant = T_CString_toUpperCase(pSubtag);
2252b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                isAdded = _addVariantToList(&(t->variants), var);
2253b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (!isAdded) {
2254b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* duplicated variant entry */
2255b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    uprv_free(var);
2256b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
2257b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2258b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pSep;
2259b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = VART | EXTS | PRIV;
2260b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2261b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2262b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2263b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTS) {
2264b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtensionSingleton(pSubtag, subtagLen)) {
2265b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension != NULL) {
226650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
2267b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* the previous extension is incomplete */
2268b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
226950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension = NULL;
2270b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
2271b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
2272b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2273b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* terminate the previous extension value */
2274b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pExtValueSubtagEnd = 0;
227550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
2276b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2277b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* insert the extension to the list */
2278b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
2279b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pLastGoodPosition = pExtValueSubtagEnd;
2280b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
2281b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* stop parsing here */
2282b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
2283b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pExtension = NULL;
2284b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
2285b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
2286b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2287b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2288b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* create a new extension */
228954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pExtension = (ExtensionListEntry*)uprv_malloc(sizeof(ExtensionListEntry));
2290b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension == NULL) {
2291b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *status = U_MEMORY_ALLOCATION_ERROR;
2292b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    goto error;
2293b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2294b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *pSep = 0;
229550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                pExtension->key = T_CString_toLowerCase(pSubtag);
2296b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtension->value = NULL;   /* will be set later */
2297b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2298b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /*
229950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                 * reset the start and the end location of extension value
2300b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 * subtags for this extension
2301b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                 */
230250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                pExtValueSubtag = NULL;
2303b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pExtValueSubtagEnd = NULL;
2304b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2305b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                next = EXTV;
2306b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                continue;
2307b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2308b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2309b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & EXTV) {
2310b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_isExtensionSubtag(pSubtag, subtagLen)) {
231154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (pExtValueSubtag == NULL) {
231254dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    /* if the start postion of this extension's value is not yet,
231354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                        this one is the first value subtag */
231454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                    pExtValueSubtag = pSubtag;
2315b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2316b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
231754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* Mark the end of this subtag */
231854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                pExtValueSubtagEnd = pSep;
231954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                next = EXTS | EXTV | PRIV;
2320b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
232154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                continue;
2322b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2323b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2324b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (next & PRIV) {
232550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (uprv_tolower(*pSubtag) == PRIVATEUSE) {
2326b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                char *pPrivuseVal;
2327b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2328b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pExtension != NULL) {
2329b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* Process the last extension */
233050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
2331b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* the previous extension is incomplete */
2332b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        uprv_free(pExtension);
233350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension = NULL;
2334b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
2335b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
2336b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* terminate the previous extension value */
2337b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        *pExtValueSubtagEnd = 0;
233850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
2339b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2340b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* insert the extension to the list */
2341b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
2342b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pLastGoodPosition = pExtValueSubtagEnd;
2343b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pExtension = NULL;
2344b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        } else {
2345b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* stop parsing here */
2346b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            uprv_free(pExtension);
2347b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            pExtension = NULL;
2348b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
2349b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
2350b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
2351b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2352b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2353b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* The rest of part will be private use value subtags */
2354b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pNext == NULL) {
2355b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    /* empty private use subtag */
2356b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    break;
2357b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2358b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* back up the private use value start position */
2359b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pPrivuseVal = pNext;
2360b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2361b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* validate private use value subtags */
2362b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                while (pNext) {
2363b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pSubtag = pNext;
2364b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    pSep = pSubtag;
2365b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    while (*pSep) {
2366b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        if (*pSep == SEP) {
2367b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                            break;
2368b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        }
2369b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pSep++;
2370b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
2371b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    if (*pSep == 0) {
2372b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        /* last subtag */
2373b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pNext = NULL;
2374b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
2375b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pNext = pSep + 1;
2376b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
237750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    subtagLen = (int32_t)(pSep - pSubtag);
2378b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2379b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (uprv_strncmp(pSubtag, PRIVUSE_VARIANT_PREFIX, uprv_strlen(PRIVUSE_VARIANT_PREFIX)) == 0) {
2380b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *pSep = 0;
2381b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        next = VART;
2382b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        privateuseVar = TRUE;
2383b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        break;
2384b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else if (_isPrivateuseValueSubtag(pSubtag, subtagLen)) {
2385b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        pLastGoodPosition = pSep;
2386b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    } else {
2387b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                        break;
2388b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    }
2389b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2390b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2391b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (next == VART) {
2392b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    continue;
2393b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
2394b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2395b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (pLastGoodPosition - pPrivuseVal > 0) {
2396b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *pLastGoodPosition = 0;
239750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    t->privateuse = T_CString_toLowerCase(pPrivuseVal);
2398b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2399b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                /* No more subtags, exiting the parse loop */
2400b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                break;
2401b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2402b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2403b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2404b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2405b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* If we fell through here, it means this subtag is illegal - quit parsing */
2406b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        break;
2407b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2408b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2409b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (pExtension != NULL) {
2410b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* Process the last extension */
241150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (pExtValueSubtag == NULL || pExtValueSubtagEnd == NULL) {
2412b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* the previous extension is incomplete */
2413b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(pExtension);
2414b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        } else {
2415b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* terminate the previous extension value */
2416b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *pExtValueSubtagEnd = 0;
241750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            pExtension->value = T_CString_toLowerCase(pExtValueSubtag);
2418b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* insert the extension to the list */
2419b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (_addExtensionToList(&(t->extensions), pExtension, FALSE)) {
2420b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                pLastGoodPosition = pExtValueSubtagEnd;
2421b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            } else {
2422b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_free(pExtension);
2423b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2424b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2425b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2426b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2427b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (parsedLen != NULL) {
242854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        *parsedLen = (grandfatheredLen > 0) ? grandfatheredLen : (int32_t)(pLastGoodPosition - t->buf);
2429b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2430b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2431b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return t;
2432b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2433b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruerror:
2434b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(t);
2435b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return NULL;
2436b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2437b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2438b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic void
2439b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_close(ULanguageTag* langtag) {
2440b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2441b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag == NULL) {
2442b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return;
2443b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2444b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2445b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(langtag->buf);
2446b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2447b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag->variants) {
2448b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        VariantListEntry *curVar = langtag->variants;
2449b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (curVar) {
2450b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            VariantListEntry *nextVar = curVar->next;
2451b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(curVar);
2452b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            curVar = nextVar;
2453b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2454b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2455b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2456b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (langtag->extensions) {
2457b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        ExtensionListEntry *curExt = langtag->extensions;
2458b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (curExt) {
2459b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            ExtensionListEntry *nextExt = curExt->next;
2460b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            uprv_free(curExt);
2461b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            curExt = nextExt;
2462b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2463b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2464b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2465b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    uprv_free(langtag);
2466b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2467b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2468b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2469b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getLanguage(const ULanguageTag* langtag) {
2470b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->language;
2471b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2472b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2473b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
2474b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2475b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getJDKLanguage(const ULanguageTag* langtag) {
2476b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
2477b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; DEPRECATEDLANGS[i] != NULL; i += 2) {
247850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (uprv_compareInvCharsAsAscii(DEPRECATEDLANGS[i], langtag->language) == 0) {
2479b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return DEPRECATEDLANGS[i + 1];
2480b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2481b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2482b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->language;
2483b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2484b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
2485b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2486b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2487b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlang(const ULanguageTag* langtag, int32_t idx) {
2488b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (idx >= 0 && idx < MAXEXTLANG) {
2489b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return langtag->extlang[idx];
2490b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2491b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return NULL;
2492b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2493b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2494b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2495b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtlangSize(const ULanguageTag* langtag) {
2496b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2497b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i;
2498b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    for (i = 0; i < MAXEXTLANG; i++) {
2499b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (langtag->extlang[i]) {
2500b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            size++;
2501b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2502b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2503b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2504b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2505b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2506b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2507b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getScript(const ULanguageTag* langtag) {
2508b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->script;
2509b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2510b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2511b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2512b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getRegion(const ULanguageTag* langtag) {
2513b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->region;
2514b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2515b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2516b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2517b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariant(const ULanguageTag* langtag, int32_t idx) {
2518b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *var = NULL;
2519b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry *cur = langtag->variants;
2520b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2521b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2522b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2523b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            var = cur->variant;
2524b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2525b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2526b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2527b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2528b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2529b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return var;
2530b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2531b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2532b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2533b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getVariantsSize(const ULanguageTag* langtag) {
2534b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2535b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    VariantListEntry *cur = langtag->variants;
2536b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (TRUE) {
2537b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (cur == NULL) {
2538b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2539b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2540b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        size++;
2541b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2542b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2543b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2544b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2545b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2546b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2547b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionKey(const ULanguageTag* langtag, int32_t idx) {
2548b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *key = NULL;
2549b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2550b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2551b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2552b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2553b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            key = cur->key;
2554b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2555b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2556b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2557b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2558b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2559b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return key;
2560b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2561b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2562b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2563b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionValue(const ULanguageTag* langtag, int32_t idx) {
2564b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *val = NULL;
2565b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2566b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t i = 0;
2567b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (cur) {
2568b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (i == idx) {
2569b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            val = cur->value;
2570b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2571b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2572b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2573b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        i++;
2574b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2575b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return val;
2576b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2577b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2578b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic int32_t
2579b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getExtensionsSize(const ULanguageTag* langtag) {
2580b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t size = 0;
2581b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ExtensionListEntry *cur = langtag->extensions;
2582b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    while (TRUE) {
2583b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (cur == NULL) {
2584b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            break;
2585b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2586b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        size++;
2587b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        cur = cur->next;
2588b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2589b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return size;
2590b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2591b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2592b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2593b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getPrivateUse(const ULanguageTag* langtag) {
2594b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->privateuse;
2595b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2596b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2597b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#if 0
2598b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Querustatic const char*
2599b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruultag_getGrandfathered(const ULanguageTag* langtag) {
2600b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return langtag->grandfathered;
2601b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2602b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru#endif
2603b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2604b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2605b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru/*
2606b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2607b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2608b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* Locale/BCP47 conversion APIs, exposed as uloc_*
2609b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*
2610b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru* -------------------------------------------------
2611b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru*/
261254dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI int32_t U_EXPORT2
2613b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruuloc_toLanguageTag(const char* localeID,
2614b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   char* langtag,
2615b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   int32_t langtagCapacity,
2616b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   UBool strict,
2617b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                   UErrorCode* status) {
2618b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* char canonical[ULOC_FULLNAME_CAPACITY]; */ /* See #6822 */
2619b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    char canonical[256];
2620b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
2621b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UErrorCode tmpStatus = U_ZERO_ERROR;
262227f654740f2a26ad62a5c155af9199af9e69b889claireho    UBool hadPosix = FALSE;
2623b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const char* pKeywordStart;
2624b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2625b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* Note: uloc_canonicalize returns "en_US_POSIX" for input locale ID "".  See #6835 */
2626b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    canonical[0] = 0;
2627b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (uprv_strlen(localeID) > 0) {
2628b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        uloc_canonicalize(localeID, canonical, sizeof(canonical), &tmpStatus);
2629b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (tmpStatus != U_ZERO_ERROR) {
2630b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *status = U_ILLEGAL_ARGUMENT_ERROR;
2631b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            return 0;
2632b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2633b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2634b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2635b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    /* For handling special case - private use only tag */
2636b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    pKeywordStart = locale_getKeywordsStart(canonical);
2637b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    if (pKeywordStart == canonical) {
2638b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UEnumeration *kwdEnum;
2639b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        int kwdCnt = 0;
2640b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        UBool done = FALSE;
2641b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2642b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        kwdEnum = uloc_openKeywords((const char*)canonical, &tmpStatus);
2643b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        if (kwdEnum != NULL) {
2644b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            kwdCnt = uenum_count(kwdEnum, &tmpStatus);
2645b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (kwdCnt == 1) {
2646b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                const char *key;
2647b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                int32_t len = 0;
2648b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2649b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                key = uenum_next(kwdEnum, &len, &tmpStatus);
2650b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                if (len == 1 && *key == PRIVATEUSE) {
2651b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    char buf[ULOC_KEYWORD_AND_VALUES_CAPACITY];
2652b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    buf[0] = PRIVATEUSE;
2653b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    buf[1] = SEP;
2654b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    len = uloc_getKeywordValue(localeID, key, &buf[2], sizeof(buf) - 2, &tmpStatus);
2655b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    if (U_SUCCESS(tmpStatus)) {
2656b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        if (_isPrivateuseValueSubtags(&buf[2], len)) {
2657b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            /* return private use only tag */
2658b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            reslen = len + 2;
2659b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            uprv_memcpy(langtag, buf, uprv_min(reslen, langtagCapacity));
2660b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            u_terminateChars(langtag, langtagCapacity, reslen, status);
2661b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            done = TRUE;
2662b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        } else if (strict) {
2663b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            *status = U_ILLEGAL_ARGUMENT_ERROR;
2664b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                            done = TRUE;
2665b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        }
2666b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        /* if not strict mode, then "und" will be returned */
2667b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    } else {
2668b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        *status = U_ILLEGAL_ARGUMENT_ERROR;
2669b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                        done = TRUE;
2670b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                    }
2671b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                }
2672b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
2673b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            uenum_close(kwdEnum);
2674b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (done) {
2675b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho                return reslen;
2676b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            }
2677b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho        }
2678b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    }
2679b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho
2680b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendLanguageToLanguageTag(canonical, langtag, langtagCapacity, strict, status);
2681b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendScriptToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
2682b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    reslen += _appendRegionToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, status);
268327f654740f2a26ad62a5c155af9199af9e69b889claireho    reslen += _appendVariantsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, &hadPosix, status);
268427f654740f2a26ad62a5c155af9199af9e69b889claireho    reslen += _appendKeywordsToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, hadPosix, status);
2685b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    reslen += _appendPrivateuseToLanguageTag(canonical, langtag + reslen, langtagCapacity - reslen, strict, hadPosix, status);
2686b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2687b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return reslen;
2688b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2689b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2690b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
269154dcd9b6a06071f647dac967e9e267abb9410720Craig CorneliusU_CAPI int32_t U_EXPORT2
2692b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queruuloc_forLanguageTag(const char* langtag,
2693b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    char* localeID,
2694b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    int32_t localeIDCapacity,
2695b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    int32_t* parsedLength,
2696b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    UErrorCode* status) {
2697b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ULanguageTag *lt;
2698b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t reslen = 0;
2699b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    const char *subtag, *p;
2700b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    int32_t len;
270154dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    int32_t i, n;
2702b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    UBool noRegion = TRUE;
2703b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2704b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    lt = ultag_parse(langtag, -1, parsedLength, status);
2705b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (U_FAILURE(*status)) {
2706b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        return 0;
2707b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2708b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2709b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* language */
2710b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getExtlangSize(lt) > 0 ? ultag_getExtlang(lt, 0) : ultag_getLanguage(lt);
271150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (uprv_compareInvCharsAsAscii(subtag, LANG_UND) != 0) {
271250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(subtag);
2713b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (len > 0) {
2714b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2715b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(localeID, subtag, uprv_min(len, localeIDCapacity - reslen));
2716b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2717b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += len;
2718b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2719b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2720b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2721b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* script */
2722b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getScript(lt);
272350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    len = (int32_t)uprv_strlen(subtag);
2724b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
2725b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < localeIDCapacity) {
2726b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(localeID + reslen) = LOCALE_SEP;
2727b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2728b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen++;
2729b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2730b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the script in title case */
2731b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = subtag;
2732b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*p) {
2733b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2734b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (p == subtag) {
2735b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = uprv_toupper(*p);
2736b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                } else {
2737b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = *p;
2738b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2739b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2740b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2741b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
2742b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2743b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2744b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2745b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* region */
2746b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getRegion(lt);
274750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    len = (int32_t)uprv_strlen(subtag);
2748b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (len > 0) {
2749b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (reslen < localeIDCapacity) {
2750b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            *(localeID + reslen) = LOCALE_SEP;
2751b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2752b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen++;
2753b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        /* write out the retion in upper case */
2754b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        p = subtag;
2755b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        while (*p) {
2756b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2757b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = uprv_toupper(*p);
2758b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2759b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2760b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p++;
2761b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2762b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        noRegion = FALSE;
2763b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2764b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2765b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* variants */
2766b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getVariantsSize(lt);
2767b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    if (n > 0) {
2768b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        if (noRegion) {
2769b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2770b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = LOCALE_SEP;
2771b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2772b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2773b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2774b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2775b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        for (i = 0; i < n; i++) {
2776b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            subtag = ultag_getVariant(lt, i);
2777b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2778b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                *(localeID + reslen) = LOCALE_SEP;
2779b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2780b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen++;
2781b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* write out the variant in upper case */
2782b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            p = subtag;
2783b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            while (*p) {
2784b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                if (reslen < localeIDCapacity) {
2785b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                    *(localeID + reslen) = uprv_toupper(*p);
2786b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                }
2787b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                reslen++;
2788b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                p++;
2789b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2790b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2791b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2792b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2793b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    /* keywords */
2794b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    n = ultag_getExtensionsSize(lt);
2795b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    subtag = ultag_getPrivateUse(lt);
279654dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    if (n > 0 || uprv_strlen(subtag) > 0) {
279754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius        if (reslen == 0 && n > 0) {
2798b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            /* need a language */
2799b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            if (reslen < localeIDCapacity) {
2800b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru                uprv_memcpy(localeID + reslen, LANG_UND, uprv_min(LANG_UND_LEN, localeIDCapacity - reslen));
2801b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            }
2802b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru            reslen += LANG_UND_LEN;
2803b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        }
2804b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        len = _appendKeywords(lt, localeID + reslen, localeIDCapacity - reslen, status);
2805b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru        reslen += len;
2806b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    }
2807b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2808b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    ultag_close(lt);
2809b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru    return u_terminateChars(localeID, localeIDCapacity, reslen, status);
2810b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru}
2811b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2812b0ac937921a2c196d8b9da665135bf6ba01a1ccfJean-Baptiste Queru
2813