10596faeddefbf198de137d5e893708495ab1584cFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html
3b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
4b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru**********************************************************************
58de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert*   Copyright (C) 1997-2016, International Business Machines
6b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
7b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru**********************************************************************
8b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
9b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* File ULOC.CPP
10b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
11b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru* Modification History:
12b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*
13b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   Date        Name        Description
14b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   04/01/97    aliu        Creation.
15b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   08/21/98    stephen     JDK 1.2 sync
16b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   12/08/98    rtg         New Locale implementation and C API
17b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   03/15/99    damiba      overhaul.
18b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   04/06/99    stephen     changed setDefault() to realloc and copy
19b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   06/14/99    stephen     Changed calls to ures_open for new params
20b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   07/21/99    stephen     Modified setDefault() to propagate to C++
21b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*   05/14/04    alan        7 years later: refactored, cleaned up, fixed bugs,
22b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*                           brought canonicalization code into line with spec
23b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*****************************************************************************/
24b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
25b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
26b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru   POSIX's locale format, from putil.c: [no spaces]
27b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
28b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     ll [ _CC ] [ . MM ] [ @ VV]
29b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
30b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru     l = lang, C = ctry, M = charmap, V = variant
31b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
32b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
33b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/utypes.h"
34b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/ustring.h"
35b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "unicode/uloc.h"
36b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
37b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "putilimp.h"
38b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "ustr_imp.h"
39b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "ulocimp.h"
40b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "umutex.h"
41b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cstring.h"
42b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "cmemory.h"
43b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "locmap.h"
44b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uarrsort.h"
45b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uenumimp.h"
46b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include "uassert.h"
470596faeddefbf198de137d5e893708495ab1584cFredrik Roubert#include "charstr.h"
48b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
49b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#include <stdio.h> /* for sprintf */
50b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
510596faeddefbf198de137d5e893708495ab1584cFredrik RoubertU_NAMESPACE_USE
5264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
53b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### Declarations **************************************************/
54b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
55b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* Locale stuff from locid.cpp */
56b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CFUNC void locale_set_default(const char *id);
57b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CFUNC const char *locale_get_default(void);
58b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CFUNC int32_t
59b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querulocale_getKeywords(const char *localeID,
60b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char prev,
61b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *keywords, int32_t keywordCapacity,
62b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *values, int32_t valuesCapacity, int32_t *valLen,
63b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UBool valuesToo,
64b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UErrorCode *status);
65b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
66b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### Data tables **************************************************/
67b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
68b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
69b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Table of language codes, both 2- and 3-letter, with preference
70b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * given to 2-letter codes where possible.  Includes 3-letter codes
71b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * that lack a 2-letter equivalent.
72b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
73b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This list must be in sorted order.  This list is returned directly
74b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to the user by some API.
75b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
76b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This list must be kept in sync with LANGUAGES_3, with corresponding
77b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * entries matched.
78b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
79b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This table should be terminated with a NULL entry, followed by a
80b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * second list, and another NULL entry.  The first list is visible to
81b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * user code when this array is returned by API.  The second list
82b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * contains codes we support, but do not expose through user API.
83b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
84b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Notes
85b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
86b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Tables updated per http://lcweb.loc.gov/standards/iso639-2/ to
87b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * include the revisions up to 2001/7/27 *CWB*
88b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
89b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The 3 character codes are the terminology codes like RFC 3066.  This
90b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * is compatible with prior ICU codes
91b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
92b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * "in" "iw" "ji" "jw" & "sh" have been withdrawn but are still in the
93b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * table but now at the end of the table because 3 character codes are
94b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * duplicates.  This avoids bad searches going from 3 to 2 character
95b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * codes.
96b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
97b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The range qaa-qtz is reserved for local use
98b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
998393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/* Generated using org.unicode.cldr.icu.GenerateISO639LanguageTables */
100c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert/* ISO639 table version is 20150505 */
101ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert/* Subsequent hand addition of selected languages */
102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char * const LANGUAGES[] = {
10364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "aa",  "ab",  "ace", "ach", "ada", "ady", "ae",  "aeb",
10464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "af",  "afh", "agq", "ain", "ak",  "akk", "akz", "ale",
10564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "aln", "alt", "am",  "an",  "ang", "anp", "ar",  "arc",
1060596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    "arn", "aro", "arp", "arq", "ars", "arw", "ary", "arz", "as",
10764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "asa", "ase", "ast", "av",  "avk", "awa", "ay",  "az",
10864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ba",  "bal", "ban", "bar", "bas", "bax", "bbc", "bbj",
10964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "be",  "bej", "bem", "bew", "bez", "bfd", "bfq", "bg",
11064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bgn", "bho", "bi",  "bik", "bin", "bjn", "bkm", "bla",
11164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bm",  "bn",  "bo",  "bpy", "bqi", "br",  "bra", "brh",
11264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "brx", "bs",  "bss", "bua", "bug", "bum", "byn", "byv",
113ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert    "ca",  "cad", "car", "cay", "cch", "ccp", "ce",  "ceb", "cgg",
11464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ch",  "chb", "chg", "chk", "chm", "chn", "cho", "chp",
11564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "chr", "chy", "ckb", "co",  "cop", "cps", "cr",  "crh",
11664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "cs",  "csb", "cu",  "cv",  "cy",
11764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "da",  "dak", "dar", "dav", "de",  "del", "den", "dgr",
11864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "dv",
11964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "dyo", "dyu", "dz",  "dzg",
12064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ebu", "ee",  "efi", "egl", "egy", "eka", "el",  "elx",
12164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "en",  "enm", "eo",  "es",  "esu", "et",  "eu",  "ewo",
12264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ext",
12364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "fa",  "fan", "fat", "ff",  "fi",  "fil", "fit", "fj",
12464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "fo",  "fon", "fr",  "frc", "frm", "fro", "frp", "frr",
12564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "frs", "fur", "fy",
12664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ga",  "gaa", "gag", "gan", "gay", "gba", "gbz", "gd",
12764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gez", "gil", "gl",  "glk", "gmh", "gn",  "goh", "gom",
12864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gon", "gor", "got", "grb", "grc", "gsw", "gu",  "guc",
12964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gur", "guz", "gv",  "gwi",
13064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ha",  "hai", "hak", "haw", "he",  "hi",  "hif", "hil",
13164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "hit", "hmn", "ho",  "hr",  "hsb", "hsn", "ht",  "hu",
13264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "hup", "hy",  "hz",
13364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ia",  "iba", "ibb", "id",  "ie",  "ig",  "ii",  "ik",
13464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ilo", "inh", "io",  "is",  "it",  "iu",  "izh",
13564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ja",  "jam", "jbo", "jgo", "jmc", "jpr", "jrb", "jut",
13664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "jv",
13764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ka",  "kaa", "kab", "kac", "kaj", "kam", "kaw", "kbd",
13864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kbl", "kcg", "kde", "kea", "ken", "kfo", "kg",  "kgp",
13964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kha", "kho", "khq", "khw", "ki",  "kiu", "kj",  "kk",
14064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kkj", "kl",  "kln", "km",  "kmb", "kn",  "ko",  "koi",
14164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kok", "kos", "kpe", "kr",  "krc", "kri", "krj", "krl",
14264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kru", "ks",  "ksb", "ksf", "ksh", "ku",  "kum", "kut",
14364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kv",  "kw",  "ky",
14464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "la",  "lad", "lag", "lah", "lam", "lb",  "lez", "lfn",
14564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lg",  "li",  "lij", "liv", "lkt", "lmo", "ln",  "lo",
14664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lol", "loz", "lrc", "lt",  "ltg", "lu",  "lua", "lui",
14764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lun", "luo", "lus", "luy", "lv",  "lzh", "lzz",
14864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
14964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mdf", "mdh", "mdr", "men", "mer", "mfe", "mg",  "mga",
15064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mgh", "mgo", "mh",  "mi",  "mic", "min", "mis", "mk",
15164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ml",  "mn",  "mnc", "mni", "moh", "mos", "mr",  "mrj",
15264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ms",  "mt",  "mua", "mul", "mus", "mwl", "mwr", "mwv",
15364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "my",  "mye", "myv", "mzn",
15464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "na",  "nan", "nap", "naq", "nb",  "nd",  "nds", "ne",
15564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "new", "ng",  "nia", "niu", "njo", "nl",  "nmg", "nn",
15664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "nnh", "no",  "nog", "non", "nov", "nqo", "nr",  "nso",
15764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "nus", "nv",  "nwc", "ny",  "nym", "nyn", "nyo", "nzi",
15864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "oc",  "oj",  "om",  "or",  "os",  "osa", "ota",
15964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pa",  "pag", "pal", "pam", "pap", "pau", "pcd", "pdc",
16064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pdt", "peo", "pfl", "phn", "pi",  "pl",  "pms", "pnt",
16164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pon", "prg", "pro", "ps",  "pt",
16264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "qu",  "quc", "qug",
16364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "raj", "rap", "rar", "rgn", "rif", "rm",  "rn",  "ro",
16464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "rof", "rom", "rtm", "ru",  "rue", "rug", "rup",
16564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "rw",  "rwk",
16664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sa",  "sad", "sah", "sam", "saq", "sas", "sat", "saz",
16764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sba", "sbp", "sc",  "scn", "sco", "sd",  "sdc", "sdh",
16864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "se",  "see", "seh", "sei", "sel", "ses", "sg",  "sga",
16964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sgs", "shi", "shn", "shu", "si",  "sid", "sk",
17064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sl",  "sli", "sly", "sm",  "sma", "smj", "smn", "sms",
17164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sn",  "snk", "so",  "sog", "sq",  "sr",  "srn", "srr",
17264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ss",  "ssy", "st",  "stq", "su",  "suk", "sus", "sux",
17364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sv",  "sw",  "swb", "swc", "syc", "syr", "szl",
17464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ta",  "tcy", "te",  "tem", "teo", "ter", "tet", "tg",
17564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "th",  "ti",  "tig", "tiv", "tk",  "tkl", "tkr", "tl",
17664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tlh", "tli", "tly", "tmh", "tn",  "to",  "tog", "tpi",
17764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tr",  "tru", "trv", "ts",  "tsd", "tsi", "tt",  "ttt",
17864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tum", "tvl", "tw",  "twq", "ty",  "tyv", "tzm",
17964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "udm", "ug",  "uga", "uk",  "umb", "und", "ur",  "uz",
18064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "vai", "ve",  "vec", "vep", "vi",  "vls", "vmf", "vo",
18164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "vot", "vro", "vun",
18264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "wa",  "wae", "wal", "war", "was", "wbp", "wo",  "wuu",
18364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "xal", "xh",  "xmf", "xog",
18464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "yao", "yap", "yav", "ybb", "yi",  "yo",  "yrl", "yue",
18564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "za",  "zap", "zbl", "zea", "zen", "zgh", "zh",  "zu",
18664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "zun", "zxx", "zza",
187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL,
188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "in",  "iw",  "ji",  "jw",  "sh",    /* obsolete language codes */
189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL
190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
1918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius
192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char* const DEPRECATED_LANGUAGES[]={
193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "in", "iw", "ji", "jw", NULL, NULL
194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char* const REPLACEMENT_LANGUAGES[]={
196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "id", "he", "yi", "jv", NULL, NULL
197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Table of 3-letter language codes.
201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This is a lookup table used to convert 3-letter language codes to
203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * their 2-letter equivalent, where possible.  It must be kept in sync
204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * with LANGUAGES.  For all valid i, LANGUAGES[i] must refer to the
205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * same language as LANGUAGES_3[i].  The commented-out lines are
206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * copied from LANGUAGES to make eyeballing this baby easier.
207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Where a 3-letter language code has no 2-letter equivalent, the
209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 3-letter code occupies both LANGUAGES[i] and LANGUAGES_3[i].
210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This table should be terminated with a NULL entry, followed by a
212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * second list, and another NULL entry.  The two lists correspond to
213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the two lists in LANGUAGES.
214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
2158393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/* Generated using org.unicode.cldr.icu.GenerateISO639LanguageTables */
216c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert/* ISO639 table version is 20150505 */
217ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert/* Subsequent hand addition of selected languages */
218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char * const LANGUAGES_3[] = {
21964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "aar", "abk", "ace", "ach", "ada", "ady", "ave", "aeb",
22064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "afr", "afh", "agq", "ain", "aka", "akk", "akz", "ale",
22164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "aln", "alt", "amh", "arg", "ang", "anp", "ara", "arc",
2220596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    "arn", "aro", "arp", "arq", "ars", "arw", "ary", "arz", "asm",
22364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "asa", "ase", "ast", "ava", "avk", "awa", "aym", "aze",
22464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bak", "bal", "ban", "bar", "bas", "bax", "bbc", "bbj",
22564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bel", "bej", "bem", "bew", "bez", "bfd", "bfq", "bul",
22664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bgn", "bho", "bis", "bik", "bin", "bjn", "bkm", "bla",
22764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "bam", "ben", "bod", "bpy", "bqi", "bre", "bra", "brh",
22864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "brx", "bos", "bss", "bua", "bug", "bum", "byn", "byv",
229ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert    "cat", "cad", "car", "cay", "cch", "ccp", "che", "ceb", "cgg",
23064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "cha", "chb", "chg", "chk", "chm", "chn", "cho", "chp",
23164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "chr", "chy", "ckb", "cos", "cop", "cps", "cre", "crh",
23264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ces", "csb", "chu", "chv", "cym",
23364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "dan", "dak", "dar", "dav", "deu", "del", "den", "dgr",
23464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "din", "dje", "doi", "dsb", "dtp", "dua", "dum", "div",
23564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "dyo", "dyu", "dzo", "dzg",
23664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ebu", "ewe", "efi", "egl", "egy", "eka", "ell", "elx",
23764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "eng", "enm", "epo", "spa", "esu", "est", "eus", "ewo",
23864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ext",
23964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "fas", "fan", "fat", "ful", "fin", "fil", "fit", "fij",
24064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "fao", "fon", "fra", "frc", "frm", "fro", "frp", "frr",
24164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "frs", "fur", "fry",
24264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gle", "gaa", "gag", "gan", "gay", "gba", "gbz", "gla",
24364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gez", "gil", "glg", "glk", "gmh", "grn", "goh", "gom",
24464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gon", "gor", "got", "grb", "grc", "gsw", "guj", "guc",
24564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "gur", "guz", "glv", "gwi",
24664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "hau", "hai", "hak", "haw", "heb", "hin", "hif", "hil",
24764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "hit", "hmn", "hmo", "hrv", "hsb", "hsn", "hat", "hun",
24864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "hup", "hye", "her",
24964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ina", "iba", "ibb", "ind", "ile", "ibo", "iii", "ipk",
25064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ilo", "inh", "ido", "isl", "ita", "iku", "izh",
25164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "jpn", "jam", "jbo", "jgo", "jmc", "jpr", "jrb", "jut",
25264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "jav",
25364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kat", "kaa", "kab", "kac", "kaj", "kam", "kaw", "kbd",
25464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kbl", "kcg", "kde", "kea", "ken", "kfo", "kon", "kgp",
25564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kha", "kho", "khq", "khw", "kik", "kiu", "kua", "kaz",
25664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kkj", "kal", "kln", "khm", "kmb", "kan", "kor", "koi",
25764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kok", "kos", "kpe", "kau", "krc", "kri", "krj", "krl",
25864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kru", "kas", "ksb", "ksf", "ksh", "kur", "kum", "kut",
25964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kom", "cor", "kir",
26064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lat", "lad", "lag", "lah", "lam", "ltz", "lez", "lfn",
26164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lug", "lim", "lij", "liv", "lkt", "lmo", "lin", "lao",
26264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lol", "loz", "lrc", "lit", "ltg", "lub", "lua", "lui",
26364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "lun", "luo", "lus", "luy", "lav", "lzh", "lzz",
26464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mad", "maf", "mag", "mai", "mak", "man", "mas", "mde",
26564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mdf", "mdh", "mdr", "men", "mer", "mfe", "mlg", "mga",
26664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mgh", "mgo", "mah", "mri", "mic", "min", "mis", "mkd",
26764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mal", "mon", "mnc", "mni", "moh", "mos", "mar", "mrj",
26864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "msa", "mlt", "mua", "mul", "mus", "mwl", "mwr", "mwv",
26964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "mya", "mye", "myv", "mzn",
27064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "nau", "nan", "nap", "naq", "nob", "nde", "nds", "nep",
27164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "new", "ndo", "nia", "niu", "njo", "nld", "nmg", "nno",
27264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "nnh", "nor", "nog", "non", "nov", "nqo", "nbl", "nso",
27364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "nus", "nav", "nwc", "nya", "nym", "nyn", "nyo", "nzi",
27464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "oci", "oji", "orm", "ori", "oss", "osa", "ota",
27564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pan", "pag", "pal", "pam", "pap", "pau", "pcd", "pdc",
27664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pdt", "peo", "pfl", "phn", "pli", "pol", "pms", "pnt",
27764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "pon", "prg", "pro", "pus", "por",
27864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "que", "quc", "qug",
27964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "raj", "rap", "rar", "rgn", "rif", "roh", "run", "ron",
28064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "rof", "rom", "rtm", "rus", "rue", "rug", "rup",
28164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "kin", "rwk",
28264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "san", "sad", "sah", "sam", "saq", "sas", "sat", "saz",
28364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sba", "sbp", "srd", "scn", "sco", "snd", "sdc", "sdh",
28464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sme", "see", "seh", "sei", "sel", "ses", "sag", "sga",
28564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sgs", "shi", "shn", "shu", "sin", "sid", "slk",
28664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "slv", "sli", "sly", "smo", "sma", "smj", "smn", "sms",
28764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "sna", "snk", "som", "sog", "sqi", "srp", "srn", "srr",
28864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "ssw", "ssy", "sot", "stq", "sun", "suk", "sus", "sux",
28964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "swe", "swa", "swb", "swc", "syc", "syr", "szl",
29064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tam", "tcy", "tel", "tem", "teo", "ter", "tet", "tgk",
29164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tha", "tir", "tig", "tiv", "tuk", "tkl", "tkr", "tgl",
29264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tlh", "tli", "tly", "tmh", "tsn", "ton", "tog", "tpi",
29364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tur", "tru", "trv", "tso", "tsd", "tsi", "tat", "ttt",
29464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "tum", "tvl", "twi", "twq", "tah", "tyv", "tzm",
29564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "udm", "uig", "uga", "ukr", "umb", "und", "urd", "uzb",
29664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "vai", "ven", "vec", "vep", "vie", "vls", "vmf", "vol",
29764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "vot", "vro", "vun",
29864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "wln", "wae", "wal", "war", "was", "wbp", "wol", "wuu",
29964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "xal", "xho", "xmf", "xog",
30064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "yao", "yap", "yav", "ybb", "yid", "yor", "yrl", "yue",
30164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "zha", "zap", "zbl", "zea", "zen", "zgh", "zho", "zul",
30264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "zun", "zxx", "zza",
303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL,
304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "in",  "iw",  "ji",  "jw",  "sh",                          */
305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ind", "heb", "yid", "jaw", "srp",
306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL
307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Table of 2-letter country codes.
311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This list must be in sorted order.  This list is returned directly
313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to the user by some API.
314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This list must be kept in sync with COUNTRIES_3, with corresponding
316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * entries matched.
317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This table should be terminated with a NULL entry, followed by a
319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * second list, and another NULL entry.  The first list is visible to
320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * user code when this array is returned by API.  The second list
321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * contains codes we support, but do not expose through user API.
322b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Notes:
324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * ZR(ZAR) is now CD(COD) and FX(FXX) is PS(PSE) as per
326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * http://www.evertype.com/standards/iso3166/iso3166-1-en.html added
327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * new codes keeping the old ones for compatibility updated to include
328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * 1999/12/03 revisions *CWB*
329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * RO(ROM) is now RO(ROU) according to
331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * http://www.iso.org/iso/en/prods-services/iso3166ma/03updates-on-iso-3166/nlv3e-rou.html
332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char * const COUNTRIES[] = {
3348393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",
335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",
336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",
3378393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "BJ",  "BL",  "BM",  "BN",  "BO",  "BQ",  "BR",  "BS",  "BT",  "BV",
338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",
339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",
3408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "CU",  "CV",  "CW",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",
341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",
342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",
343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",
344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GM",  "GN",  "GP",  "GQ",  "GR",  "GS",  "GT",  "GU",
345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",
346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS",
347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",
348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",
349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "LB",  "LC",  "LI",  "LK",  "LR",  "LS",  "LT",  "LU",
350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "LV",  "LY",  "MA",  "MC",  "MD",  "ME",  "MF",  "MG",  "MH",  "MK",
351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ML",  "MM",  "MN",  "MO",  "MP",  "MQ",  "MR",  "MS",
352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "MT",  "MU",  "MV",  "MW",  "MX",  "MY",  "MZ",  "NA",
353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "NC",  "NE",  "NF",  "NG",  "NI",  "NL",  "NO",  "NP",
354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "NR",  "NU",  "NZ",  "OM",  "PA",  "PE",  "PF",  "PG",
355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "PH",  "PK",  "PL",  "PM",  "PN",  "PR",  "PS",  "PT",
356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "PW",  "PY",  "QA",  "RE",  "RO",  "RS",  "RU",  "RW",  "SA",
357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",
3588393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "SS",  "ST",  "SV",
3598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "SX",  "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",
360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",
361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",
362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",
363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",
364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL,
3658393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "AN",  "BU", "CS", "FX", "RO", "SU", "TP", "YD", "YU", "ZR",   /* obsolete country codes */
366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL
367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
3698393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Corneliusstatic const char* const DEPRECATED_COUNTRIES[] = {
3708393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "AN", "BU", "CS", "DD", "DY", "FX", "HV", "NH", "RH", "SU", "TP", "UK", "VD", "YD", "YU", "ZR", NULL, NULL /* deprecated country list */
371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char* const REPLACEMENT_COUNTRIES[] = {
3738393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "AN", "BU", "CS", "DD", "DY", "FX", "HV", "NH", "RH", "SU", "TP", "UK", "VD", "YD", "YU", "ZR" */
37464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    "CW", "MM", "RS", "DE", "BJ", "FR", "BF", "VU", "ZW", "RU", "TL", "GB", "VN", "YE", "RS", "CD", NULL, NULL  /* replacement country codes */
375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
37664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Table of 3-letter country codes.
379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This is a lookup table used to convert 3-letter country codes to
381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * their 2-letter equivalent.  It must be kept in sync with COUNTRIES.
382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * For all valid i, COUNTRIES[i] must refer to the same country as
383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * COUNTRIES_3[i].  The commented-out lines are copied from COUNTRIES
384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to make eyeballing this baby easier.
385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This table should be terminated with a NULL entry, followed by a
387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * second list, and another NULL entry.  The two lists correspond to
388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the two lists in COUNTRIES.
389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
390b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char * const COUNTRIES_3[] = {
3918393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "AD",  "AE",  "AF",  "AG",  "AI",  "AL",  "AM",      */
3928393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "AND", "ARE", "AFG", "ATG", "AIA", "ALB", "ARM",
393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "AO",  "AQ",  "AR",  "AS",  "AT",  "AU",  "AW",  "AX",  "AZ",     */
394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "AGO", "ATA", "ARG", "ASM", "AUT", "AUS", "ABW", "ALA", "AZE",
395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "BA",  "BB",  "BD",  "BE",  "BF",  "BG",  "BH",  "BI",     */
396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "BIH", "BRB", "BGD", "BEL", "BFA", "BGR", "BHR", "BDI",
3978393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "BJ",  "BL",  "BM",  "BN",  "BO",  "BQ",  "BR",  "BS",  "BT",  "BV",     */
3988393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "BEN", "BLM", "BMU", "BRN", "BOL", "BES", "BRA", "BHS", "BTN", "BVT",
399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "BW",  "BY",  "BZ",  "CA",  "CC",  "CD",  "CF",  "CG",     */
400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "BWA", "BLR", "BLZ", "CAN", "CCK", "COD", "CAF", "COG",
401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "CH",  "CI",  "CK",  "CL",  "CM",  "CN",  "CO",  "CR",     */
402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "CHE", "CIV", "COK", "CHL", "CMR", "CHN", "COL", "CRI",
4038393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "CU",  "CV",  "CW",  "CX",  "CY",  "CZ",  "DE",  "DJ",  "DK",     */
4048393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "CUB", "CPV", "CUW", "CXR", "CYP", "CZE", "DEU", "DJI", "DNK",
405b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "DM",  "DO",  "DZ",  "EC",  "EE",  "EG",  "EH",  "ER",     */
406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "DMA", "DOM", "DZA", "ECU", "EST", "EGY", "ESH", "ERI",
407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "ES",  "ET",  "FI",  "FJ",  "FK",  "FM",  "FO",  "FR",     */
408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ESP", "ETH", "FIN", "FJI", "FLK", "FSM", "FRO", "FRA",
409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "GA",  "GB",  "GD",  "GE",  "GF",  "GG",  "GH",  "GI",  "GL",     */
410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GAB", "GBR", "GRD", "GEO", "GUF", "GGY", "GHA", "GIB", "GRL",
411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "GM",  "GN",  "GP",  "GQ",  "GR",  "GS",  "GT",  "GU",     */
412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GMB", "GIN", "GLP", "GNQ", "GRC", "SGS", "GTM", "GUM",
413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "GW",  "GY",  "HK",  "HM",  "HN",  "HR",  "HT",  "HU",     */
414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "GNB", "GUY", "HKG", "HMD", "HND", "HRV", "HTI", "HUN",
415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "ID",  "IE",  "IL",  "IM",  "IN",  "IO",  "IQ",  "IR",  "IS" */
416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "IDN", "IRL", "ISR", "IMN", "IND", "IOT", "IRQ", "IRN", "ISL",
417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "IT",  "JE",  "JM",  "JO",  "JP",  "KE",  "KG",  "KH",  "KI",     */
418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "ITA", "JEY", "JAM", "JOR", "JPN", "KEN", "KGZ", "KHM", "KIR",
419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "KM",  "KN",  "KP",  "KR",  "KW",  "KY",  "KZ",  "LA",     */
420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "COM", "KNA", "PRK", "KOR", "KWT", "CYM", "KAZ", "LAO",
421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "LB",  "LC",  "LI",  "LK",  "LR",  "LS",  "LT",  "LU",     */
422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "LBN", "LCA", "LIE", "LKA", "LBR", "LSO", "LTU", "LUX",
423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "LV",  "LY",  "MA",  "MC",  "MD",  "ME",  "MF",  "MG",  "MH",  "MK",     */
424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "LVA", "LBY", "MAR", "MCO", "MDA", "MNE", "MAF", "MDG", "MHL", "MKD",
425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "ML",  "MM",  "MN",  "MO",  "MP",  "MQ",  "MR",  "MS",     */
426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "MLI", "MMR", "MNG", "MAC", "MNP", "MTQ", "MRT", "MSR",
427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "MT",  "MU",  "MV",  "MW",  "MX",  "MY",  "MZ",  "NA",     */
428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "MLT", "MUS", "MDV", "MWI", "MEX", "MYS", "MOZ", "NAM",
429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "NC",  "NE",  "NF",  "NG",  "NI",  "NL",  "NO",  "NP",     */
430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "NCL", "NER", "NFK", "NGA", "NIC", "NLD", "NOR", "NPL",
431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "NR",  "NU",  "NZ",  "OM",  "PA",  "PE",  "PF",  "PG",     */
432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "NRU", "NIU", "NZL", "OMN", "PAN", "PER", "PYF", "PNG",
433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "PH",  "PK",  "PL",  "PM",  "PN",  "PR",  "PS",  "PT",     */
434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "PHL", "PAK", "POL", "SPM", "PCN", "PRI", "PSE", "PRT",
435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "PW",  "PY",  "QA",  "RE",  "RO",  "RS",  "RU",  "RW",  "SA",     */
436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "PLW", "PRY", "QAT", "REU", "ROU", "SRB", "RUS", "RWA", "SAU",
437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "SB",  "SC",  "SD",  "SE",  "SG",  "SH",  "SI",  "SJ",     */
438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "SLB", "SYC", "SDN", "SWE", "SGP", "SHN", "SVN", "SJM",
4398393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "SK",  "SL",  "SM",  "SN",  "SO",  "SR",  "SS",  "ST",  "SV",     */
4408393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "SVK", "SLE", "SMR", "SEN", "SOM", "SUR", "SSD", "STP", "SLV",
4418393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "SX",  "SY",  "SZ",  "TC",  "TD",  "TF",  "TG",  "TH",  "TJ",     */
4428393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "SXM", "SYR", "SWZ", "TCA", "TCD", "ATF", "TGO", "THA", "TJK",
443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "TK",  "TL",  "TM",  "TN",  "TO",  "TR",  "TT",  "TV",     */
444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "TKL", "TLS", "TKM", "TUN", "TON", "TUR", "TTO", "TUV",
445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "TW",  "TZ",  "UA",  "UG",  "UM",  "US",  "UY",  "UZ",     */
446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "TWN", "TZA", "UKR", "UGA", "UMI", "USA", "URY", "UZB",
447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "VA",  "VC",  "VE",  "VG",  "VI",  "VN",  "VU",  "WF",     */
448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "VAT", "VCT", "VEN", "VGB", "VIR", "VNM", "VUT", "WLF",
449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*  "WS",  "YE",  "YT",  "ZA",  "ZM",  "ZW",          */
450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    "WSM", "YEM", "MYT", "ZAF", "ZMB", "ZWE",
451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL,
4528393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius/*  "AN",  "BU",  "CS",  "FX",  "RO", "SU",  "TP",  "YD",  "YU",  "ZR" */
4538393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius    "ANT", "BUR", "SCG", "FXX", "ROM", "SUN", "TMP", "YMD", "YUG", "ZAR",
454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruNULL
455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef struct CanonicalizationMap {
458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *id;          /* input ID */
459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *canonicalID; /* canonicalized output ID */
460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *keyword;     /* keyword, or NULL if none */
461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *value;       /* keyword value, or NULL if kw==NULL */
462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} CanonicalizationMap;
463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * A map to canonicalize locale IDs.  This handles a variety of
466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * different semantic kinds of transformations.
467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const CanonicalizationMap CANONICALIZE_MAP[] = {
469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "",               "en_US_POSIX", NULL, NULL }, /* .NET name */
47027f654740f2a26ad62a5c155af9199af9e69b889claireho    { "c",              "en_US_POSIX", NULL, NULL }, /* POSIX name */
471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "posix",          "en_US_POSIX", NULL, NULL }, /* POSIX name (alias of C) */
472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "art_LOJBAN",     "jbo", NULL, NULL }, /* registered name */
473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "az_AZ_CYRL",     "az_Cyrl_AZ", NULL, NULL }, /* .NET name */
474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "az_AZ_LATN",     "az_Latn_AZ", NULL, NULL }, /* .NET name */
475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "ca_ES_PREEURO",  "ca_ES", "currency", "ESP" },
476c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "de__PHONEBOOK",  "de", "collation", "phonebook" }, /* Old ICU name */
477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "de_AT_PREEURO",  "de_AT", "currency", "ATS" },
478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "de_DE_PREEURO",  "de_DE", "currency", "DEM" },
479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "de_LU_PREEURO",  "de_LU", "currency", "LUF" },
480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "el_GR_PREEURO",  "el_GR", "currency", "GRD" },
481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "en_BE_PREEURO",  "en_BE", "currency", "BEF" },
482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "en_IE_PREEURO",  "en_IE", "currency", "IEP" },
483c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "es__TRADITIONAL", "es", "collation", "traditional" }, /* Old ICU name */
484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "es_ES_PREEURO",  "es_ES", "currency", "ESP" },
485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "eu_ES_PREEURO",  "eu_ES", "currency", "ESP" },
486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "fi_FI_PREEURO",  "fi_FI", "currency", "FIM" },
487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "fr_BE_PREEURO",  "fr_BE", "currency", "BEF" },
488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "fr_FR_PREEURO",  "fr_FR", "currency", "FRF" },
489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "fr_LU_PREEURO",  "fr_LU", "currency", "LUF" },
490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "ga_IE_PREEURO",  "ga_IE", "currency", "IEP" },
491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "gl_ES_PREEURO",  "gl_ES", "currency", "ESP" },
492c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "hi__DIRECT",     "hi", "collation", "direct" }, /* Old ICU name */
493b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "it_IT_PREEURO",  "it_IT", "currency", "ITL" },
494c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "ja_JP_TRADITIONAL", "ja_JP", "calendar", "japanese" }, /* Old ICU name */
495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "nb_NO_NY",       "nn_NO", NULL, NULL },  /* "markus said this was ok" :-) */
496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "nl_BE_PREEURO",  "nl_BE", "currency", "BEF" },
497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "nl_NL_PREEURO",  "nl_NL", "currency", "NLG" },
498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "pt_PT_PREEURO",  "pt_PT", "currency", "PTE" },
499c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "sr_SP_CYRL",     "sr_Cyrl_RS", NULL, NULL }, /* .NET name */
500c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "sr_SP_LATN",     "sr_Latn_RS", NULL, NULL }, /* .NET name */
501c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "sr_YU_CYRILLIC", "sr_Cyrl_RS", NULL, NULL }, /* Linux name */
502c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "th_TH_TRADITIONAL", "th_TH", "calendar", "buddhist" }, /* Old ICU name */
503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "uz_UZ_CYRILLIC", "uz_Cyrl_UZ", NULL, NULL }, /* Linux name */
504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "uz_UZ_CYRL",     "uz_Cyrl_UZ", NULL, NULL }, /* .NET name */
505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "uz_UZ_LATN",     "uz_Latn_UZ", NULL, NULL }, /* .NET name */
506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "zh_CHS",         "zh_Hans", NULL, NULL }, /* .NET name */
507c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "zh_CHT",         "zh_Hant", NULL, NULL }, /* .NET name */
508103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_GAN",         "gan", NULL, NULL }, /* registered name */
509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    { "zh_GUOYU",       "zh", NULL, NULL }, /* registered name */
510103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_HAKKA",       "hak", NULL, NULL }, /* registered name */
511103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_MIN_NAN",     "nan", NULL, NULL }, /* registered name */
512103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_WUU",         "wuu", NULL, NULL }, /* registered name */
513103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_XIANG",       "hsn", NULL, NULL }, /* registered name */
514103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    { "zh_YUE",         "yue", NULL, NULL }, /* registered name */
515c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru};
516c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
517c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querutypedef struct VariantMap {
518c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    const char *variant;          /* input ID */
519c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    const char *keyword;     /* keyword, or NULL if none */
520c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    const char *value;       /* keyword value, or NULL if kw==NULL */
521c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru} VariantMap;
522c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru
523c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Querustatic const VariantMap VARIANT_MAP[] = {
524c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "EURO",   "currency", "EUR" },
525c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "PINYIN", "collation", "pinyin" }, /* Solaris variant */
526c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    { "STROKE", "collation", "stroke" }  /* Solaris variant */
527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
52927f654740f2a26ad62a5c155af9199af9e69b889claireho/* ### BCP47 Conversion *******************************************/
53027f654740f2a26ad62a5c155af9199af9e69b889claireho/* Test if the locale id has BCP47 u extension and does not have '@' */
53127f654740f2a26ad62a5c155af9199af9e69b889claireho#define _hasBCP47Extension(id) (id && uprv_strstr(id, "@") == NULL && getShortestSubtagLength(localeID) == 1)
53227f654740f2a26ad62a5c155af9199af9e69b889claireho/* Converts the BCP47 id to Unicode id. Does nothing to id if conversion fails */
53327f654740f2a26ad62a5c155af9199af9e69b889claireho#define _ConvertBCP47(finalID, id, buffer, length,err) \
534ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert        if (uloc_forLanguageTag(id, buffer, length, NULL, err) <= 0 ||  \
535ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert                U_FAILURE(*err) || *err == U_STRING_NOT_TERMINATED_WARNING) { \
53627f654740f2a26ad62a5c155af9199af9e69b889claireho            finalID=id; \
537ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert            if (*err == U_STRING_NOT_TERMINATED_WARNING) { *err = U_BUFFER_OVERFLOW_ERROR; } \
53827f654740f2a26ad62a5c155af9199af9e69b889claireho        } else { \
53927f654740f2a26ad62a5c155af9199af9e69b889claireho            finalID=buffer; \
54027f654740f2a26ad62a5c155af9199af9e69b889claireho        }
54127f654740f2a26ad62a5c155af9199af9e69b889claireho/* Gets the size of the shortest subtag in the given localeID. */
54227f654740f2a26ad62a5c155af9199af9e69b889clairehostatic int32_t getShortestSubtagLength(const char *localeID) {
543ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert    int32_t localeIDLength = static_cast<int32_t>(uprv_strlen(localeID));
54427f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t length = localeIDLength;
54527f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t tmpLength = 0;
54627f654740f2a26ad62a5c155af9199af9e69b889claireho    int32_t i;
54727f654740f2a26ad62a5c155af9199af9e69b889claireho    UBool reset = TRUE;
54827f654740f2a26ad62a5c155af9199af9e69b889claireho
54927f654740f2a26ad62a5c155af9199af9e69b889claireho    for (i = 0; i < localeIDLength; i++) {
55027f654740f2a26ad62a5c155af9199af9e69b889claireho        if (localeID[i] != '_' && localeID[i] != '-') {
55127f654740f2a26ad62a5c155af9199af9e69b889claireho            if (reset) {
55227f654740f2a26ad62a5c155af9199af9e69b889claireho                tmpLength = 0;
55327f654740f2a26ad62a5c155af9199af9e69b889claireho                reset = FALSE;
55427f654740f2a26ad62a5c155af9199af9e69b889claireho            }
55527f654740f2a26ad62a5c155af9199af9e69b889claireho            tmpLength++;
55627f654740f2a26ad62a5c155af9199af9e69b889claireho        } else {
55727f654740f2a26ad62a5c155af9199af9e69b889claireho            if (tmpLength != 0 && tmpLength < length) {
55827f654740f2a26ad62a5c155af9199af9e69b889claireho                length = tmpLength;
55927f654740f2a26ad62a5c155af9199af9e69b889claireho            }
56027f654740f2a26ad62a5c155af9199af9e69b889claireho            reset = TRUE;
56127f654740f2a26ad62a5c155af9199af9e69b889claireho        }
56227f654740f2a26ad62a5c155af9199af9e69b889claireho    }
56327f654740f2a26ad62a5c155af9199af9e69b889claireho
56427f654740f2a26ad62a5c155af9199af9e69b889claireho    return length;
56527f654740f2a26ad62a5c155af9199af9e69b889claireho}
56627f654740f2a26ad62a5c155af9199af9e69b889claireho
567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### Keywords **************************************************/
5680596faeddefbf198de137d5e893708495ab1584cFredrik Roubert#define UPRV_ISDIGIT(c) (((c) >= '0') && ((c) <= '9'))
5690596faeddefbf198de137d5e893708495ab1584cFredrik Roubert#define UPRV_ISALPHANUM(c) (uprv_isASCIILetter(c) || UPRV_ISDIGIT(c) )
5700596faeddefbf198de137d5e893708495ab1584cFredrik Roubert/* Punctuation/symbols allowed in legacy key values */
5710596faeddefbf198de137d5e893708495ab1584cFredrik Roubert#define UPRV_OK_VALUE_PUNCTUATION(c) ((c) == '_' || (c) == '-' || (c) == '+' || (c) == '/')
572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ULOC_KEYWORD_BUFFER_LEN 25
574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define ULOC_MAX_NO_KEYWORDS 25
575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
57627f654740f2a26ad62a5c155af9199af9e69b889clairehoU_CAPI const char * U_EXPORT2
577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querulocale_getKeywordsStart(const char *localeID) {
578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *result = NULL;
579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if((result = uprv_strchr(localeID, '@')) != NULL) {
580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return result;
581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if (U_CHARSET_FAMILY == U_EBCDIC_FAMILY)
583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else {
584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* We do this because the @ sign is variant, and the @ sign used on one
585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        EBCDIC machine won't be compiled the same way on other EBCDIC based
586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        machines. */
587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        static const uint8_t ebcdicSigns[] = { 0x7C, 0x44, 0x66, 0x80, 0xAC, 0xAE, 0xAF, 0xB5, 0xEC, 0xEF, 0x00 };
588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const uint8_t *charToFind = ebcdicSigns;
589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(*charToFind) {
590b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if((result = uprv_strchr(localeID, *charToFind)) != NULL) {
591b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return result;
592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
593b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            charToFind++;
594b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
595b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
596b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
597b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NULL;
598b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
599b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
600b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
601b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param buf buffer of size [ULOC_KEYWORD_BUFFER_LEN]
602b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param keywordName incoming name to be canonicalized
603b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param status return status (keyword too long)
604b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return length of the keyword name
605b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
606b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t locale_canonKeywordName(char *buf, const char *keywordName, UErrorCode *status)
607b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
6080596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  int32_t keywordNameLen = 0;
60964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
6100596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  for (; *keywordName != 0; keywordName++) {
6110596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (!UPRV_ISALPHANUM(*keywordName)) {
6120596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      *status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
6130596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      return 0;
6140596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
6150596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (keywordNameLen < ULOC_KEYWORD_BUFFER_LEN - 1) {
6160596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      buf[keywordNameLen++] = uprv_tolower(*keywordName);
6170596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    } else {
6180596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      /* keyword name too long for internal buffer */
6190596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      *status = U_INTERNAL_PROGRAM_ERROR;
6200596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      return 0;
6210596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
6230596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  if (keywordNameLen == 0) {
6240596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    *status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name */
6250596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    return 0;
626b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  }
6270596faeddefbf198de137d5e893708495ab1584cFredrik Roubert  buf[keywordNameLen] = 0; /* terminate */
62864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  return keywordNameLen;
630b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
631b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
632b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef struct {
633b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char keyword[ULOC_KEYWORD_BUFFER_LEN];
634b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t keywordLen;
635b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *valueStart;
636b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t valueLen;
637b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} KeywordStruct;
638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t U_CALLCONV
640103e9ffba2cba345d0078eb8b8db33249f81840aCraig CorneliuscompareKeywordStructs(const void * /*context*/, const void *left, const void *right) {
641b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* leftString = ((const KeywordStruct *)left)->keyword;
642b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* rightString = ((const KeywordStruct *)right)->keyword;
643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return uprv_strcmp(leftString, rightString);
644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
645b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
646b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Both addKeyword and addValue must already be in canonical form.
648b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Either both addKeyword and addValue are NULL, or neither is NULL.
649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If they are not NULL they must be zero terminated.
650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * If addKeyword is not NULL is must have length small enough to fit in KeywordStruct.keyword.
651b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
652b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t
653b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_getKeywords(const char *localeID,
654b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             char prev,
655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             char *keywords, int32_t keywordCapacity,
656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             char *values, int32_t valuesCapacity, int32_t *valLen,
657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             UBool valuesToo,
658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             const char* addKeyword,
659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             const char* addValue,
660b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             UErrorCode *status)
661b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    KeywordStruct keywordList[ULOC_MAX_NO_KEYWORDS];
66364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t maxKeywords = ULOC_MAX_NO_KEYWORDS;
665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t numKeywords = 0;
666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* pos = localeID;
667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* equalSign = NULL;
668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* semicolon = NULL;
669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i = 0, j, n;
670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t keywordsLen = 0;
671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t valuesLen = 0;
672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(prev == '@') { /* start of keyword definition */
674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* we will grab pairs, trim spaces, lowercase keywords, sort and return */
675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        do {
676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UBool duplicate = FALSE;
677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* skip leading spaces */
678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while(*pos == ' ') {
679b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                pos++;
680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (!*pos) { /* handle trailing "; " */
682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(numKeywords == maxKeywords) {
685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                *status = U_INTERNAL_PROGRAM_ERROR;
686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return 0;
687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            equalSign = uprv_strchr(pos, '=');
689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            semicolon = uprv_strchr(pos, ';');
690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* lack of '=' [foo@currency] is illegal */
691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* ';' before '=' [foo@currency;collation=pinyin] is illegal */
692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(!equalSign || (semicolon && semicolon<equalSign)) {
693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                *status = U_INVALID_FORMAT_ERROR;
694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return 0;
695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
696b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* need to normalize both keyword and keyword name */
697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(equalSign - pos >= ULOC_KEYWORD_BUFFER_LEN) {
698b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                /* keyword name too long for internal buffer */
699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                *status = U_INTERNAL_PROGRAM_ERROR;
700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return 0;
701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            for(i = 0, n = 0; i < equalSign - pos; ++i) {
703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (pos[i] != ' ') {
704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    keywordList[numKeywords].keyword[n++] = uprv_tolower(pos[i]);
705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
70759d709d503bab6e2b61931737e662dd293b40578ccornelius
70859d709d503bab6e2b61931737e662dd293b40578ccornelius            /* zero-length keyword is an error. */
70959d709d503bab6e2b61931737e662dd293b40578ccornelius            if (n == 0) {
71059d709d503bab6e2b61931737e662dd293b40578ccornelius                *status = U_INVALID_FORMAT_ERROR;
71159d709d503bab6e2b61931737e662dd293b40578ccornelius                return 0;
71259d709d503bab6e2b61931737e662dd293b40578ccornelius            }
71359d709d503bab6e2b61931737e662dd293b40578ccornelius
714b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            keywordList[numKeywords].keyword[n] = 0;
715b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            keywordList[numKeywords].keywordLen = n;
716b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* now grab the value part. First we skip the '=' */
717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            equalSign++;
718b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* then we leading spaces */
719b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while(*equalSign == ' ') {
720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                equalSign++;
721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
72259d709d503bab6e2b61931737e662dd293b40578ccornelius
72359d709d503bab6e2b61931737e662dd293b40578ccornelius            /* Premature end or zero-length value */
724c14898b482f76ecab9026615e2e4c6fe78358bdcFredrik Roubert            if (!*equalSign || equalSign == semicolon) {
72559d709d503bab6e2b61931737e662dd293b40578ccornelius                *status = U_INVALID_FORMAT_ERROR;
72659d709d503bab6e2b61931737e662dd293b40578ccornelius                return 0;
72759d709d503bab6e2b61931737e662dd293b40578ccornelius            }
72859d709d503bab6e2b61931737e662dd293b40578ccornelius
729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            keywordList[numKeywords].valueStart = equalSign;
73059d709d503bab6e2b61931737e662dd293b40578ccornelius
731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            pos = semicolon;
732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            i = 0;
733b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(pos) {
734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                while(*(pos - i - 1) == ' ') {
735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    i++;
736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
737b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordList[numKeywords].valueLen = (int32_t)(pos - equalSign - i);
738b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                pos++;
739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            } else {
740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                i = (int32_t)uprv_strlen(equalSign);
741816c50fb47edc483a0516072584640b520045214claireho                while(i && equalSign[i-1] == ' ') {
742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    i--;
743b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordList[numKeywords].valueLen = i;
745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* If this is a duplicate keyword, then ignore it */
747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            for (j=0; j<numKeywords; ++j) {
748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (uprv_strcmp(keywordList[j].keyword, keywordList[numKeywords].keyword) == 0) {
749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    duplicate = TRUE;
750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
752b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
753b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (!duplicate) {
754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++numKeywords;
755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
756b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } while(pos);
757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Handle addKeyword/addValue. */
759b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (addKeyword != NULL) {
760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            UBool duplicate = FALSE;
761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            U_ASSERT(addValue != NULL);
762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Search for duplicate; if found, do nothing. Explicit keyword
763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru               overrides addKeyword. */
764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            for (j=0; j<numKeywords; ++j) {
765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (uprv_strcmp(keywordList[j].keyword, addKeyword) == 0) {
766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    duplicate = TRUE;
767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break;
768b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
769b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
770b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (!duplicate) {
771b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (numKeywords == maxKeywords) {
772b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    *status = U_INTERNAL_PROGRAM_ERROR;
773b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    return 0;
774b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
775b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                uprv_strcpy(keywordList[numKeywords].keyword, addKeyword);
776b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordList[numKeywords].keywordLen = (int32_t)uprv_strlen(addKeyword);
777b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordList[numKeywords].valueStart = addValue;
778b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordList[numKeywords].valueLen = (int32_t)uprv_strlen(addValue);
779b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++numKeywords;
780b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
781b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
782b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            U_ASSERT(addValue == NULL);
783b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
784b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* now we have a list of keywords */
786b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* we need to sort it */
787b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_sortArray(keywordList, numKeywords, sizeof(KeywordStruct), compareKeywordStructs, NULL, FALSE, status);
78864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Now construct the keyword part */
790b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for(i = 0; i < numKeywords; i++) {
791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(keywordsLen + keywordList[i].keywordLen + 1< keywordCapacity) {
792b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                uprv_strcpy(keywords+keywordsLen, keywordList[i].keyword);
793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(valuesToo) {
794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    keywords[keywordsLen + keywordList[i].keywordLen] = '=';
795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    keywords[keywordsLen + keywordList[i].keywordLen] = 0;
797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
799b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            keywordsLen += keywordList[i].keywordLen + 1;
800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(valuesToo) {
801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(keywordsLen + keywordList[i].valueLen < keywordCapacity) {
802b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_strncpy(keywords+keywordsLen, keywordList[i].valueStart, keywordList[i].valueLen);
803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                keywordsLen += keywordList[i].valueLen;
80564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(i < numKeywords - 1) {
80764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                    if(keywordsLen < keywordCapacity) {
808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        keywords[keywordsLen] = ';';
809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    keywordsLen++;
811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
813b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(values) {
814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(valuesLen + keywordList[i].valueLen + 1< valuesCapacity) {
815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_strcpy(values+valuesLen, keywordList[i].valueStart);
816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    values[valuesLen + keywordList[i].valueLen] = 0;
817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                valuesLen += keywordList[i].valueLen + 1;
819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
820b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
821b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(values) {
822b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            values[valuesLen] = 0;
823b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(valLen) {
824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                *valLen = valuesLen;
825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
82764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        return u_terminateChars(keywords, keywordCapacity, keywordsLen, status);
828b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
830b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CFUNC int32_t
834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querulocale_getKeywords(const char *localeID,
835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                   char prev,
836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                   char *keywords, int32_t keywordCapacity,
837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                   char *values, int32_t valuesCapacity, int32_t *valLen,
838b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                   UBool valuesToo,
839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                   UErrorCode *status) {
840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return _getKeywords(localeID, prev, keywords, keywordCapacity,
841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        values, valuesCapacity, valLen, valuesToo,
842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        NULL, NULL, status);
843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
844b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getKeywordValue(const char* localeID,
847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     const char* keywordName,
848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     char* buffer, int32_t bufferCapacity,
849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     UErrorCode* status)
85064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert{
85127f654740f2a26ad62a5c155af9199af9e69b889claireho    const char* startSearchHere = NULL;
852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* nextSeparator = NULL;
853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t result = 0;
856b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(status && U_SUCCESS(*status) && localeID) {
85827f654740f2a26ad62a5c155af9199af9e69b889claireho      char tempBuffer[ULOC_FULLNAME_CAPACITY];
85927f654740f2a26ad62a5c155af9199af9e69b889claireho      const char* tmpLocaleID;
86027f654740f2a26ad62a5c155af9199af9e69b889claireho
8610596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      if (keywordName == NULL || keywordName[0] == 0) {
8620596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        *status = U_ILLEGAL_ARGUMENT_ERROR;
8630596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        return 0;
8640596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      }
8650596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
8660596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      locale_canonKeywordName(keywordNameBuffer, keywordName, status);
8670596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      if(U_FAILURE(*status)) {
8680596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        return 0;
8690596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      }
8700596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
87127f654740f2a26ad62a5c155af9199af9e69b889claireho      if (_hasBCP47Extension(localeID)) {
87227f654740f2a26ad62a5c155af9199af9e69b889claireho          _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
87327f654740f2a26ad62a5c155af9199af9e69b889claireho      } else {
87427f654740f2a26ad62a5c155af9199af9e69b889claireho          tmpLocaleID=localeID;
87527f654740f2a26ad62a5c155af9199af9e69b889claireho      }
87664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
8770596faeddefbf198de137d5e893708495ab1584cFredrik Roubert      startSearchHere = locale_getKeywordsStart(tmpLocaleID);
878b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      if(startSearchHere == NULL) {
879b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          /* no keywords, return at once */
880b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          return 0;
881b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      }
882b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
883b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      /* find the first keyword */
884b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      while(startSearchHere) {
8850596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          const char* keyValueTail;
8860596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          int32_t keyValueLen;
8870596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
8880596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          startSearchHere++; /* skip @ or ; */
8890596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          nextSeparator = uprv_strchr(startSearchHere, '=');
8900596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          if(!nextSeparator) {
8910596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              *status = U_ILLEGAL_ARGUMENT_ERROR; /* key must have =value */
8920596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              return 0;
8930596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          }
8940596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          /* strip leading & trailing spaces (TC decided to tolerate these) */
895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          while(*startSearchHere == ' ') {
896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              startSearchHere++;
897b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          }
8980596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          keyValueTail = nextSeparator;
8990596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          while (keyValueTail > startSearchHere && *(keyValueTail-1) == ' ') {
9000596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              keyValueTail--;
9010596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          }
9020596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          /* now keyValueTail points to first char after the keyName */
9030596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          /* copy & normalize keyName from locale */
9040596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          if (startSearchHere == keyValueTail) {
9050596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              *status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name in passed-in locale */
9060596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              return 0;
907b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          }
9080596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          keyValueLen = 0;
9090596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          while (startSearchHere < keyValueTail) {
9100596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (!UPRV_ISALPHANUM(*startSearchHere)) {
9110596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              *status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
9120596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              return 0;
9130596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
9140596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (keyValueLen < ULOC_KEYWORD_BUFFER_LEN - 1) {
9150596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              localeKeywordNameBuffer[keyValueLen++] = uprv_tolower(*startSearchHere++);
9160596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            } else {
917b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              /* keyword name too long for internal buffer */
918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              *status = U_INTERNAL_PROGRAM_ERROR;
919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              return 0;
9200596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          }
9220596faeddefbf198de137d5e893708495ab1584cFredrik Roubert          localeKeywordNameBuffer[keyValueLen] = 0; /* terminate */
92364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          startSearchHere = uprv_strchr(nextSeparator, ';');
92564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          if(uprv_strcmp(keywordNameBuffer, localeKeywordNameBuffer) == 0) {
9270596faeddefbf198de137d5e893708495ab1584cFredrik Roubert               /* current entry matches the keyword. */
9280596faeddefbf198de137d5e893708495ab1584cFredrik Roubert             nextSeparator++; /* skip '=' */
9290596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              /* First strip leading & trailing spaces (TC decided to tolerate these) */
930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              while(*nextSeparator == ' ') {
9310596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                nextSeparator++;
9320596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              }
9330596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              keyValueTail = (startSearchHere)? startSearchHere: nextSeparator + uprv_strlen(nextSeparator);
9340596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              while(keyValueTail > nextSeparator && *(keyValueTail-1) == ' ') {
9350596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                keyValueTail--;
9360596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              }
9370596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              /* Now copy the value, but check well-formedness */
9380596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              if (nextSeparator == keyValueTail) {
9390596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                *status = U_ILLEGAL_ARGUMENT_ERROR; /* empty key value name in passed-in locale */
9400596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                return 0;
941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              }
9420596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              keyValueLen = 0;
9430596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              while (nextSeparator < keyValueTail) {
9440596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                if (!UPRV_ISALPHANUM(*nextSeparator) && !UPRV_OK_VALUE_PUNCTUATION(*nextSeparator)) {
9450596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  *status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed key value */
9460596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  return 0;
9470596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                }
9480596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                if (keyValueLen < bufferCapacity) {
9490596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  /* Should we lowercase value to return here? Tests expect as-is. */
9500596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  buffer[keyValueLen++] = *nextSeparator++;
9510596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                } else { /* keep advancing so we return correct length in case of overflow */
9520596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  keyValueLen++;
9530596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                  nextSeparator++;
9540596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                }
955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              }
9560596faeddefbf198de137d5e893708495ab1584cFredrik Roubert              result = u_terminateChars(buffer, bufferCapacity, keyValueLen, status);
957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              return result;
958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru          }
959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru      }
960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return 0;
962b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_setKeywordValue(const char* keywordName,
966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     const char* keywordValue,
967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     char* buffer, int32_t bufferCapacity,
968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                     UErrorCode* status)
969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* TODO: sorting. removal. */
971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t keywordNameLen;
972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t keywordValueLen;
973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t bufLen;
974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t needLen = 0;
975b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char keywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
9760596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    char keywordValueBuffer[ULOC_KEYWORDS_CAPACITY+1];
977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char localeKeywordNameBuffer[ULOC_KEYWORD_BUFFER_LEN];
978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t rc;
979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* nextSeparator = NULL;
980b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* nextEqualsign = NULL;
981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* startSearchHere = NULL;
982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* keywordStart = NULL;
9830596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    CharString updatedKeysAndValues;
9840596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    int32_t updatedKeysAndValuesLen;
9850596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    UBool handledInputKeyAndValue = FALSE;
9860596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    char keyValuePrefix = '@';
9870596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
98864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if(U_FAILURE(*status)) {
98964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        return -1;
990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
9910596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (keywordName == NULL || keywordName[0] == 0 || bufferCapacity <= 1) {
992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
9950596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    bufLen = (int32_t)uprv_strlen(buffer);
996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(bufferCapacity<bufLen) {
997b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* The capacity is less than the length?! Is this NULL terminated? */
998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_ILLEGAL_ARGUMENT_ERROR;
999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1001b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    keywordNameLen = locale_canonKeywordName(keywordNameBuffer, keywordName, status);
1002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_FAILURE(*status)) {
1003b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
10050596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
10060596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    keywordValueLen = 0;
10070596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if(keywordValue) {
10080596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        while (*keywordValue != 0) {
10090596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (!UPRV_ISALPHANUM(*keywordValue) && !UPRV_OK_VALUE_PUNCTUATION(*keywordValue)) {
10100596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                *status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed key value */
10110596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                return 0;
10120596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
10130596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (keywordValueLen < ULOC_KEYWORDS_CAPACITY) {
10140596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                /* Should we force lowercase in value to set? */
10150596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                keywordValueBuffer[keywordValueLen++] = *keywordValue++;
10160596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            } else {
10170596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                /* keywordValue too long for internal buffer */
10180596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                *status = U_INTERNAL_PROGRAM_ERROR;
10190596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                return 0;
10200596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
10210596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
10220596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
10230596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    keywordValueBuffer[keywordValueLen] = 0; /* terminate */
10240596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
1025b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    startSearchHere = (char*)locale_getKeywordsStart(buffer);
1026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(startSearchHere == NULL || (startSearchHere[1]==0)) {
10270596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        if(keywordValueLen == 0) { /* no keywords = nothing to remove */
102864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            return bufLen;
1029b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        needLen = bufLen+1+keywordNameLen+1+keywordValueLen;
103264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(startSearchHere) { /* had a single @ */
1033b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            needLen--; /* already had the @ */
1034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* startSearchHere points at the @ */
1035b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
1036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            startSearchHere=buffer+bufLen;
1037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(needLen >= bufferCapacity) {
1039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            *status = U_BUFFER_OVERFLOW_ERROR;
1040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return needLen; /* no change */
1041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
10420596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        *startSearchHere++ = '@';
1043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_strcpy(startSearchHere, keywordNameBuffer);
1044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        startSearchHere += keywordNameLen;
10450596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        *startSearchHere++ = '=';
10460596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        uprv_strcpy(startSearchHere, keywordValueBuffer);
1047b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return needLen;
1048b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } /* end shortcut - no @ */
104964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1050b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    keywordStart = startSearchHere;
1051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* search for keyword */
1052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(keywordStart) {
10530596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        const char* keyValueTail;
10540596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        int32_t keyValueLen;
10550596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
10560596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        keywordStart++; /* skip @ or ; */
10570596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        nextEqualsign = uprv_strchr(keywordStart, '=');
10580596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        if (!nextEqualsign) {
10590596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            *status = U_ILLEGAL_ARGUMENT_ERROR; /* key must have =value */
10600596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            return 0;
10610596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
10620596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* strip leading & trailing spaces (TC decided to tolerate these) */
1063b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(*keywordStart == ' ') {
1064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            keywordStart++;
1065b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
10660596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        keyValueTail = nextEqualsign;
10670596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        while (keyValueTail > keywordStart && *(keyValueTail-1) == ' ') {
10680596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            keyValueTail--;
1069b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
10700596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* now keyValueTail points to first char after the keyName */
10710596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* copy & normalize keyName from locale */
10720596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        if (keywordStart == keyValueTail) {
10730596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            *status = U_ILLEGAL_ARGUMENT_ERROR; /* empty keyword name in passed-in locale */
1074b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return 0;
1075b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
10760596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        keyValueLen = 0;
10770596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        while (keywordStart < keyValueTail) {
10780596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (!UPRV_ISALPHANUM(*keywordStart)) {
10790596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                *status = U_ILLEGAL_ARGUMENT_ERROR; /* malformed keyword name */
10800596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                return 0;
10810596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
10820596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (keyValueLen < ULOC_KEYWORD_BUFFER_LEN - 1) {
10830596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                localeKeywordNameBuffer[keyValueLen++] = uprv_tolower(*keywordStart++);
10840596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            } else {
10850596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                /* keyword name too long for internal buffer */
10860596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                *status = U_INTERNAL_PROGRAM_ERROR;
10870596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                return 0;
10880596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            }
1089b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
10900596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        localeKeywordNameBuffer[keyValueLen] = 0; /* terminate */
1091b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        nextSeparator = uprv_strchr(nextEqualsign, ';');
10930596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
10940596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* start processing the value part */
10950596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        nextEqualsign++; /* skip '=' */
10960596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* First strip leading & trailing spaces (TC decided to tolerate these) */
10970596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        while(*nextEqualsign == ' ') {
10980596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            nextEqualsign++;
10990596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
11000596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        keyValueTail = (nextSeparator)? nextSeparator: nextEqualsign + uprv_strlen(nextEqualsign);
11010596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        while(keyValueTail > nextEqualsign && *(keyValueTail-1) == ' ') {
11020596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            keyValueTail--;
11030596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
11040596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        if (nextEqualsign == keyValueTail) {
11050596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            *status = U_ILLEGAL_ARGUMENT_ERROR; /* empty key value in passed-in locale */
11060596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            return 0;
11070596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
11080596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
1109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rc = uprv_strcmp(keywordNameBuffer, localeKeywordNameBuffer);
1110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(rc == 0) {
11110596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            /* Current entry matches the input keyword. Update the entry */
11120596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if(keywordValueLen > 0) { /* updating a value */
11130596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keyValuePrefix, *status);
11140596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                keyValuePrefix = ';'; /* for any subsequent key-value pair */
11150596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keywordNameBuffer, keywordNameLen, *status);
11160596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append('=', *status);
11170596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
11180596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            } /* else removing this entry, don't emit anything */
11190596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            handledInputKeyAndValue = TRUE;
11200596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        } else {
11210596faeddefbf198de137d5e893708495ab1584cFredrik Roubert           /* input keyword sorts earlier than current entry, add before current entry */
11220596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            if (rc < 0 && keywordValueLen > 0 && !handledInputKeyAndValue) {
11230596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                /* insert new entry at this location */
11240596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keyValuePrefix, *status);
11250596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                keyValuePrefix = ';'; /* for any subsequent key-value pair */
11260596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keywordNameBuffer, keywordNameLen, *status);
11270596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append('=', *status);
11280596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
11290596faeddefbf198de137d5e893708495ab1584cFredrik Roubert                handledInputKeyAndValue = TRUE;
1130b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
11310596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            /* copy the current entry */
11320596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(keyValuePrefix, *status);
11330596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            keyValuePrefix = ';'; /* for any subsequent key-value pair */
11340596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(localeKeywordNameBuffer, keyValueLen, *status);
11350596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append('=', *status);
11360596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(nextEqualsign, keyValueTail-nextEqualsign, *status);
11370596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        }
11380596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        if (!nextSeparator && keywordValueLen > 0 && !handledInputKeyAndValue) {
11390596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            /* append new entry at the end, it sorts later than existing entries */
11400596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(keyValuePrefix, *status);
11410596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            /* skip keyValuePrefix update, no subsequent key-value pair */
11420596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(keywordNameBuffer, keywordNameLen, *status);
11430596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append('=', *status);
11440596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            updatedKeysAndValues.append(keywordValueBuffer, keywordValueLen, *status);
11450596faeddefbf198de137d5e893708495ab1584cFredrik Roubert            handledInputKeyAndValue = TRUE;
1146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        keywordStart = nextSeparator;
1148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } /* end loop searching */
114964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
11500596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    /* Any error from updatedKeysAndValues.append above would be internal and not due to
11510596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * problems with the passed-in locale. So if we did encounter problems with the
11520596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * passed-in locale above, those errors took precedence and overrode any error
11530596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * status from updatedKeysAndValues.append, and also caused a return of 0. If there
11540596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * are errors here they are from updatedKeysAndValues.append; they do cause an
11550596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * error return but the passed-in locale is unmodified and the original bufLen is
11560596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     * returned.
11570596faeddefbf198de137d5e893708495ab1584cFredrik Roubert     */
11580596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (!handledInputKeyAndValue || U_FAILURE(*status)) {
11590596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        /* if input key/value specified removal of a keyword not present in locale, or
11600596faeddefbf198de137d5e893708495ab1584cFredrik Roubert         * there was an error in CharString.append, leave original locale alone. */
11610596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        return bufLen;
11620596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
11630596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
11640596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    updatedKeysAndValuesLen = updatedKeysAndValues.length();
11650596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    /* needLen = length of the part before '@' + length of updated key-value part including '@' */
11660596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    needLen = (int32_t)(startSearchHere - buffer) + updatedKeysAndValuesLen;
1167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(needLen >= bufferCapacity) {
1168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_BUFFER_OVERFLOW_ERROR;
1169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return needLen; /* no change */
1170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
11710596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (updatedKeysAndValuesLen > 0) {
11720596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        uprv_strncpy(startSearchHere, updatedKeysAndValues.data(), updatedKeysAndValuesLen);
1173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    buffer[needLen]=0;
1175b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return needLen;
1176b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1177b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1178b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### ID parsing implementation **************************************************/
1179b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1180b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define _isPrefixLetter(a) ((a=='x')||(a=='X')||(a=='i')||(a=='I'))
1181b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1182b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*returns TRUE if one of the special prefixes is here (s=string)
1183b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru  'x-' or 'i-' */
1184b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define _isIDPrefix(s) (_isPrefixLetter(s[0])&&_isIDSeparator(s[1]))
1185b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1186b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* Dot terminates it because of POSIX form  where dot precedes the codepage
1187b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * except for variant
1188b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define _isTerminator(a)  ((a==0)||(a=='.')||(a=='@'))
1190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic char* _strnchr(const char* str, int32_t len, char c) {
1192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    U_ASSERT(str != 0 && len >= 0);
1193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while (len-- != 0) {
1194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        char d = *str;
1195b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (d == c) {
1196b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return (char*) str;
1197b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (d == 0) {
1198b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            break;
1199b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1200b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ++str;
1201b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1202b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return NULL;
1203b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1204b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1205b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1206b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Lookup 'key' in the array 'list'.  The array 'list' should contain
1207b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * a NULL entry, followed by more entries, and a second NULL entry.
1208b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
1209b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * The 'list' param should be LANGUAGES, LANGUAGES_3, COUNTRIES, or
1210b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * COUNTRIES_3.
1211b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1212b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int16_t _findIndex(const char* const* list, const char* key)
1213b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1214b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* const* anchor = list;
1215b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t pass = 0;
1216b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1217b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Make two passes through two NULL-terminated arrays at 'list' */
1218b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while (pass++ < 2) {
1219b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while (*list) {
1220b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (uprv_strcmp(key, *list) == 0) {
1221b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return (int16_t)(list - anchor);
1222b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1223b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            list++;
1224b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1225b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ++list;     /* skip final NULL *CWB*/
1226b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1227b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return -1;
1228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* count the length of src while copying it to dest; return strlen(src) */
1231103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusstatic inline int32_t
1232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_copyCount(char *dest, int32_t destCapacity, const char *src) {
1233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *anchor;
1234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char c;
1235b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    anchor=src;
1237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(;;) {
1238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if((c=*src)==0) {
1239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return (int32_t)(src-anchor);
1240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(destCapacity<=0) {
1242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return (int32_t)((src-anchor)+uprv_strlen(src));
1243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ++src;
1245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *dest++=c;
1246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        --destCapacity;
1247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1248b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
125064339d36f8bd4db5025fe2988eda22b491a9219cFredrik RoubertU_CFUNC const char*
1251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getCurrentCountryID(const char* oldID){
1252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset = _findIndex(DEPRECATED_COUNTRIES, oldID);
1253b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (offset >= 0) {
1254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return REPLACEMENT_COUNTRIES[offset];
1255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return oldID;
1257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
125864339d36f8bd4db5025fe2988eda22b491a9219cFredrik RoubertU_CFUNC const char*
1259b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getCurrentLanguageID(const char* oldID){
1260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset = _findIndex(DEPRECATED_LANGUAGES, oldID);
1261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (offset >= 0) {
1262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return REPLACEMENT_LANGUAGES[offset];
1263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
126464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    return oldID;
1265b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
1267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * the internal functions _getLanguage(), _getCountry(), _getVariant()
1268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * avoid duplicating code to handle the earlier locale ID pieces
1269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * in the functions for the later ones by
1270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * setting the *pEnd pointer to where they stopped parsing
1271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
1272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * TODO try to use this in Locale
1273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
127450294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_CFUNC int32_t
127550294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoulocimp_getLanguage(const char *localeID,
127650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    char *language, int32_t languageCapacity,
127750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    const char **pEnd) {
1278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
1279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset;
1280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char lang[4]={ 0, 0, 0, 0 }; /* temporary buffer to hold language code for searching */
1281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* if it starts with i- or x- then copy that prefix */
1283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(_isIDPrefix(localeID)) {
1284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(i<languageCapacity) {
1285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            language[i]=(char)uprv_tolower(*localeID);
1286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(i<languageCapacity) {
1288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            language[i+1]='-';
1289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        i+=2;
1291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID+=2;
1292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
129364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* copy the language as far as possible and count its length */
1295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(!_isTerminator(*localeID) && !_isIDSeparator(*localeID)) {
1296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(i<languageCapacity) {
1297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            language[i]=(char)uprv_tolower(*localeID);
1298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(i<3) {
1300103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            U_ASSERT(i>=0);
1301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            lang[i]=(char)uprv_tolower(*localeID);
1302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        i++;
1304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID++;
1305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(i==3) {
1308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* convert 3 character code to 2 character code if possible *CWB*/
1309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        offset=_findIndex(LANGUAGES_3, lang);
1310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(offset>=0) {
1311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            i=_copyCount(language, languageCapacity, LANGUAGES[offset]);
1312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(pEnd!=NULL) {
1316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *pEnd=localeID;
1317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return i;
1319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
132150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_CFUNC int32_t
132250294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoulocimp_getScript(const char *localeID,
132350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                  char *script, int32_t scriptCapacity,
132450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                  const char **pEnd)
1325b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t idLen = 0;
1327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (pEnd != NULL) {
1329b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *pEnd = localeID;
1330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* copy the second item as far as possible and count its length */
1333103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius    while(!_isTerminator(localeID[idLen]) && !_isIDSeparator(localeID[idLen])
1334103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            && uprv_isASCIILetter(localeID[idLen])) {
1335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        idLen++;
1336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* If it's exactly 4 characters long, then it's a script and not a country. */
1339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (idLen == 4) {
1340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        int32_t i;
1341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (pEnd != NULL) {
1342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            *pEnd = localeID+idLen;
1343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(idLen > scriptCapacity) {
1345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            idLen = scriptCapacity;
1346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (idLen >= 1) {
1348b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            script[0]=(char)uprv_toupper(*(localeID++));
1349b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (i = 1; i < idLen; i++) {
1351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            script[i]=(char)uprv_tolower(*(localeID++));
1352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    else {
1355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        idLen = 0;
1356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1357b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return idLen;
1358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
136050294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoU_CFUNC int32_t
136150294ead5e5d23f5bbfed76e00e6b510bd41eee1clairehoulocimp_getCountry(const char *localeID,
136250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                   char *country, int32_t countryCapacity,
136350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                   const char **pEnd)
1364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
136550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    int32_t idLen=0;
1366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char cnty[ULOC_COUNTRY_CAPACITY]={ 0, 0, 0, 0 };
1367b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t offset;
1368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* copy the country as far as possible and count its length */
137050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    while(!_isTerminator(localeID[idLen]) && !_isIDSeparator(localeID[idLen])) {
137150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if(idLen<(ULOC_COUNTRY_CAPACITY-1)) {   /*CWB*/
137250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            cnty[idLen]=(char)uprv_toupper(localeID[idLen]);
1373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
137450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        idLen++;
1375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
137750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    /* the country should be either length 2 or 3 */
137850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (idLen == 2 || idLen == 3) {
137950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        UBool gotCountry = FALSE;
138050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        /* convert 3 character code to 2 character code if possible *CWB*/
138150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if(idLen==3) {
138250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            offset=_findIndex(COUNTRIES_3, cnty);
138350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if(offset>=0) {
138450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                idLen=_copyCount(country, countryCapacity, COUNTRIES[offset]);
138550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                gotCountry = TRUE;
138650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
138750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        }
138850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        if (!gotCountry) {
138950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            int32_t i = 0;
139050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            for (i = 0; i < idLen; i++) {
139150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                if (i < countryCapacity) {
139250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    country[i]=(char)uprv_toupper(localeID[i]);
139350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                }
139450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
1395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
139650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        localeID+=idLen;
139750294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    } else {
139850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        idLen = 0;
1399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(pEnd!=NULL) {
1402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *pEnd=localeID;
1403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
140450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
140550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    return idLen;
1406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1408b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param needSeparator if true, then add leading '_' if any variants
1410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * are added to 'variant'
1411b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t
1413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_getVariantEx(const char *localeID,
1414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              char prev,
1415b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              char *variant, int32_t variantCapacity,
1416b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              UBool needSeparator) {
1417b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
1418b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1419b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* get one or more variant tags and separate them with '_' */
1420b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(_isIDSeparator(prev)) {
1421b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* get a variant string after a '-' or '_' */
1422b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(!_isTerminator(*localeID)) {
1423b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (needSeparator) {
1424b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (i<variantCapacity) {
1425b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    variant[i] = '_';
1426b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1427b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++i;
1428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                needSeparator = FALSE;
1429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(i<variantCapacity) {
1431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                variant[i]=(char)uprv_toupper(*localeID);
1432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(variant[i]=='-') {
1433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    variant[i]='_';
1434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            i++;
1437b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            localeID++;
1438b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1439b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1440b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1441b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* if there is no variant tag after a '-' or '_' then look for '@' */
1442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(i==0) {
1443b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(prev=='@') {
1444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* keep localeID */
1445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if((localeID=locale_getKeywordsStart(localeID))!=NULL) {
1446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++localeID; /* point after the '@' */
1447b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
1448b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return 0;
1449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(!_isTerminator(*localeID)) {
1451b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (needSeparator) {
1452b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (i<variantCapacity) {
1453b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    variant[i] = '_';
1454b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1455b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++i;
1456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                needSeparator = FALSE;
1457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(i<variantCapacity) {
1459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                variant[i]=(char)uprv_toupper(*localeID);
1460b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(variant[i]=='-' || variant[i]==',') {
1461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    variant[i]='_';
1462b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1463b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            i++;
1465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            localeID++;
1466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
146864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1469b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return i;
1470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t
1473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_getVariant(const char *localeID,
1474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char prev,
1475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char *variant, int32_t variantCapacity) {
1476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return _getVariantEx(localeID, prev, variant, variantCapacity, FALSE);
1477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Delete ALL instances of a variant from the given list of one or
1481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * more variants.  Example: "FOO_EURO_BAR_EURO" => "FOO_BAR".
1482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param variants the source string of one or more variants,
1483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * separated by '_'.  This will be MODIFIED IN PLACE.  Not zero
1484b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * terminated; if it is, trailing zero will NOT be maintained.
1485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param variantsLen length of variants
1486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param toDelete variant to delete, without separators, e.g.  "EURO"
1487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * or "PREEURO"; not zero terminated
1488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @param toDeleteLen length of toDelete
1489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * @return number of characters deleted from variants
1490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t
1492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_deleteVariant(char* variants, int32_t variantsLen,
1493c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru               const char* toDelete, int32_t toDeleteLen)
1494c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru{
1495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t delta = 0; /* number of chars deleted */
1496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for (;;) {
1497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool flag = FALSE;
1498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (variantsLen < toDeleteLen) {
1499b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return delta;
1500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (uprv_strncmp(variants, toDelete, toDeleteLen) == 0 &&
1502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            (variantsLen == toDeleteLen ||
1503c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru             (flag=(variants[toDeleteLen] == '_'))))
1504c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        {
1505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t d = toDeleteLen + (flag?1:0);
1506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            variantsLen -= d;
1507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            delta += d;
1508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (variantsLen > 0) {
1509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                uprv_memmove(variants, variants+d, variantsLen);
1510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
1512b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char* p = _strnchr(variants, variantsLen, '_');
1513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (p == NULL) {
1514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                return delta;
1515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++p;
1517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            variantsLen -= (int32_t)(p - variants);
1518b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            variants = p;
1519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1520b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* Keyword enumeration */
1524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querutypedef struct UKeywordsContext {
1526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* keywords;
1527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* current;
1528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} UKeywordsContext;
1529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
153064339d36f8bd4db5025fe2988eda22b491a9219cFredrik RoubertU_CDECL_BEGIN
153164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic void U_CALLCONV
1533b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_kw_closeKeywords(UEnumeration *enumerator) {
1534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(((UKeywordsContext *)enumerator->context)->keywords);
1535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(enumerator->context);
1536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(enumerator);
1537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1539b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t U_CALLCONV
1540103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusuloc_kw_countKeywords(UEnumeration *en, UErrorCode * /*status*/) {
1541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *kw = ((UKeywordsContext *)en->context)->keywords;
1542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t result = 0;
1543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    while(*kw) {
1544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result++;
1545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        kw += uprv_strlen(kw)+1;
1546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
1548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
155064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic const char * U_CALLCONV
1551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_kw_nextKeyword(UEnumeration* en,
1552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t* resultLength,
1553103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    UErrorCode* /*status*/) {
1554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* result = ((UKeywordsContext *)en->context)->current;
1555b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t len = 0;
1556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(*result) {
1557b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        len = (int32_t)uprv_strlen(((UKeywordsContext *)en->context)->current);
1558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ((UKeywordsContext *)en->context)->current += len+1;
1559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        result = NULL;
1561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (resultLength) {
1563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *resultLength = len;
1564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return result;
1566b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
156864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertstatic void U_CALLCONV
156964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_kw_resetKeywords(UEnumeration* en,
1570103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                      UErrorCode* /*status*/) {
1571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    ((UKeywordsContext *)en->context)->current = ((UKeywordsContext *)en->context)->keywords;
1572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
157464339d36f8bd4db5025fe2988eda22b491a9219cFredrik RoubertU_CDECL_END
157564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
157664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1577b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const UEnumeration gKeywordsEnum = {
1578b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    NULL,
1579b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    NULL,
1580b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_kw_closeKeywords,
1581b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_kw_countKeywords,
1582b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uenum_unextDefault,
1583b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_kw_nextKeyword,
1584b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_kw_resetKeywords
1585b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru};
1586b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1587b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
1588b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_openKeywordList(const char *keywordList, int32_t keywordListSize, UErrorCode* status)
1589b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1590c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UKeywordsContext *myContext = NULL;
1591c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    UEnumeration *result = NULL;
1592b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1593c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if(U_FAILURE(*status)) {
1594c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return NULL;
1595c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1596c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    result = (UEnumeration *)uprv_malloc(sizeof(UEnumeration));
1597c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    /* Null pointer test */
1598c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (result == NULL) {
1599c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
1600c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return NULL;
1601c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1602c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    uprv_memcpy(result, &gKeywordsEnum, sizeof(UEnumeration));
160354dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    myContext = static_cast<UKeywordsContext *>(uprv_malloc(sizeof(UKeywordsContext)));
1604c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    if (myContext == NULL) {
1605c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
1606c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        uprv_free(result);
1607c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return NULL;
1608c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
1609c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    myContext->keywords = (char *)uprv_malloc(keywordListSize+1);
1610c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    uprv_memcpy(myContext->keywords, keywordList, keywordListSize);
1611c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    myContext->keywords[keywordListSize] = 0;
1612c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    myContext->current = myContext->keywords;
1613c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    result->context = myContext;
1614c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    return result;
1615b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1616b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1617b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI UEnumeration* U_EXPORT2
1618b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_openKeywords(const char* localeID,
161964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                        UErrorCode* status)
1620b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1621b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
1622b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char keywords[256];
1623b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t keywordsCapacity = 256;
162427f654740f2a26ad62a5c155af9199af9e69b889claireho    char tempBuffer[ULOC_FULLNAME_CAPACITY];
162527f654740f2a26ad62a5c155af9199af9e69b889claireho    const char* tmpLocaleID;
162627f654740f2a26ad62a5c155af9199af9e69b889claireho
1627b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(status==NULL || U_FAILURE(*status)) {
1628b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1629b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
163064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
163127f654740f2a26ad62a5c155af9199af9e69b889claireho    if (_hasBCP47Extension(localeID)) {
163227f654740f2a26ad62a5c155af9199af9e69b889claireho        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), status);
163327f654740f2a26ad62a5c155af9199af9e69b889claireho    } else {
163427f654740f2a26ad62a5c155af9199af9e69b889claireho        if (localeID==NULL) {
163527f654740f2a26ad62a5c155af9199af9e69b889claireho           localeID=uloc_getDefault();
163627f654740f2a26ad62a5c155af9199af9e69b889claireho        }
163727f654740f2a26ad62a5c155af9199af9e69b889claireho        tmpLocaleID=localeID;
1638b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1639b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1640b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Skip the language */
164127f654740f2a26ad62a5c155af9199af9e69b889claireho    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
164227f654740f2a26ad62a5c155af9199af9e69b889claireho    if(_isIDSeparator(*tmpLocaleID)) {
1643b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *scriptID;
1644b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Skip the script if available */
164527f654740f2a26ad62a5c155af9199af9e69b889claireho        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
164627f654740f2a26ad62a5c155af9199af9e69b889claireho        if(scriptID != tmpLocaleID+1) {
1647b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Found optional script */
164827f654740f2a26ad62a5c155af9199af9e69b889claireho            tmpLocaleID = scriptID;
1649b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1650b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Skip the Country */
165127f654740f2a26ad62a5c155af9199af9e69b889claireho        if (_isIDSeparator(*tmpLocaleID)) {
165227f654740f2a26ad62a5c155af9199af9e69b889claireho            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &tmpLocaleID);
165327f654740f2a26ad62a5c155af9199af9e69b889claireho            if(_isIDSeparator(*tmpLocaleID)) {
165427f654740f2a26ad62a5c155af9199af9e69b889claireho                _getVariant(tmpLocaleID+1, *tmpLocaleID, NULL, 0);
1655b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1656b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1657b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1658b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1659b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* keywords are located after '@' */
166027f654740f2a26ad62a5c155af9199af9e69b889claireho    if((tmpLocaleID = locale_getKeywordsStart(tmpLocaleID)) != NULL) {
166127f654740f2a26ad62a5c155af9199af9e69b889claireho        i=locale_getKeywords(tmpLocaleID+1, '@', keywords, keywordsCapacity, NULL, 0, NULL, FALSE, status);
1662b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1663b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1664b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(i) {
1665b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return uloc_openKeywordList(keywords, i, status);
1666b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1667b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return NULL;
1668b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1669b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1670b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1671b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* bit-flags for 'options' parameter of _canonicalize */
1673b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define _ULOC_STRIP_KEYWORDS 0x2
1674b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define _ULOC_CANONICALIZE   0x1
1675b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1676b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#define OPTION_SET(options, mask) ((options & mask) != 0)
1677b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1678b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic const char i_default[] = {'i', '-', 'd', 'e', 'f', 'a', 'u', 'l', 't'};
16798de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert#define I_DEFAULT_LENGTH UPRV_LENGTHOF(i_default)
1680b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1681b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
1682b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Canonicalize the given localeID, to level 1 or to level 2,
1683b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * depending on the options.  To specify level 1, pass in options=0.
1684b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * To specify level 2, pass in options=_ULOC_CANONICALIZE.
1685b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru *
1686b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * This is the code underlying uloc_getName and uloc_canonicalize.
1687b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
1688b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t
1689b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_canonicalize(const char* localeID,
1690b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              char* result,
1691b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              int32_t resultCapacity,
1692b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              uint32_t options,
1693b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru              UErrorCode* err) {
1694b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t j, len, fieldCount=0, scriptSize=0, variantSize=0, nameCapacity;
1695b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char localeBuffer[ULOC_FULLNAME_CAPACITY];
169627f654740f2a26ad62a5c155af9199af9e69b889claireho    char tempBuffer[ULOC_FULLNAME_CAPACITY];
1697b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* origLocaleID;
169827f654740f2a26ad62a5c155af9199af9e69b889claireho    const char* tmpLocaleID;
1699b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* keywordAssign = NULL;
1700b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* separatorIndicator = NULL;
1701b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* addKeyword = NULL;
1702b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char* addValue = NULL;
1703b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* name;
1704b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char* variant = NULL; /* pointer into name, or NULL */
1705b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1706b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(*err)) {
1707b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1708b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
170964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
171027f654740f2a26ad62a5c155af9199af9e69b889claireho    if (_hasBCP47Extension(localeID)) {
171127f654740f2a26ad62a5c155af9199af9e69b889claireho        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
171227f654740f2a26ad62a5c155af9199af9e69b889claireho    } else {
171327f654740f2a26ad62a5c155af9199af9e69b889claireho        if (localeID==NULL) {
171427f654740f2a26ad62a5c155af9199af9e69b889claireho           localeID=uloc_getDefault();
171527f654740f2a26ad62a5c155af9199af9e69b889claireho        }
171627f654740f2a26ad62a5c155af9199af9e69b889claireho        tmpLocaleID=localeID;
1717b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
171827f654740f2a26ad62a5c155af9199af9e69b889claireho
171927f654740f2a26ad62a5c155af9199af9e69b889claireho    origLocaleID=tmpLocaleID;
1720b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1721b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* if we are doing a full canonicalization, then put results in
1722b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru       localeBuffer, if necessary; otherwise send them to result. */
172350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    if (/*OPTION_SET(options, _ULOC_CANONICALIZE) &&*/
1724103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        (result == NULL || resultCapacity < (int32_t)sizeof(localeBuffer))) {
1725b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        name = localeBuffer;
1726103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        nameCapacity = (int32_t)sizeof(localeBuffer);
1727b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1728b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        name = result;
1729b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        nameCapacity = resultCapacity;
1730b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1731b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1732b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* get all pieces, one after another, and separate with '_' */
173327f654740f2a26ad62a5c155af9199af9e69b889claireho    len=ulocimp_getLanguage(tmpLocaleID, name, nameCapacity, &tmpLocaleID);
1734b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1735b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(len == I_DEFAULT_LENGTH && uprv_strncmp(origLocaleID, i_default, len) == 0) {
1736b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *d = uloc_getDefault();
173764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
173850294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        len = (int32_t)uprv_strlen(d);
1739b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1740b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if (name != NULL) {
1741b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            uprv_strncpy(name, d, len);
1742b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
174327f654740f2a26ad62a5c155af9199af9e69b889claireho    } else if(_isIDSeparator(*tmpLocaleID)) {
1744b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *scriptID;
1745b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1746b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ++fieldCount;
1747b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(len<nameCapacity) {
1748b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            name[len]='_';
1749b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1750b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        ++len;
1751b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1752103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius        scriptSize=ulocimp_getScript(tmpLocaleID+1,
1753103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            (len<nameCapacity ? name+len : NULL), nameCapacity-len, &scriptID);
1754b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(scriptSize > 0) {
1755b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Found optional script */
175627f654740f2a26ad62a5c155af9199af9e69b889claireho            tmpLocaleID = scriptID;
1757b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++fieldCount;
1758b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len+=scriptSize;
175927f654740f2a26ad62a5c155af9199af9e69b889claireho            if (_isIDSeparator(*tmpLocaleID)) {
1760b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                /* If there is something else, then we add the _ */
1761b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(len<nameCapacity) {
1762b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    name[len]='_';
1763b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1764b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++len;
1765b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1766b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1767b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
176827f654740f2a26ad62a5c155af9199af9e69b889claireho        if (_isIDSeparator(*tmpLocaleID)) {
176950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            const char *cntryID;
1770103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            int32_t cntrySize = ulocimp_getCountry(tmpLocaleID+1,
1771103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                (len<nameCapacity ? name+len : NULL), nameCapacity-len, &cntryID);
177250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            if (cntrySize > 0) {
177350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* Found optional country */
177427f654740f2a26ad62a5c155af9199af9e69b889claireho                tmpLocaleID = cntryID;
177550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                len+=cntrySize;
177650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
177727f654740f2a26ad62a5c155af9199af9e69b889claireho            if(_isIDSeparator(*tmpLocaleID)) {
177854dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                /* If there is something else, then we add the _  if we found country before. */
177954dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius                if (cntrySize >= 0 && ! _isIDSeparator(*(tmpLocaleID+1)) ) {
178050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ++fieldCount;
178150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    if(len<nameCapacity) {
178250294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                        name[len]='_';
178350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    }
178450294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                    ++len;
1785b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
178650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho
1787103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                variantSize = _getVariant(tmpLocaleID+1, *tmpLocaleID,
1788103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    (len<nameCapacity ? name+len : NULL), nameCapacity-len);
1789b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (variantSize > 0) {
1790103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                    variant = len<nameCapacity ? name+len : NULL;
1791b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    len += variantSize;
179227f654740f2a26ad62a5c155af9199af9e69b889claireho                    tmpLocaleID += variantSize + 1; /* skip '_' and variant */
1793b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1794b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1795b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1796b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1797b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1798b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Copy POSIX-style charset specifier, if any [mr.utf8] */
179927f654740f2a26ad62a5c155af9199af9e69b889claireho    if (!OPTION_SET(options, _ULOC_CANONICALIZE) && *tmpLocaleID == '.') {
1800b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        UBool done = FALSE;
1801b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        do {
180227f654740f2a26ad62a5c155af9199af9e69b889claireho            char c = *tmpLocaleID;
1803b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            switch (c) {
1804b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            case 0:
1805b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            case '@':
1806b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                done = TRUE;
1807b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
1808b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            default:
1809b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (len<nameCapacity) {
1810b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    name[len] = c;
1811b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1812b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                ++len;
181327f654740f2a26ad62a5c155af9199af9e69b889claireho                ++tmpLocaleID;
1814b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
1815b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1816b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } while (!done);
1817b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1818b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1819b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Scan ahead to next '@' and determine if it is followed by '=' and/or ';'
182027f654740f2a26ad62a5c155af9199af9e69b889claireho       After this, tmpLocaleID either points to '@' or is NULL */
182127f654740f2a26ad62a5c155af9199af9e69b889claireho    if ((tmpLocaleID=locale_getKeywordsStart(tmpLocaleID))!=NULL) {
182227f654740f2a26ad62a5c155af9199af9e69b889claireho        keywordAssign = uprv_strchr(tmpLocaleID, '=');
182327f654740f2a26ad62a5c155af9199af9e69b889claireho        separatorIndicator = uprv_strchr(tmpLocaleID, ';');
1824b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1825b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1826b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Copy POSIX-style variant, if any [mr@FOO] */
1827b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!OPTION_SET(options, _ULOC_CANONICALIZE) &&
182827f654740f2a26ad62a5c155af9199af9e69b889claireho        tmpLocaleID != NULL && keywordAssign == NULL) {
1829b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for (;;) {
183027f654740f2a26ad62a5c155af9199af9e69b889claireho            char c = *tmpLocaleID;
1831b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (c == 0) {
1832b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
1833b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1834b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (len<nameCapacity) {
1835b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                name[len] = c;
1836b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1837b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++len;
183827f654740f2a26ad62a5c155af9199af9e69b889claireho            ++tmpLocaleID;
1839b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1840b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1841b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1842b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (OPTION_SET(options, _ULOC_CANONICALIZE)) {
1843b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Handle @FOO variant if @ is present and not followed by = */
184427f654740f2a26ad62a5c155af9199af9e69b889claireho        if (tmpLocaleID!=NULL && keywordAssign==NULL) {
1845b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t posixVariantSize;
1846b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Add missing '_' if needed */
1847b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (fieldCount < 2 || (fieldCount < 3 && scriptSize > 0)) {
1848b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                do {
1849b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if(len<nameCapacity) {
1850b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        name[len]='_';
1851b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
1852b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    ++len;
1853b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    ++fieldCount;
1854b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } while(fieldCount<2);
1855b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
185627f654740f2a26ad62a5c155af9199af9e69b889claireho            posixVariantSize = _getVariantEx(tmpLocaleID+1, '@', name+len, nameCapacity-len,
1857b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                                             (UBool)(variantSize > 0));
1858b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (posixVariantSize > 0) {
1859b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if (variant == NULL) {
1860b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    variant = name+len;
1861b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1862b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                len += posixVariantSize;
1863b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                variantSize += posixVariantSize;
1864b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1865b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1866b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1867c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        /* Handle generic variants first */
1868c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        if (variant) {
18698de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            for (j=0; j<UPRV_LENGTHOF(VARIANT_MAP); j++) {
1870c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                const char* variantToCompare = VARIANT_MAP[j].variant;
1871c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                int32_t n = (int32_t)uprv_strlen(variantToCompare);
1872c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                int32_t variantLen = _deleteVariant(variant, uprv_min(variantSize, (nameCapacity-len)), variantToCompare, n);
1873c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                len -= variantLen;
1874c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                if (variantLen > 0) {
1875ab19ce4e2e94e2c9e847a6ae07773a48e4d40713claireho                    if (len > 0 && name[len-1] == '_') { /* delete trailing '_' */
1876c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                        --len;
1877c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    }
1878c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    addKeyword = VARIANT_MAP[j].keyword;
1879c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    addValue = VARIANT_MAP[j].value;
1880c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    break;
1881c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
1882c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
1883ab19ce4e2e94e2c9e847a6ae07773a48e4d40713claireho            if (len > 0 && len <= nameCapacity && name[len-1] == '_') { /* delete trailing '_' */
1884c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                --len;
1885c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru            }
1886b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1887b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1888b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Look up the ID in the canonicalization map */
18898de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert        for (j=0; j<UPRV_LENGTHOF(CANONICALIZE_MAP); j++) {
1890b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            const char* id = CANONICALIZE_MAP[j].id;
1891b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t n = (int32_t)uprv_strlen(id);
1892b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if (len == n && uprv_strncmp(name, id, n) == 0) {
189327f654740f2a26ad62a5c155af9199af9e69b889claireho                if (n == 0 && tmpLocaleID != NULL) {
1894b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    break; /* Don't remap "" if keywords present */
1895b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
1896b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                len = _copyCount(name, nameCapacity, CANONICALIZE_MAP[j].canonicalID);
1897c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                if (CANONICALIZE_MAP[j].keyword) {
1898c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    addKeyword = CANONICALIZE_MAP[j].keyword;
1899c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                    addValue = CANONICALIZE_MAP[j].value;
1900c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru                }
1901b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                break;
1902b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1903b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1904b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1905b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1906b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!OPTION_SET(options, _ULOC_STRIP_KEYWORDS)) {
190727f654740f2a26ad62a5c155af9199af9e69b889claireho        if (tmpLocaleID!=NULL && keywordAssign!=NULL &&
1908b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            (!separatorIndicator || separatorIndicator > keywordAssign)) {
1909b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(len<nameCapacity) {
1910b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                name[len]='@';
1911b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
1912b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++len;
1913b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ++fieldCount;
1914103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius            len += _getKeywords(tmpLocaleID+1, '@', (len<nameCapacity ? name+len : NULL), nameCapacity-len,
1915103e9ffba2cba345d0078eb8b8db33249f81840aCraig Cornelius                                NULL, 0, NULL, TRUE, addKeyword, addValue, err);
1916b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else if (addKeyword != NULL) {
191754dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius            U_ASSERT(addValue != NULL && len < nameCapacity);
1918b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* inelegant but works -- later make _getKeywords do this? */
1919b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len += _copyCount(name+len, nameCapacity-len, "@");
1920b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len += _copyCount(name+len, nameCapacity-len, addKeyword);
1921b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len += _copyCount(name+len, nameCapacity-len, "=");
1922b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len += _copyCount(name+len, nameCapacity-len, addValue);
1923b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
1924b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1925b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1926b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_SUCCESS(*err) && result != NULL && name == localeBuffer) {
1927b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_strncpy(result, localeBuffer, (len > resultCapacity) ? resultCapacity : len);
1928b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1929b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1930b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(result, resultCapacity, len, err);
1931b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1932b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1933b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### ID parsing API **************************************************/
1934b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1935b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
1936b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getParent(const char*    localeID,
1937b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru               char* parent,
1938b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru               int32_t parentCapacity,
1939b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru               UErrorCode* err)
1940b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1941b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *lastUnderscore;
1942b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i;
194364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1944b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(*err))
1945b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
194664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1947b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (localeID == NULL)
1948b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID = uloc_getDefault();
1949b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1950b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    lastUnderscore=uprv_strrchr(localeID, '_');
1951b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(lastUnderscore!=NULL) {
1952b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        i=(int32_t)(lastUnderscore-localeID);
1953b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
1954b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        i=0;
1955b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1956b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1957b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(i>0 && parent != localeID) {
1958b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_memcpy(parent, localeID, uprv_min(i, parentCapacity));
1959b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1960b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(parent, parentCapacity, i, err);
1961b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1962b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1963b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
1964b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getLanguage(const char*    localeID,
1965b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         char* language,
1966b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         int32_t languageCapacity,
1967b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         UErrorCode* err)
1968b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1969b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* uloc_getLanguage will return a 2 character iso-639 code if one exists. *CWB*/
1970b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
1971b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1972b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (err==NULL || U_FAILURE(*err)) {
1973b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1974b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
197564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
1976b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(localeID==NULL) {
1977b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID=uloc_getDefault();
1978b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1979b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
198050294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    i=ulocimp_getLanguage(localeID, language, languageCapacity, NULL);
1981b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(language, languageCapacity, i, err);
1982b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
1983b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1984b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
1985b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getScript(const char*    localeID,
1986b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         char* script,
1987b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         int32_t scriptCapacity,
1988b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru         UErrorCode* err)
1989b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
1990b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
1991b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1992b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(err==NULL || U_FAILURE(*err)) {
1993b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
1994b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1995b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
1996b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(localeID==NULL) {
1997b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID=uloc_getDefault();
1998b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
1999b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2000b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* skip the language */
200150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
2002b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(_isIDSeparator(*localeID)) {
200350294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        i=ulocimp_getScript(localeID+1, script, scriptCapacity, NULL);
2004b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2005b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(script, scriptCapacity, i, err);
2006b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2007b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2008b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
2009b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getCountry(const char* localeID,
2010b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            char* country,
2011b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            int32_t countryCapacity,
201264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            UErrorCode* err)
2013b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2014b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
2015b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2016b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(err==NULL || U_FAILURE(*err)) {
2017b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
2018b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2019b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2020b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(localeID==NULL) {
2021b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID=uloc_getDefault();
2022b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2023b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2024b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Skip the language */
202550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho    ulocimp_getLanguage(localeID, NULL, 0, &localeID);
2026b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(_isIDSeparator(*localeID)) {
2027b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *scriptID;
2028b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Skip the script if available */
202950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho        ulocimp_getScript(localeID+1, NULL, 0, &scriptID);
2030b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(scriptID != localeID+1) {
2031b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Found optional script */
2032b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            localeID = scriptID;
2033b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2034b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(_isIDSeparator(*localeID)) {
203550294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            i=ulocimp_getCountry(localeID+1, country, countryCapacity, NULL);
2036b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2037b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2038b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(country, countryCapacity, i, err);
2039b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2040b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2041b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
2042b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getVariant(const char* localeID,
2043b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                char* variant,
2044b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                int32_t variantCapacity,
204564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                UErrorCode* err)
2046b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
204727f654740f2a26ad62a5c155af9199af9e69b889claireho    char tempBuffer[ULOC_FULLNAME_CAPACITY];
204827f654740f2a26ad62a5c155af9199af9e69b889claireho    const char* tmpLocaleID;
2049b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i=0;
205064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2051b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(err==NULL || U_FAILURE(*err)) {
2052b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
2053b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
205464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
205527f654740f2a26ad62a5c155af9199af9e69b889claireho    if (_hasBCP47Extension(localeID)) {
205627f654740f2a26ad62a5c155af9199af9e69b889claireho        _ConvertBCP47(tmpLocaleID, localeID, tempBuffer, sizeof(tempBuffer), err);
205727f654740f2a26ad62a5c155af9199af9e69b889claireho    } else {
205827f654740f2a26ad62a5c155af9199af9e69b889claireho        if (localeID==NULL) {
205927f654740f2a26ad62a5c155af9199af9e69b889claireho           localeID=uloc_getDefault();
206027f654740f2a26ad62a5c155af9199af9e69b889claireho        }
206127f654740f2a26ad62a5c155af9199af9e69b889claireho        tmpLocaleID=localeID;
2062b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
206364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2064b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* Skip the language */
206527f654740f2a26ad62a5c155af9199af9e69b889claireho    ulocimp_getLanguage(tmpLocaleID, NULL, 0, &tmpLocaleID);
206627f654740f2a26ad62a5c155af9199af9e69b889claireho    if(_isIDSeparator(*tmpLocaleID)) {
2067b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        const char *scriptID;
2068b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Skip the script if available */
206927f654740f2a26ad62a5c155af9199af9e69b889claireho        ulocimp_getScript(tmpLocaleID+1, NULL, 0, &scriptID);
207027f654740f2a26ad62a5c155af9199af9e69b889claireho        if(scriptID != tmpLocaleID+1) {
2071b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* Found optional script */
207227f654740f2a26ad62a5c155af9199af9e69b889claireho            tmpLocaleID = scriptID;
2073b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2074b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* Skip the Country */
207527f654740f2a26ad62a5c155af9199af9e69b889claireho        if (_isIDSeparator(*tmpLocaleID)) {
207650294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            const char *cntryID;
207727f654740f2a26ad62a5c155af9199af9e69b889claireho            ulocimp_getCountry(tmpLocaleID+1, NULL, 0, &cntryID);
207827f654740f2a26ad62a5c155af9199af9e69b889claireho            if (cntryID != tmpLocaleID+1) {
207950294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho                /* Found optional country */
208027f654740f2a26ad62a5c155af9199af9e69b889claireho                tmpLocaleID = cntryID;
208150294ead5e5d23f5bbfed76e00e6b510bd41eee1claireho            }
208227f654740f2a26ad62a5c155af9199af9e69b889claireho            if(_isIDSeparator(*tmpLocaleID)) {
208327f654740f2a26ad62a5c155af9199af9e69b889claireho                /* If there was no country ID, skip a possible extra IDSeparator */
208427f654740f2a26ad62a5c155af9199af9e69b889claireho                if (tmpLocaleID != cntryID && _isIDSeparator(tmpLocaleID[1])) {
208527f654740f2a26ad62a5c155af9199af9e69b889claireho                    tmpLocaleID++;
208627f654740f2a26ad62a5c155af9199af9e69b889claireho                }
208727f654740f2a26ad62a5c155af9199af9e69b889claireho                i=_getVariant(tmpLocaleID+1, *tmpLocaleID, variant, variantCapacity);
2088b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2089b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2090b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
209164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2092b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* removed by weiv. We don't want to handle POSIX variants anymore. Use canonicalization function */
2093b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* if we do not have a variant tag yet then try a POSIX variant after '@' */
2094b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*
2095b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(!haveVariant && (localeID=uprv_strrchr(localeID, '@'))!=NULL) {
2096b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        i=_getVariant(localeID+1, '@', variant, variantCapacity);
2097b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2098b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
2099b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return u_terminateChars(variant, variantCapacity, i, err);
2100b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2101b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2102b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
2103b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getName(const char* localeID,
2104b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             char* name,
2105b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru             int32_t nameCapacity,
210664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert             UErrorCode* err)
2107b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2108b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return _canonicalize(localeID, name, nameCapacity, 0, err);
2109b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2110b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2111b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
2112b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getBaseName(const char* localeID,
2113b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 char* name,
2114b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                 int32_t nameCapacity,
211564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                 UErrorCode* err)
2116b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2117b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return _canonicalize(localeID, name, nameCapacity, _ULOC_STRIP_KEYWORDS, err);
2118b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2119b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2120b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t  U_EXPORT2
2121b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_canonicalize(const char* localeID,
2122b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                  char* name,
2123b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                  int32_t nameCapacity,
212464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                  UErrorCode* err)
2125b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2126b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return _canonicalize(localeID, name, nameCapacity, _ULOC_CANONICALIZE, err);
2127b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
212864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2129b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char*  U_EXPORT2
213064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_getISO3Language(const char* localeID)
2131b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2132b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int16_t offset;
2133b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char lang[ULOC_LANG_CAPACITY];
2134b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode err = U_ZERO_ERROR;
213564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2136b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (localeID == NULL)
2137b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
2138b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID = uloc_getDefault();
2139b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2140b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_getLanguage(localeID, lang, ULOC_LANG_CAPACITY, &err);
2141b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(err))
2142b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return "";
2143b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    offset = _findIndex(LANGUAGES, lang);
2144b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (offset < 0)
2145b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return "";
2146b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return LANGUAGES_3[offset];
2147b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2148b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2149b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char*  U_EXPORT2
215064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_getISO3Country(const char* localeID)
2151b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2152b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int16_t offset;
2153b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char cntry[ULOC_LANG_CAPACITY];
2154b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode err = U_ZERO_ERROR;
215564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2156b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (localeID == NULL)
2157b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    {
2158b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        localeID = uloc_getDefault();
2159b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2160b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_getCountry(localeID, cntry, ULOC_LANG_CAPACITY, &err);
2161b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(err))
2162b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return "";
2163b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    offset = _findIndex(COUNTRIES, cntry);
2164b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (offset < 0)
2165b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return "";
216664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2167b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return COUNTRIES_3[offset];
2168b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2169b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2170b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI uint32_t  U_EXPORT2
217164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_getLCID(const char* localeID)
2172b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2173b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    UErrorCode status = U_ZERO_ERROR;
2174b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char       langID[ULOC_FULLNAME_CAPACITY];
21750596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    uint32_t   lcid = 0;
21760596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
21770596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    /* Check for incomplete id. */
21780596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (!localeID || uprv_strlen(localeID) < 2) {
21790596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        return 0;
21800596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
21810596faeddefbf198de137d5e893708495ab1584cFredrik Roubert
21820596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    // Attempt platform lookup if available
21830596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    lcid = uprv_convertToLCIDPlatform(localeID);
21840596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    if (lcid > 0)
21850596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    {
21860596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        // Windows found an LCID, return that
21870596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        return lcid;
21880596faeddefbf198de137d5e893708495ab1584cFredrik Roubert    }
2189b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2190b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uloc_getLanguage(localeID, langID, sizeof(langID), &status);
2191b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(status)) {
2192b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return 0;
2193b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2194b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
219559d709d503bab6e2b61931737e662dd293b40578ccornelius    if (uprv_strchr(localeID, '@')) {
219659d709d503bab6e2b61931737e662dd293b40578ccornelius        // uprv_convertToLCID does not support keywords other than collation.
219759d709d503bab6e2b61931737e662dd293b40578ccornelius        // Remove all keywords except collation.
219859d709d503bab6e2b61931737e662dd293b40578ccornelius        int32_t len;
219959d709d503bab6e2b61931737e662dd293b40578ccornelius        char collVal[ULOC_KEYWORDS_CAPACITY];
220059d709d503bab6e2b61931737e662dd293b40578ccornelius        char tmpLocaleID[ULOC_FULLNAME_CAPACITY];
220159d709d503bab6e2b61931737e662dd293b40578ccornelius
220259d709d503bab6e2b61931737e662dd293b40578ccornelius        len = uloc_getKeywordValue(localeID, "collation", collVal,
22038de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            UPRV_LENGTHOF(collVal) - 1, &status);
220459d709d503bab6e2b61931737e662dd293b40578ccornelius
220559d709d503bab6e2b61931737e662dd293b40578ccornelius        if (U_SUCCESS(status) && len > 0) {
220659d709d503bab6e2b61931737e662dd293b40578ccornelius            collVal[len] = 0;
220759d709d503bab6e2b61931737e662dd293b40578ccornelius
220859d709d503bab6e2b61931737e662dd293b40578ccornelius            len = uloc_getBaseName(localeID, tmpLocaleID,
22098de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert                UPRV_LENGTHOF(tmpLocaleID) - 1, &status);
221059d709d503bab6e2b61931737e662dd293b40578ccornelius
22118de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert            if (U_SUCCESS(status) && len > 0) {
221259d709d503bab6e2b61931737e662dd293b40578ccornelius                tmpLocaleID[len] = 0;
221359d709d503bab6e2b61931737e662dd293b40578ccornelius
221459d709d503bab6e2b61931737e662dd293b40578ccornelius                len = uloc_setKeywordValue("collation", collVal, tmpLocaleID,
22158de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert                    UPRV_LENGTHOF(tmpLocaleID) - len - 1, &status);
221659d709d503bab6e2b61931737e662dd293b40578ccornelius
22178de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert                if (U_SUCCESS(status) && len > 0) {
221859d709d503bab6e2b61931737e662dd293b40578ccornelius                    tmpLocaleID[len] = 0;
221959d709d503bab6e2b61931737e662dd293b40578ccornelius                    return uprv_convertToLCID(langID, tmpLocaleID, &status);
222059d709d503bab6e2b61931737e662dd293b40578ccornelius                }
222159d709d503bab6e2b61931737e662dd293b40578ccornelius            }
222259d709d503bab6e2b61931737e662dd293b40578ccornelius        }
222359d709d503bab6e2b61931737e662dd293b40578ccornelius
222459d709d503bab6e2b61931737e662dd293b40578ccornelius        // fall through - all keywords are simply ignored
222559d709d503bab6e2b61931737e662dd293b40578ccornelius        status = U_ZERO_ERROR;
222659d709d503bab6e2b61931737e662dd293b40578ccornelius    }
222759d709d503bab6e2b61931737e662dd293b40578ccornelius
2228b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return uprv_convertToLCID(langID, localeID, &status);
2229b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2230b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2231b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
2232b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getLocaleForLCID(uint32_t hostid, char *locale, int32_t localeCapacity,
2233b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                UErrorCode *status)
2234b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
223559d709d503bab6e2b61931737e662dd293b40578ccornelius    return uprv_convertToPosix(hostid, locale, localeCapacity, status);
2236b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2237b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2238b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* ### Default locale **************************************************/
2239b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2240b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char*  U_EXPORT2
2241b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_getDefault()
2242b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2243b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return locale_get_default();
2244b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2245b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2246b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI void  U_EXPORT2
2247b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_setDefault(const char*   newDefaultLocale,
224864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert             UErrorCode* err)
2249b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2250b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (U_FAILURE(*err))
2251b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return;
2252b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* the error code isn't currently used for anything by this function*/
225364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert
2254b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    /* propagate change to C++ */
2255b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    locale_set_default(newDefaultLocale);
2256b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2257b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2258b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
22598393335b955da7340c9f19b1b4b2d6c0c2c04be7Craig Cornelius * Returns a list of all 2-letter language codes defined in ISO 639.  This is a pointer
2260b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * to an array of pointers to arrays of char.  All of these pointers are owned
2261b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * by ICU-- do not delete them, and do not write through them.  The array is
2262b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * terminated with a null pointer.
2263b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
2264b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char* const*  U_EXPORT2
226564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_getISOLanguages()
2266b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2267b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return LANGUAGES;
2268b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2269b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2270b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/**
2271b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * Returns a list of all 2-letter country codes defined in ISO 639.  This is a
2272b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * pointer to an array of pointers to arrays of char.  All of these pointers are
2273b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * owned by ICU-- do not delete them, and do not write through them.  The array is
2274b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru * terminated with a null pointer.
2275b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru */
2276b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI const char* const*  U_EXPORT2
227764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_getISOCountries()
2278b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2279b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return COUNTRIES;
2280b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2281b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2282b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2283b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* this function to be moved into cstring.c later */
2284b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic char gDecimal = 0;
2285b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2286b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic /* U_CAPI */
2287b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querudouble
2288b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/* U_EXPORT2 */
2289b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru_uloc_strtod(const char *start, char **end) {
2290b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *decimal;
2291b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char *myEnd;
2292b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char buf[30];
2293b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    double rv;
2294b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if (!gDecimal) {
2295b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        char rep[5];
2296b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* For machines that decide to change the decimal on you,
2297b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        and try to be too smart with localization.
2298b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        This normally should be just a '.'. */
2299b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        sprintf(rep, "%+1.1f", 1.0);
2300b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        gDecimal = rep[2];
2301b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2302b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2303b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(gDecimal == '.') {
2304b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return uprv_strtod(start, end); /* fall through to OS */
2305b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
2306b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_strncpy(buf, start, 29);
2307b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        buf[29]=0;
2308b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        decimal = uprv_strchr(buf, '.');
2309b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(decimal) {
2310b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            *decimal = gDecimal;
2311b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
2312b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            return uprv_strtod(start, end); /* no decimal point */
2313b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2314b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rv = uprv_strtod(buf, &myEnd);
2315b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(end) {
2316b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            *end = (char*)(start+(myEnd-buf)); /* cast away const (to follow uprv_strtod API.) */
2317b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2318b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return rv;
2319b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2320b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2321b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
232264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Rouberttypedef struct {
2323b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    float q;
2324b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t dummy;  /* to avoid uninitialized memory copy from qsort */
232564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    char locale[ULOC_FULLNAME_CAPACITY+1];
2326b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru} _acceptLangItem;
2327b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2328b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querustatic int32_t U_CALLCONV
2329103e9ffba2cba345d0078eb8b8db33249f81840aCraig Corneliusuloc_acceptLanguageCompare(const void * /*context*/, const void *a, const void *b)
2330b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2331b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const _acceptLangItem *aa = (const _acceptLangItem*)a;
2332b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const _acceptLangItem *bb = (const _acceptLangItem*)b;
2333b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2334b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t rc = 0;
2335b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(bb->q < aa->q) {
2336b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rc = -1;  /* A > B */
2337b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else if(bb->q > aa->q) {
2338b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rc = 1;   /* A < B */
2339b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    } else {
2340b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rc = 0;   /* A = B */
2341b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2342b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2343b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(rc==0) {
2344b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        rc = uprv_stricmp(aa->locale, bb->locale);
2345b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2346b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2347b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
234864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    /*  fprintf(stderr, "a:[%s:%g], b:[%s:%g] -> %d\n",
234964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    aa->locale, aa->q,
2350b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    bb->locale, bb->q,
2351b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    rc);*/
2352b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2353b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2354b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return rc;
2355b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2356b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
235764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert/*
2358b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Querumt-mt, ja;q=0.76, en-us;q=0.95, en;q=0.92, en-gb;q=0.89, fr;q=0.87, iu-ca;q=0.84, iu;q=0.82, ja-jp;q=0.79, mt;q=0.97, de-de;q=0.74, de;q=0.71, es;q=0.68, it-it;q=0.66, it;q=0.63, vi-vn;q=0.61, vi;q=0.58, nl-nl;q=0.55, nl;q=0.53
2359b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru*/
2360b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2361b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
2362b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queruuloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult *outResult,
2363b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            const char *httpAcceptLanguage,
2364b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            UEnumeration* availableLocales,
2365b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            UErrorCode *status)
2366b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
236764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert  MaybeStackArray<_acceptLangItem, 4> items; // Struct for collecting items.
2368b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char tmp[ULOC_FULLNAME_CAPACITY +1];
2369b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t n = 0;
2370b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *itemEnd;
2371b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *paramEnd;
2372b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *s;
2373b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *t;
2374b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t res;
2375b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i;
2376b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
2377b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2378b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_FAILURE(*status)) {
2379b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return -1;
2380b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2381b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2382b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(s=httpAcceptLanguage;s&&*s;) {
2383b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(isspace(*s)) /* eat space at the beginning */
2384b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            s++;
2385b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        itemEnd=uprv_strchr(s,',');
2386b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        paramEnd=uprv_strchr(s,';');
2387b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        if(!itemEnd) {
2388b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            itemEnd = httpAcceptLanguage+l; /* end of string */
2389b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
239064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(paramEnd && paramEnd<itemEnd) {
2391b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* semicolon (;) is closer than end (,) */
2392b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            t = paramEnd+1;
2393b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(*t=='q') {
2394b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                t++;
2395b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2396b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while(isspace(*t)) {
2397b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                t++;
2398b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2399b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(*t=='=') {
2400b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                t++;
2401b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2402b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            while(isspace(*t)) {
2403b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                t++;
2404b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
240564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            items[n].q = (float)_uloc_strtod(t,NULL);
2406b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
2407b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            /* no semicolon - it's 1.0 */
240864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            items[n].q = 1.0f;
2409b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            paramEnd = itemEnd;
2410b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
241164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        items[n].dummy=0;
2412b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* eat spaces prior to semi */
2413b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--)
2414b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            ;
241564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        int32_t slen = ((t+1)-s);
241664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(slen > ULOC_FULLNAME_CAPACITY) {
241764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          *status = U_BUFFER_OVERFLOW_ERROR;
241864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          return -1; // too big
241964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        }
242064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        uprv_strncpy(items[n].locale, s, slen);
242164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        items[n].locale[slen]=0; // terminate
242264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        int32_t clen = uloc_canonicalize(items[n].locale, tmp, UPRV_LENGTHOF(tmp)-1, status);
242364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(U_FAILURE(*status)) return -1;
242464339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if((clen!=slen) || (uprv_strncmp(items[n].locale, tmp, slen))) {
242564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            // canonicalization had an effect- copy back
242664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            uprv_strncpy(items[n].locale, tmp, clen);
242764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert            items[n].locale[clen] = 0; // terminate
2428b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2429b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2430b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /*fprintf(stderr,"%d: s <%s> q <%g>\n", n, j[n].locale, j[n].q);*/
2431b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2432b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        n++;
2433b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        s = itemEnd;
2434b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        while(*s==',') { /* eat duplicate commas */
2435b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            s++;
2436b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
243764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(n>=items.getCapacity()) { // If we need more items
243864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          if(NULL == items.resize(items.getCapacity()*2, items.getCapacity())) {
243964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert              *status = U_MEMORY_ALLOCATION_ERROR;
244064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert              return -1;
244164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          }
2442b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
244364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert          fprintf(stderr,"malloced at size %d\n", items.getCapacity());
2444b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2445b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2446b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
244764339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    uprv_sortArray(items.getAlias(), n, sizeof(items[0]), uloc_acceptLanguageCompare, NULL, TRUE, status);
244864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (U_FAILURE(*status)) {
2449b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return -1;
2450b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
245164339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    LocalMemory<const char*> strs(NULL);
245264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    if (strs.allocateInsteadAndReset(n) == NULL) {
2453c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
2454c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru        return -1;
2455c69afcec261fc345fda8daf46f0ea6b4351dc777Jean-Baptiste Queru    }
2456b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(i=0;i<n;i++) {
2457b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2458b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /*fprintf(stderr,"%d: s <%s> q <%g>\n", i, j[i].locale, j[i].q);*/
2459b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
246064339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        strs[i]=items[i].locale;
2461b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
246264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert    res =  uloc_acceptLanguage(result, resultAvailable, outResult,
246364339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                               strs.getAlias(), n, availableLocales, status);
2464b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return res;
2465b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2466b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2467b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2468b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste QueruU_CAPI int32_t U_EXPORT2
246964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubertuloc_acceptLanguage(char *result, int32_t resultAvailable,
2470b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UAcceptResult *outResult, const char **acceptList,
2471b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    int32_t acceptListCount,
2472b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UEnumeration* availableLocales,
2473b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    UErrorCode *status)
2474b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru{
2475b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t i,j;
2476b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t len;
2477b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    int32_t maxLen=0;
2478b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char tmp[ULOC_FULLNAME_CAPACITY+1];
2479b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    const char *l;
2480b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    char **fallbackList;
2481b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(U_FAILURE(*status)) {
2482b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return -1;
2483b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
248454dcd9b6a06071f647dac967e9e267abb9410720Craig Cornelius    fallbackList = static_cast<char **>(uprv_malloc((size_t)(sizeof(fallbackList[0])*acceptListCount)));
2485b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    if(fallbackList==NULL) {
2486b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        *status = U_MEMORY_ALLOCATION_ERROR;
2487b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        return -1;
2488b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2489b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(i=0;i<acceptListCount;i++) {
2490b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2491b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        fprintf(stderr,"%02d: %s\n", i, acceptList[i]);
2492b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2493ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert        while((l=uenum_next(availableLocales, NULL, status)) != NULL) {
2494b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2495b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fprintf(stderr,"  %s\n", l);
2496b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2497b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            len = (int32_t)uprv_strlen(l);
2498b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(!uprv_strcmp(acceptList[i], l)) {
249964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                if(outResult) {
2500b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    *outResult = ULOC_ACCEPT_VALID;
2501b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
2502b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2503b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fprintf(stderr, "MATCH! %s\n", l);
2504b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2505b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                if(len>0) {
2506b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_strncpy(result, l, uprv_min(len, resultAvailable));
2507b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
2508b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                for(j=0;j<i;j++) {
2509b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_free(fallbackList[j]);
2510b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
2511b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                uprv_free(fallbackList);
251264339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                return u_terminateChars(result, resultAvailable, len, status);
2513b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2514b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(len>maxLen) {
2515b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                maxLen = len;
2516b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2517b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
251864339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        uenum_reset(availableLocales, status);
2519b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        /* save off parent info */
25208de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert        if(uloc_getParent(acceptList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
2521b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fallbackList[i] = uprv_strdup(tmp);
2522b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        } else {
2523b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            fallbackList[i]=0;
2524b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2525b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2526b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2527b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(maxLen--;maxLen>0;maxLen--) {
2528b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        for(i=0;i<acceptListCount;i++) {
2529b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            if(fallbackList[i] && ((int32_t)uprv_strlen(fallbackList[i])==maxLen)) {
2530b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2531b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                fprintf(stderr,"Try: [%s]", fallbackList[i]);
2532b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2533ffdc27edd5503111189fc11165c5a11289a71f79Fredrik Roubert                while((l=uenum_next(availableLocales, NULL, status)) != NULL) {
2534b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2535b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fprintf(stderr,"  %s\n", l);
2536b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2537b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    len = (int32_t)uprv_strlen(l);
2538b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    if(!uprv_strcmp(fallbackList[i], l)) {
253964339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                        if(outResult) {
2540b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            *outResult = ULOC_ACCEPT_FALLBACK;
2541b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
2542b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#if defined(ULOC_DEBUG)
2543b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        fprintf(stderr, "fallback MATCH! %s\n", l);
2544b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru#endif
2545b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        if(len>0) {
2546b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            uprv_strncpy(result, l, uprv_min(len, resultAvailable));
2547b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
2548b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        for(j=0;j<acceptListCount;j++) {
2549b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                            uprv_free(fallbackList[j]);
2550b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        }
2551b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        uprv_free(fallbackList);
2552b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                        return u_terminateChars(result, resultAvailable, len, status);
2553b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    }
2554b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
255564339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert                uenum_reset(availableLocales, status);
2556b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
25578de051c3d18a56cc126f0f44e368495a52f9148cFredrik Roubert                if(uloc_getParent(fallbackList[i], tmp, UPRV_LENGTHOF(tmp), status)!=0) {
2558b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_free(fallbackList[i]);
2559b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fallbackList[i] = uprv_strdup(tmp);
2560b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                } else {
2561b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    uprv_free(fallbackList[i]);
2562b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                    fallbackList[i]=0;
2563b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru                }
2564b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            }
2565b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
256664339d36f8bd4db5025fe2988eda22b491a9219cFredrik Roubert        if(outResult) {
2567b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru            *outResult = ULOC_ACCEPT_FAILED;
2568b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        }
2569b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2570b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    for(i=0;i<acceptListCount;i++) {
2571b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru        uprv_free(fallbackList[i]);
2572b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    }
2573b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    uprv_free(fallbackList);
2574b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru    return -1;
2575b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru}
2576b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru
2577f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI const char* U_EXPORT2
2578f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusuloc_toUnicodeLocaleKey(const char* keyword)
2579f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2580f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* bcpKey = ulocimp_toBcpKey(keyword);
2581f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (bcpKey == NULL && ultag_isUnicodeLocaleKey(keyword, -1)) {
2582f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // unknown keyword, but syntax is fine..
2583f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        return keyword;
2584f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2585f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return bcpKey;
2586f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2587f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2588f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI const char* U_EXPORT2
2589f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusuloc_toUnicodeLocaleType(const char* keyword, const char* value)
2590f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2591f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* bcpType = ulocimp_toBcpType(keyword, value, NULL, NULL);
2592f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (bcpType == NULL && ultag_isUnicodeLocaleType(value, -1)) {
2593f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // unknown keyword, but syntax is fine..
2594f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        return value;
2595f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2596f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return bcpType;
2597f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2598f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2599f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstatic UBool
2600f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusisWellFormedLegacyKey(const char* legacyKey)
2601f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2602f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* p = legacyKey;
2603f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    while (*p) {
2604f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        if (!UPRV_ISALPHANUM(*p)) {
2605f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            return FALSE;
2606f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        }
2607f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        p++;
2608f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2609f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return TRUE;
2610f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2611f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2612f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusstatic UBool
2613f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusisWellFormedLegacyType(const char* legacyType)
2614f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2615f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* p = legacyType;
2616f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    int32_t alphaNumLen = 0;
2617f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    while (*p) {
2618f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        if (*p == '_' || *p == '/' || *p == '-') {
2619f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            if (alphaNumLen == 0) {
2620f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius                return FALSE;
2621f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            }
2622f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            alphaNumLen = 0;
2623f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        } else if (UPRV_ISALPHANUM(*p)) {
2624f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            alphaNumLen++;
2625f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        } else {
2626f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            return FALSE;
2627f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        }
2628f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        p++;
2629f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2630f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return (alphaNumLen != 0);
2631f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2632f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2633f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI const char* U_EXPORT2
2634f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusuloc_toLegacyKey(const char* keyword)
2635f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2636f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* legacyKey = ulocimp_toLegacyKey(keyword);
2637f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (legacyKey == NULL) {
2638f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // Checks if the specified locale key is well-formed with the legacy locale syntax.
2639f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        //
2640f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // Note:
26410596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  LDML/CLDR provides some definition of keyword syntax in
26420596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  * http://www.unicode.org/reports/tr35/#Unicode_locale_identifier and
26430596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  * http://www.unicode.org/reports/tr35/#Old_Locale_Extension_Syntax
26440596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  Keys can only consist of [0-9a-zA-Z].
2645f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        if (isWellFormedLegacyKey(keyword)) {
2646f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            return keyword;
2647f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        }
2648f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2649f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return legacyKey;
2650f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2651f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2652f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusU_CAPI const char* U_EXPORT2
2653f9878a236aa0d9662d8e40cafdaf2e04cd615835ccorneliusuloc_toLegacyType(const char* keyword, const char* value)
2654f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius{
2655f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    const char* legacyType = ulocimp_toLegacyType(keyword, value, NULL, NULL);
2656f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    if (legacyType == NULL) {
2657f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // Checks if the specified locale type is well-formed with the legacy locale syntax.
2658f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        //
2659f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        // Note:
26600596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  LDML/CLDR provides some definition of keyword syntax in
26610596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  * http://www.unicode.org/reports/tr35/#Unicode_locale_identifier and
26620596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  * http://www.unicode.org/reports/tr35/#Old_Locale_Extension_Syntax
26630596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  Values (types) can only consist of [0-9a-zA-Z], plus for legacy values
26640596faeddefbf198de137d5e893708495ab1584cFredrik Roubert        //  we allow [/_-+] in the middle (e.g. "Etc/GMT+1", "Asia/Tel_Aviv")
2665f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        if (isWellFormedLegacyType(value)) {
2666f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius            return value;
2667f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius        }
2668f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    }
2669f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius    return legacyType;
2670f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius}
2671f9878a236aa0d9662d8e40cafdaf2e04cd615835ccornelius
2672b13da9df870a61b11249bf741347908dbea0edd8Jean-Baptiste Queru/*eof*/
2673