tizen 2.4 release
[apps/home/ug-lockscreen-setting-efl.git] / ug-lockscreen-setting-efl / src / lockscreen-options-ucol.c
1 /*
2  * Copyright (c) 2009 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 //#include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include <ctype.h>
27
28 #include <Eina.h>
29 //#include <dlog.h>
30
31 #include <unicode/ucol.h>
32 #include <unicode/ustring.h>
33
34 #include "lockscreen-options-debug.h"
35 #include "lockscreen-options-ucol.h"
36
37
38 static struct info {
39         UCollator *coll;
40         enum LANGUAGE lang;
41 } s_info = {
42         .coll = NULL,
43         .lang = LANG_ENGLISH,
44 };
45
46 HAPI int ucol_init(void)
47 {
48         const char *env;
49         UErrorCode status = U_ZERO_ERROR;
50
51         env = getenv("LANG");
52         if (env) {
53                 if (!strcasecmp(env, "en_US.utf-8")) {
54                         s_info.lang = LANG_ENGLISH;
55                 } else if (!strcasecmp(env, "ja_JP.utf-8")) {
56                         s_info.lang = LANG_JAPANESS;
57                 } else if (!strcasecmp(env, "ko_KR.utf-8")) {
58                         s_info.lang = LANG_KOREAN;
59                 }
60         }
61
62         s_info.coll = ucol_open(NULL, &status);
63         if (!U_SUCCESS(status)) {
64                 LOCKOPTIONS_DBG("Failed to open ucol (%d)\n", status);
65                 ucol_close(s_info.coll);
66                 s_info.coll = NULL;
67         }
68
69         ucol_setAttribute(s_info.coll, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
70         if (!U_SUCCESS(status)) {
71                 LOCKOPTIONS_DBG("Failed to open ucol (%d)\n", status);
72                 ucol_close(s_info.coll);
73                 s_info.coll = NULL;
74         }
75
76         ucol_setStrength(s_info.coll, UCOL_PRIMARY);
77         return 0;
78 }
79
80 static inline UChar *to_UTF16(const char *src, int *out_len)
81 {
82         UChar *res;
83         UErrorCode status = U_ZERO_ERROR;
84         int32_t len;
85
86         len = strlen(src);
87
88         res = calloc(len + 1, sizeof(*res));
89         if (!res) {
90                 LOCKOPTIONS_DBG("Heap: %s\n", strerror(errno));
91                 return NULL;
92         }
93
94         u_strFromUTF8(res, len, &len, src, -1, &status);
95         if (!U_SUCCESS(status)) {
96                 LOCKOPTIONS_DBG("Unable to convert(%s) to UTF16(%s)\n", src, u_errorName(status));
97                 free(res);
98                 return NULL;
99         }
100
101         *out_len = len;
102         return res;
103 }
104
105 static inline int hangul_to_jamo(const char *index)
106 {
107         Eina_Unicode *ret;
108         Eina_Unicode tmp = 0;
109         int base = 0xAC00;
110         int last = 0xD79F;
111         int a;
112         static int table[] = {
113                 0x00003131, 0x00003131,
114                 0x00003134,
115                 0x00003137, 0x00003137,
116                 0x00003139,
117                 0x00003141,
118                 0x00003142, 0x00003142,
119                 0x00003145, 0x00003145,
120                 0x00003147,
121                 0x00003148, 0x00003148,
122                 0x0000314a,
123                 0x0000314b,
124                 0x0000314c,
125                 0x0000314d,
126                 0x0000314e,
127                 /*
128                    0xb184e3, 0xb284e3, 0xb484e3, 0xb784e3, 0xb884e3, 0xb984e3,
129                    0x8185e3, 0x8285e3, 0x8385e3, 0x8585e3, 0x8685e3, 0x8785e3,
130                    0x8885e3, 0x8985e3, 0x8a85e3, 0x8b85e3, 0x8c85e3, 0x8d85e3,
131                    0x8e85e3,
132                  */
133         };
134
135         ret = eina_unicode_utf8_to_unicode(index, &a);
136         if (ret) {
137                 tmp = *ret;
138                 free(ret);
139         }
140
141         if (tmp < base || tmp > last) {
142                 return tmp;
143         }
144
145         tmp = tmp - base;
146         a = tmp / (21 * 28);
147         return table[a];
148 }
149
150 #define __isalpha(a)    (((a) >= 'a' && (a) <= 'z') || ((a) >= 'A' && (a) <= 'Z'))
151 #define __tolower(a)    (((a) >= 'A' && (a) <= 'Z') ? (a) + 32 : (a))
152
153 HAPI int ucol_compare_first_letters(const char *name, const char *letters)
154 {
155         if (s_info.lang == LANG_KOREAN) {
156                 int jamo_name;
157                 int jamo_letters = 0;
158                 Eina_Unicode *ucs;
159
160                 jamo_name = hangul_to_jamo(name);
161
162                 ucs = eina_unicode_utf8_to_unicode(letters, &jamo_letters);
163                 if (ucs) {
164                         jamo_letters = (int)*ucs;
165                         free(ucs);
166                 }
167
168                 if (__isalpha(jamo_letters)) {
169                         if (!__isalpha(jamo_name)) {
170                                 //DbgPrint("%d - %d (%s, %s)\n", jamo_name, jamo_letters, name, letters);
171                                 return -1;
172                         }
173
174                         return __tolower(jamo_name) - __tolower(jamo_letters);
175                 }
176
177                 return jamo_name - jamo_letters;
178         }
179
180         return ucol_ncompare(name, letters, strlen(letters));
181 }
182
183 HAPI int ucol_is_alpha(const char *name)
184 {
185         Eina_Unicode *ucs;
186         int len;
187         int letter = 0;
188
189         ucs = eina_unicode_utf8_to_unicode(name, &len);
190         if (ucs) {
191                 letter = (int)*ucs;
192                 free(ucs);
193         }
194
195         return __isalpha(letter);
196 }
197
198 HAPI int ucol_detect_lang(int ch)
199 {
200 //      int result;
201         int lang;
202 //      int status;
203 //      int size;
204
205         /*
206         u_strToUpper((UChar *)&ch, 1, (UChar *)&result, -1, NULL, &status);
207         if (U_FAILURE(status)) {
208                 ErrPrint("u_strToLower: %s\n", u_errorName(status));
209                 return LANG_UNKNOWN;
210         }
211
212         size = unorm_normalize((UChar *)&result, 1, UNORM_NFD, 0, (UChar *)&result, 1, &status);
213         if (U_FAILURE(status)) {
214                 ErrPrint("unorm_normalize: %s\n", u_errorName(status));
215                 return LANG_UNKNOWN;
216         }
217         */
218
219         lang = ublock_getCode(ch);
220         switch (lang) {
221                 case UBLOCK_HIRAGANA:
222                 case UBLOCK_KATAKANA:
223                 case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS:
224                 case UBLOCK_JAVANESE:
225                 case UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS:
226                         lang = LANG_JAPANESS;
227                         break;
228                 case UBLOCK_HANGUL_JAMO:
229                 case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
230                 case UBLOCK_HANGUL_SYLLABLES:
231                 case UBLOCK_HANGUL_JAMO_EXTENDED_A:
232                 case UBLOCK_HANGUL_JAMO_EXTENDED_B:
233                         lang = LANG_KOREAN;
234                         break;
235                 case UBLOCK_BASIC_LATIN:                                                        // = 1, /*[0000]*/
236                 case UBLOCK_LATIN_1_SUPPLEMENT:                                 // =2, /*[0080]*/
237                 case UBLOCK_LATIN_EXTENDED_A:                                           // =3, /*[0100]*/
238                 case UBLOCK_LATIN_EXTENDED_B:                                           // =4, /*[0180]*/
239                 case UBLOCK_LATIN_EXTENDED_ADDITIONAL:                  // =38, /*[1E00]*/
240                         lang = LANG_ENGLISH;
241                         break;
242                 case UBLOCK_CJK_RADICALS_SUPPLEMENT:                     //=58, /*[2E80]*/
243                 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:                 //=61, /*[3000]*/
244                 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:  //=68, /*[3200]*/
245                 case UBLOCK_CJK_STROKES:                                                         // =130, /*[31C0]*/
246                 case UBLOCK_CJK_COMPATIBILITY:                                           // =69, /*[3300]*/
247                 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A: //=70, /*[3400]*/
248                 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:                              //=71, /*[4E00]*/
249                 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:                //=79, /*[F900]*/
250                 case UBLOCK_CJK_COMPATIBILITY_FORMS:                             //=83, /*[FE30]*/
251                 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B :       // =94, /*[20000]*/
252                 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:         // =95, /*[2F800]*/
253                 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:         // =197, /*[2A700]*/
254                 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:         // =209, /*[2B740]*/
255                         lang = LANG_CHINESS;
256                         break;
257                 default:
258                         LOCKOPTIONS_DBG("Detected unknown: %d\n", lang);
259                         lang = LANG_UNKNOWN;
260                         break;
261         }
262
263         return lang;
264 }
265
266 HAPI int ucol_ncompare(const char *src, const char *dest, int len)
267 {
268         UChar *src_uni;
269         UChar *dest_uni;
270         UCollationResult res;
271         int32_t dest_len;
272         int32_t src_len;
273         char *tmp;
274
275         if (!s_info.coll) {
276                 return strncmp(src, dest, len);
277         }
278
279         tmp = malloc(len + 1);
280         if (!tmp) {
281                 LOCKOPTIONS_DBG("Heap: %s\n", strerror(errno));
282                 return strncmp(src, dest, len);
283         }
284         strncpy(tmp, dest, len);
285         tmp[len] = '\0';
286
287         /* To get the ucs16 len */
288         src_uni = to_UTF16(tmp, &len);
289         free(tmp);
290         if (!src_uni) {
291                 LOCKOPTIONS_DBG("Failed get utf16\n");
292                 return strncmp(src, dest, len);
293         }
294         free(src_uni);
295
296         src_uni = to_UTF16(src, &src_len);
297         if (!src_uni) {
298                 LOCKOPTIONS_DBG("SRC: Failed to convert to UTF16\n");
299                 return strncmp(src, dest, len);
300         }
301
302         dest_uni = to_UTF16(dest, &dest_len);
303         if (!dest_uni) {
304                 LOCKOPTIONS_DBG("DEST: Failed to convert to UTF16\n");
305                 free(src_uni);
306                 return strncmp(src, dest, len);
307         }
308
309         switch (s_info.lang) {
310         case LANG_JAPANESS:
311                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
312                         res = UCOL_GREATER;
313                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
314                         res = UCOL_LESS;
315                 } else {
316                         int src_lang;
317                         int dest_lang;
318
319                         src_lang = ucol_detect_lang(*src_uni);
320                         dest_lang = ucol_detect_lang(*dest_uni);
321
322                         if (src_lang == LANG_JAPANESS && dest_lang != LANG_JAPANESS) {
323                                 res = UCOL_LESS;
324                         } else if (src_lang != LANG_JAPANESS && dest_lang == LANG_JAPANESS) {
325                                 res = UCOL_GREATER;
326                         } else {
327                                 res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
328                         }
329                 }
330                 break;
331         case LANG_KOREAN:
332                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
333                         res = UCOL_GREATER;
334                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
335                         res = UCOL_LESS;
336                 } else {
337                         int src_lang;
338                         int dest_lang;
339
340                         src_lang = ucol_detect_lang(*src_uni);
341                         dest_lang = ucol_detect_lang(*dest_uni);
342
343                         if (src_lang == LANG_KOREAN && dest_lang != LANG_KOREAN) {
344                                 res = UCOL_LESS;
345                         } else if (src_lang != LANG_KOREAN && dest_lang == LANG_KOREAN) {
346                                 res = UCOL_GREATER;
347                         } else {
348                                 res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
349                         }
350                 }
351                 break;
352         case LANG_ENGLISH:
353         default:
354                 /*
355                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
356                         res = UCOL_LESS;
357                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
358                         res = UCOL_GREATER;
359                 } else {
360                 */
361                         res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
362                 /*
363                 }
364                 */
365         }
366
367         free(src_uni);
368         free(dest_uni);
369
370         switch (res) {
371         case UCOL_LESS:
372                 return -1;
373
374         case UCOL_EQUAL:
375                 return 0;
376
377         case UCOL_GREATER:
378                 return 1;
379
380         default:
381                 LOCKOPTIONS_DBG("%s ? %s\n", src, dest);
382                 return 0;
383         }
384 }
385
386 HAPI int ucol_compare(const char *src, const char *dest)
387 {
388         UChar *src_uni;
389         UChar *dest_uni;
390         UCollationResult res;
391         int32_t dest_len;
392         int32_t src_len;
393         int len;
394
395         if (!s_info.coll) {
396                 return strcmp(src, dest);
397         }
398
399         src_uni = to_UTF16(src, &src_len);
400         if (!src_uni) {
401                 LOCKOPTIONS_DBG("SRC: Failed to convert to UTF16\n");
402                 return strcmp(src, dest);
403         }
404
405         dest_uni = to_UTF16(dest, &dest_len);
406         if (!dest_uni) {
407                 LOCKOPTIONS_DBG("DEST: Failed to convert to UTF16\n");
408                 free(src_uni);
409                 return strcmp(src, dest);
410         }
411
412         len = src_len > dest_len ? dest_len : src_len;
413
414         switch (s_info.lang) {
415         case LANG_JAPANESS:
416                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
417                         res = UCOL_GREATER;
418                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
419                         res = UCOL_LESS;
420                 } else {
421                         int src_lang;
422                         int dest_lang;
423
424                         src_lang = ucol_detect_lang(*src_uni);
425                         dest_lang = ucol_detect_lang(*dest_uni);
426
427                         if (src_lang == LANG_JAPANESS && dest_lang != LANG_JAPANESS) {
428                                 res = UCOL_LESS;
429                         } else if (src_lang != LANG_JAPANESS && dest_lang == LANG_JAPANESS) {
430                                 res = UCOL_GREATER;
431                         } else {
432                                 res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
433                         }
434                 }
435                 break;
436         case LANG_KOREAN:
437                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
438                         res = UCOL_GREATER;
439                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
440                         res = UCOL_LESS;
441                 } else {
442                         int src_lang;
443                         int dest_lang;
444
445                         src_lang = ucol_detect_lang(*src_uni);
446                         dest_lang = ucol_detect_lang(*dest_uni);
447
448                         if (src_lang == LANG_KOREAN && dest_lang != LANG_KOREAN) {
449                                 res = UCOL_LESS;
450                         } else if (src_lang != LANG_KOREAN && dest_lang == LANG_KOREAN) {
451                                 res = UCOL_GREATER;
452                         } else {
453                                 res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
454                         }
455                 }
456                 break;
457         case LANG_ENGLISH:
458         default:
459                 if (__isalpha(*src_uni) && !__isalpha(*dest_uni)) {
460                         res = UCOL_LESS;
461                 } else if (!__isalpha(*src_uni) && __isalpha(*dest_uni)) {
462                         res = UCOL_GREATER;
463                 } else {
464                         res = ucol_strcoll(s_info.coll, (UChar *)src_uni, len, (UChar *)dest_uni, len);
465                 }
466         }
467
468         free(src_uni);
469         free(dest_uni);
470
471         switch (res) {
472         case UCOL_LESS:
473                 return -1;
474
475         case UCOL_EQUAL:
476                 if (src_len > dest_len) {
477                         return 1;
478                 } else if (src_len == dest_len) {
479                         return 0;
480                 }
481
482                 return -1;
483
484         case UCOL_GREATER:
485                 return 1;
486
487         default:
488                 LOCKOPTIONS_DBG("%s ? %s\n", src, dest);
489                 return 0;
490         }
491 }
492
493 HAPI int ucol_fini(void)
494 {
495         if (s_info.coll) {
496                 ucol_close(s_info.coll);
497                 s_info.coll = NULL;
498         }
499         return 0;
500 }
501
502 HAPI const int ucol_current_lang(void)
503 {
504         return s_info.lang;
505 }
506
507 /* End of a file */