1/*
2**********************************************************************
3*   Copyright (C) 1997-2014, International Business Machines
4*   Corporation and others.  All Rights Reserved.
5**********************************************************************
6*
7* File USCRIPT.C
8*
9* Modification History:
10*
11*   Date        Name        Description
12*   07/06/2001    Ram         Creation.
13******************************************************************************
14*/
15
16#include "unicode/uchar.h"
17#include "unicode/uscript.h"
18#include "unicode/uloc.h"
19#include "cmemory.h"
20#include "cstring.h"
21
22static const UScriptCode JAPANESE[3] = { USCRIPT_KATAKANA, USCRIPT_HIRAGANA, USCRIPT_HAN };
23static const UScriptCode KOREAN[2] = { USCRIPT_HANGUL, USCRIPT_HAN };
24static const UScriptCode HAN_BOPO[2] = { USCRIPT_HAN, USCRIPT_BOPOMOFO };
25
26static int32_t
27setCodes(const UScriptCode *src, int32_t length,
28         UScriptCode *dest, int32_t capacity, UErrorCode *err) {
29    int32_t i;
30    if(U_FAILURE(*err)) { return 0; }
31    if(length > capacity) {
32        *err = U_BUFFER_OVERFLOW_ERROR;
33        return length;
34    }
35    for(i = 0; i < length; ++i) {
36        dest[i] = src[i];
37    }
38    return length;
39}
40
41static int32_t
42setOneCode(UScriptCode script, UScriptCode *scripts, int32_t capacity, UErrorCode *err) {
43    if(U_FAILURE(*err)) { return 0; }
44    if(1 > capacity) {
45        *err = U_BUFFER_OVERFLOW_ERROR;
46        return 1;
47    }
48    scripts[0] = script;
49    return 1;
50}
51
52static int32_t
53getCodesFromLocale(const char *locale,
54                   UScriptCode *scripts, int32_t capacity, UErrorCode *err) {
55    UErrorCode internalErrorCode = U_ZERO_ERROR;
56    char lang[8];
57    char script[8];
58    int32_t scriptLength;
59    if(U_FAILURE(*err)) { return 0; }
60    // Multi-script languages, equivalent to the LocaleScript data
61    // that we used to load from locale resource bundles.
62    /*length = */ uloc_getLanguage(locale, lang, UPRV_LENGTHOF(lang), &internalErrorCode);
63    if(U_FAILURE(internalErrorCode) || internalErrorCode == U_STRING_NOT_TERMINATED_WARNING) {
64        return 0;
65    }
66    if(0 == uprv_strcmp(lang, "ja")) {
67        return setCodes(JAPANESE, UPRV_LENGTHOF(JAPANESE), scripts, capacity, err);
68    }
69    if(0 == uprv_strcmp(lang, "ko")) {
70        return setCodes(KOREAN, UPRV_LENGTHOF(KOREAN), scripts, capacity, err);
71    }
72    scriptLength = uloc_getScript(locale, script, UPRV_LENGTHOF(script), &internalErrorCode);
73    if(U_FAILURE(internalErrorCode) || internalErrorCode == U_STRING_NOT_TERMINATED_WARNING) {
74        return 0;
75    }
76    if(0 == uprv_strcmp(lang, "zh") && 0 == uprv_strcmp(script, "Hant")) {
77        return setCodes(HAN_BOPO, UPRV_LENGTHOF(HAN_BOPO), scripts, capacity, err);
78    }
79    // Explicit script code.
80    if(scriptLength != 0) {
81        UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script);
82        if(scriptCode != USCRIPT_INVALID_CODE) {
83            if(scriptCode == USCRIPT_SIMPLIFIED_HAN || scriptCode == USCRIPT_TRADITIONAL_HAN) {
84                scriptCode = USCRIPT_HAN;
85            }
86            return setOneCode(scriptCode, scripts, capacity, err);
87        }
88    }
89    return 0;
90}
91
92/* TODO: this is a bad API and should be deprecated, ticket #11141 */
93U_CAPI int32_t  U_EXPORT2
94uscript_getCode(const char* nameOrAbbrOrLocale,
95                UScriptCode* fillIn,
96                int32_t capacity,
97                UErrorCode* err){
98    UBool triedCode;
99    char likely[ULOC_FULLNAME_CAPACITY];
100    UErrorCode internalErrorCode;
101    int32_t length;
102
103    if(U_FAILURE(*err)) {
104        return 0;
105    }
106    if(nameOrAbbrOrLocale==NULL ||
107            (fillIn == NULL ? capacity != 0 : capacity < 0)) {
108        *err = U_ILLEGAL_ARGUMENT_ERROR;
109        return 0;
110    }
111
112    triedCode = FALSE;
113    if(uprv_strchr(nameOrAbbrOrLocale, '-')==NULL && uprv_strchr(nameOrAbbrOrLocale, '_')==NULL ){
114        /* try long and abbreviated script names first */
115        UScriptCode code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, nameOrAbbrOrLocale);
116        if(code!=USCRIPT_INVALID_CODE) {
117            return setOneCode(code, fillIn, capacity, err);
118        }
119        triedCode = TRUE;
120    }
121    internalErrorCode = U_ZERO_ERROR;
122    length = getCodesFromLocale(nameOrAbbrOrLocale, fillIn, capacity, err);
123    if(U_FAILURE(*err) || length != 0) {
124        return length;
125    }
126    (void)uloc_addLikelySubtags(nameOrAbbrOrLocale,
127                                likely, UPRV_LENGTHOF(likely), &internalErrorCode);
128    if(U_SUCCESS(internalErrorCode) && internalErrorCode != U_STRING_NOT_TERMINATED_WARNING) {
129        length = getCodesFromLocale(likely, fillIn, capacity, err);
130        if(U_FAILURE(*err) || length != 0) {
131            return length;
132        }
133    }
134    if(!triedCode) {
135        /* still not found .. try long and abbreviated script names again */
136        UScriptCode code = (UScriptCode) u_getPropertyValueEnum(UCHAR_SCRIPT, nameOrAbbrOrLocale);
137        if(code!=USCRIPT_INVALID_CODE) {
138            return setOneCode(code, fillIn, capacity, err);
139        }
140    }
141    return 0;
142}
143