1 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
4 * Smart Common Input Method
6 * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
7 * Copyright (c) 2012-2015 Samsung Electronics Co., Ltd.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this program; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23 * Boston, MA 02111-1307 USA
25 * Modifications by Samsung Electronics Co., Ltd.
26 * 1. Add time and logs functions for performance profile
28 * $Id: scim_utility.cpp,v 1.48.2.5 2006/11/02 04:11:51 suzhe Exp $
31 #define Uses_SCIM_UTILITY
32 #define Uses_SCIM_CONFIG_PATH
42 #include <sys/types.h>
50 #include <sys/times.h>
53 #include "scim_private.h"
59 #define LOG_TAG "ISF_UTILITY"
64 utf8_mbtowc (ucs4_t *pwc, const unsigned char *src, int src_len)
69 unsigned char c = src [0];
74 } else if (c < 0xc2) {
76 } else if (c < 0xe0) {
79 unsigned char utf8_x1 = src [1] ^ 0x80;
82 *pwc = ((ucs4_t) (c & 0x1f) << 6)
85 } else if (c < 0xf0) {
88 unsigned char utf8_x1 = src[1] ^ 0x80;
89 unsigned char utf8_x2 = src[2] ^ 0x80;
90 if (!((utf8_x1 | utf8_x2) < 0x40
91 && (c >= 0xe1 || src [1] >= 0xa0)))
93 *pwc = ((ucs4_t) (c & 0x0f) << 12)
94 | ((ucs4_t) (utf8_x1) << 6)
97 } else if (c < 0xf8) {
100 unsigned char utf8_x1 = src[1] ^ 0x80;
101 unsigned char utf8_x2 = src[2] ^ 0x80;
102 unsigned char utf8_x3 = src[3] ^ 0x80;
103 if (!((utf8_x1 | utf8_x2 | utf8_x3) < 0x40
104 && (c >= 0xf1 || src [1] >= 0x90)))
106 *pwc = ((ucs4_t) (c & 0x07) << 18)
107 | ((ucs4_t) (utf8_x1) << 12)
108 | ((ucs4_t) (utf8_x2) << 6)
109 | (ucs4_t) (utf8_x3);
111 } else if (c < 0xfc) {
113 return RET_TOOFEW(0);
114 unsigned char utf8_x1 = src[1] ^ 0x80;
115 unsigned char utf8_x2 = src[2] ^ 0x80;
116 unsigned char utf8_x3 = src[3] ^ 0x80;
117 unsigned char utf8_x4 = src[4] ^ 0x80;
118 if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4) < 0x40
119 && (c >= 0xf9 || src [1] >= 0x88)))
121 *pwc = ((ucs4_t) (c & 0x03) << 24)
122 | ((ucs4_t) (utf8_x1) << 18)
123 | ((ucs4_t) (utf8_x2) << 12)
124 | ((ucs4_t) (utf8_x3) << 6)
125 | (ucs4_t) (utf8_x4);
127 } else if (c < 0xfe) {
129 return RET_TOOFEW(0);
130 unsigned char utf8_x1 = src[1] ^ 0x80;
131 unsigned char utf8_x2 = src[2] ^ 0x80;
132 unsigned char utf8_x3 = src[3] ^ 0x80;
133 unsigned char utf8_x4 = src[4] ^ 0x80;
134 unsigned char utf8_x5 = src[5] ^ 0x80;
135 if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4 | utf8_x5) < 0x40
136 && (c >= 0xfd || src [1] >= 0x84)))
138 *pwc = ((ucs4_t) (c & 0x01) << 30)
139 | ((ucs4_t) (utf8_x1) << 24)
140 | ((ucs4_t) (utf8_x2) << 18)
141 | ((ucs4_t) (utf8_x3) << 12)
142 | ((ucs4_t) (utf8_x4) << 6)
143 | (ucs4_t) (utf8_x5);
150 utf8_wctomb (unsigned char *dest, ucs4_t wc, int dest_size)
155 unsigned int _wc = wc;
158 else if (_wc < 0x800)
160 else if (_wc < 0x10000)
162 else if (_wc < 0x200000)
164 else if (_wc < 0x4000000)
166 else if (_wc <= 0x7fffffff)
171 if (dest_size < count)
173 switch (count) { /* note: code falls through cases! */
174 case 6: dest [5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
175 case 5: dest [4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
176 case 4: dest [3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
177 case 3: dest [2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
178 case 2: dest [1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
179 case 1: dest [0] = wc;
185 utf8_read_wchar (std::istream &is)
187 unsigned char utf8[5] = {0};
188 unsigned char utf8_x_;
190 is.read ((char*)(&utf8_x_), sizeof(unsigned char)); // reducing utf8 char sequence to ucs4 convertations
191 if (utf8_x_ < 0x80) {
192 return (ucs4_t)utf8_x_;
193 } else if (utf8_x_ < 0xc2) {
195 } else if (utf8_x_ < 0xe0) {
196 unsigned char utf8_x1;
197 is.read ((char*)(&utf8_x1), sizeof(unsigned char));
201 return ((ucs4_t) (utf8_x_ & 0x1f) << 6)
202 | (ucs4_t) (utf8_x1);
203 } else if (utf8_x_ < 0xf0) {
204 is.read ((char*)(&utf8[0]), 2*sizeof(unsigned char));
205 unsigned char utf8_x1 = utf8[0] ^ 0x80;
206 unsigned char utf8_x2 = utf8[1] ^ 0x80;
207 if (!((utf8_x1 | utf8_x2) < 0x40
208 && (utf8_x_ >= 0xe1 || utf8[0] >= 0xa0)))
210 return ((ucs4_t) (utf8_x_ & 0x0f) << 12)
211 | ((ucs4_t) (utf8_x1) << 6)
212 | (ucs4_t) (utf8_x2);
213 } else if (utf8_x_ < 0xf8) {
214 is.read ((char*)(&utf8[0]), 3*sizeof(unsigned char));
215 unsigned char utf8_x1 = utf8[0] ^ 0x80;
216 unsigned char utf8_x2 = utf8[1] ^ 0x80;
217 unsigned char utf8_x3 = utf8[2] ^ 0x80;
218 if (!((utf8_x1 | utf8_x2 | utf8_x3) < 0x40
219 && (utf8_x_ >= 0xf1 || utf8[0] >= 0x90)))
221 return ((ucs4_t) (utf8_x_ & 0x07) << 18)
222 | ((ucs4_t) (utf8_x1) << 12)
223 | ((ucs4_t) (utf8_x2) << 6)
224 | (ucs4_t) (utf8_x3);
225 } else if (utf8_x_ < 0xfc) {
226 is.read ((char*)(&utf8[0]), 4*sizeof(unsigned char));
227 unsigned char utf8_x1 = utf8[0] ^ 0x80;
228 unsigned char utf8_x2 = utf8[1] ^ 0x80;
229 unsigned char utf8_x3 = utf8[2] ^ 0x80;
230 unsigned char utf8_x4 = utf8[3] ^ 0x80;
231 if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4) < 0x40
232 && (utf8_x_ >= 0xf9 || utf8[0] >= 0x88)))
234 return ((ucs4_t) (utf8_x_ & 0x03) << 24)
235 | ((ucs4_t) (utf8_x1) << 18)
236 | ((ucs4_t) (utf8_x2) << 12)
237 | ((ucs4_t) (utf8_x3) << 6)
238 | (ucs4_t) (utf8_x4);
239 } else if (utf8_x_ < 0xfe) {
240 is.read ((char*)(&utf8[0]), 5*sizeof(unsigned char));
241 unsigned char utf8_x1 = utf8[0] ^ 0x80;
242 unsigned char utf8_x2 = utf8[1] ^ 0x80;
243 unsigned char utf8_x3 = utf8[2] ^ 0x80;
244 unsigned char utf8_x4 = utf8[3] ^ 0x80;
245 unsigned char utf8_x5 = utf8[4] ^ 0x80;
246 if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4 | utf8_x5) < 0x40
247 && (utf8_x_ >= 0xfd || utf8[0] >= 0x84)))
249 return ((ucs4_t) (utf8_x_ & 0x01) << 30)
250 | ((ucs4_t) (utf8_x1) << 24)
251 | ((ucs4_t) (utf8_x2) << 18)
252 | ((ucs4_t) (utf8_x3) << 12)
253 | ((ucs4_t) (utf8_x4) << 6)
254 | (ucs4_t) (utf8_x5);
260 utf8_read_wstring (std::istream &is, ucs4_t delim, bool rm_delim)
264 while ((wc = utf8_read_wchar (is)) > 0) {
277 utf8_write_wchar (std::ostream &os, ucs4_t wc)
279 unsigned char utf8[6];
282 if ((count=utf8_wctomb (utf8, wc, 6)) > 0)
283 os.write ((char*)utf8, (std::streamsize)(count * sizeof (unsigned char)));
289 utf8_write_wstring (std::ostream &os, const WideString & wstr)
291 for (unsigned int i=0; i<wstr.size (); ++i)
292 utf8_write_wchar (os, wstr [i]);
298 utf8_mbstowcs (const String & str)
305 const unsigned char *s = (const unsigned char *) str.c_str ();
307 while (sn < str.length () && *s != 0 &&
308 (un=utf8_mbtowc (&wc, s, str.length () - sn)) > 0) {
317 utf8_mbstowcs (const char *str, int len)
326 if (len < 0) len = strlen (str);
328 while (sn < ((unsigned int)len) && *str != 0 && (un=utf8_mbtowc (&wc, (const unsigned char *)str, len - sn)) > 0) {
338 utf8_wcstombs (const WideString & wstr)
344 for (unsigned int i = 0; i<wstr.size (); ++i) {
345 un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
347 str.append (utf8, un);
353 utf8_wcstombs (const ucs4_t *wstr, int len)
366 for (int i = 0; i < len; ++i) {
367 un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
369 str.append (utf8, un);
375 static String trim_blank (const String &str)
377 String::size_type begin, len;
379 begin = str.find_first_not_of (" \t\n\v");
381 if (begin == String::npos)
384 len = str.find_last_not_of (" \t\n\v") - begin + 1;
386 return str.substr (begin, len);
390 scim_validate_locale (const String& locale)
394 String last = String (setlocale (LC_CTYPE, 0));
396 if (setlocale (LC_CTYPE, locale.c_str ())) {
399 std::vector<String> vec;
400 if (scim_split_string_list (vec, locale, '.') == 2) {
401 if (isupper (vec[1][0])) {
402 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
403 *i = (char) tolower (*i);
405 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
406 *i = (char) toupper (*i);
408 if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ())) {
409 good = vec [0] + "." + vec[1];
414 setlocale (LC_CTYPE, last.c_str ());
420 scim_get_locale_encoding (const String& locale)
422 String last = String (setlocale (LC_CTYPE, 0));
425 if (setlocale (LC_CTYPE, locale.c_str ()))
426 encoding = String (nl_langinfo (CODESET));
428 std::vector<String> vec;
429 if (scim_split_string_list (vec, locale, '.') == 2) {
430 if (isupper (vec[1][0])) {
431 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
432 *i = (char) tolower (*i);
434 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
435 *i = (char) toupper (*i);
437 if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ()))
438 encoding = String (nl_langinfo (CODESET));
442 setlocale (LC_CTYPE, last.c_str ());
448 scim_get_locale_maxlen (const String& locale)
452 String last = String (setlocale (LC_CTYPE, 0));
454 if (setlocale (LC_CTYPE, locale.c_str ()))
459 setlocale (LC_CTYPE, last.c_str ());
464 scim_split_string_list (std::vector<String>& vec, const String& str, char delim)
469 String::const_iterator bg, ed;
473 if (str.empty ()) return 0;
478 while (bg != str.end () && ed != str.end ()) {
479 for (; ed != str.end (); ++ed) {
483 temp.assign (bg, ed);
484 temp = trim_blank (temp);
485 vec.push_back (temp);
488 if (ed != str.end ())
495 scim_combine_string_list (const std::vector<String>& vec, char delim)
498 for (std::vector<String>::const_iterator i = vec.begin (); i!=vec.end (); ++i) {
500 if (i+1 != vec.end ())
507 scim_if_wchar_ucs4_equal ()
509 if (sizeof (wchar_t) != sizeof (ucs4_t))
513 wchar_t wcbuf [2] = {0,0};
514 ucs4_t ucsbuf [2] = {0x4E00, 0x0001};
515 size_t wclen = 2 * sizeof (wchar_t);
516 size_t ucslen = 2 * sizeof (ucs4_t);
518 char *wcp = (char *) wcbuf;
519 ICONV_CONST char *ucsp = (ICONV_CONST char *) ucsbuf;
521 if (scim_is_little_endian ())
522 cd = iconv_open ("UCS-4LE", "wchar_t");
524 cd = iconv_open ("UCS-4BE", "wchar_t");
526 if (cd == (iconv_t) -1)
529 iconv (cd, &ucsp, &ucslen, &wcp, &wclen);
533 if (wcbuf [0] == (wchar_t) ucsbuf [0] &&
534 wcbuf [1] == (wchar_t) ucsbuf [1])
544 } __half_full_table [] = {
546 {0x0021, 0xFF01, 0x5E},
599 {0xFFA1, 0x3131, 30},
611 * convert a half width unicode char to full width char
614 scim_wchar_to_full_width (ucs4_t code)
617 while (__half_full_table [i].size) {
618 if (code >= __half_full_table [i].half &&
619 code < __half_full_table [i].half +
620 __half_full_table [i].size)
621 return __half_full_table [i].full +
622 (code - __half_full_table [i].half);
629 * convert a full width unicode char to half width char
632 scim_wchar_to_half_width (ucs4_t code)
635 while (__half_full_table [i].size) {
636 if (code >= __half_full_table [i].full &&
637 code < __half_full_table [i].full +
638 __half_full_table [i].size)
639 return __half_full_table [i].half +
640 (code - __half_full_table [i].full);
649 const char * home_dir = 0;
651 struct passwd *result;
652 char buf [2048] = {0,};
655 int ret = getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
658 if (ret != 0 || !result) {
659 LOGE ("Fail to getpwuid_r");
664 home_dir = pw.pw_dir;
666 home_dir = getenv ("HOME");
669 return String (home_dir);
675 scim_get_user_name ()
677 const char *user_name;
679 struct passwd *result;
680 char buf [2048] = {0,};
683 int ret = getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
686 if (ret != 0 || !result) {
687 LOGE ("Fail to getpwuid_r");
691 if (result && pw.pw_name) {
692 return String (pw.pw_name);
693 } else if ((user_name = getenv ("USER")) != NULL) {
694 return String (user_name);
699 snprintf (uid_str, 10, "%u", getuid ());
701 return String (uid_str);
705 scim_get_user_data_dir ()
707 String dir = scim_get_home_dir () + String ("/.config/.scim");
713 scim_get_current_locale ()
715 char *locale = setlocale (LC_CTYPE, 0);
717 if (locale) return String (locale);
721 EXAPI String scim_get_current_language ()
723 return scim_get_locale_language (scim_get_current_locale ());
727 scim_is_little_endian ()
730 return (*((char *)&endian) != 0);
734 scim_load_file (const String &filename, char **bufptr)
736 if (!filename.length ())
741 if (stat (filename.c_str (), &statbuf) < 0 ||
742 !S_ISREG (statbuf.st_mode) ||
747 return statbuf.st_size;
749 FILE *fp = fopen (filename.c_str (), "r");
756 if (feof (fp) != 0) {
767 *bufptr = new char [statbuf.st_size];
768 } catch (std::bad_alloc &e) {
773 size_t size = fread (*bufptr, 1, statbuf.st_size, fp);
786 scim_make_dir (const String &dir)
788 if (access (dir.c_str (), R_OK) != 0) {
789 std::vector <String> paths;
792 scim_split_string_list (paths, dir, SCIM_PATH_DELIM);
794 for (size_t i = 1; i < paths.size (); ++i) {
795 path += SCIM_PATH_DELIM_STRING + paths [i];
797 //Make the dir if it's not exist.
798 if (access (path.c_str (), R_OK) != 0) {
799 if (mkdir (path.c_str (), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
800 LOGE ("Can not create %s", path.c_str ());
804 if (access (path.c_str (), R_OK) != 0) {
805 LOGE ("Can not access %s", path.c_str ());
817 const char *normalized;
819 const char *untranslated;
820 const char *locale_suffix;
823 static __Language __languages [] = {
824 { "C", NULL, N_("English Keyboard"), NULL, NULL},
825 { "am_ET", NULL, N_("Amharic"), "አማርኛ", NULL },
826 { "ar", "ar", N_("Arabic"), "عربي", NULL },
827 { "ar_EG", NULL, N_("Arabic (Egypt)"), "العربية (مصر)", NULL },
828 { "ar_LB", NULL, N_("Arabic (Lebanon)"), "العربية (لبنان)", NULL },
829 { "ar_IL", NULL, N_("Arabic (Israel)"), "العربية", NULL },
830 { "as_IN", NULL, N_("Assamese"), "অসমীয়া", NULL},
831 { "az_AZ", NULL, N_("Azerbaijani"), "Azərbaycan", NULL },
832 { "be_BY", NULL, N_("Belarusian"), "Беларуская мова", NULL },
833 { "bg_BG", NULL, N_("Bulgarian"), "Български", NULL },
834 { "bn", "bn_BD", N_("Bengali"), "বাংলা", NULL },
835 { "bn_BD", NULL, N_("Bengali"), "বাংলা", NULL },
836 { "bn_IN", NULL, N_("Bengali (India)"), "বাংলা", NULL },
837 { "bo", NULL, N_("Tibetan"), "པོད་སྐད་", NULL },
838 { "bs_BA", NULL, N_("Bosnian"), "Bosanski", NULL },
839 { "ca_ES", NULL, N_("Catalan"), "Català", "@euro" },
840 { "cs_CZ", NULL, N_("Czech"), "čeština", NULL },
841 { "cy_GB", NULL, N_("Welsh"), "Cymraeg", NULL },
842 { "da_DK", NULL, N_("Danish"), "Dansk", "@euro" },
843 { "de_DE", NULL, N_("German"), "Deutsch", "@euro" },
844 { "dv_MV", NULL, N_("Divehi"), "ދިވެހިބަސް", NULL },
845 { "el_GR", NULL, N_("Greek"), "ελληνικά", NULL },
846 { "en" , NULL, N_("English"), "English", NULL },
847 { "en_AU", NULL, N_("English (Australian)"), "English (Australian)", NULL },
848 { "en_CA", NULL, N_("English (Canadian)"), "English (Canadian)", NULL },
849 { "en_GB", NULL, N_("English (United Kingdom)"), "English (United Kingdom)", ".iso885915" },
850 { "en_IE", NULL, N_("English (Ireland)"), "English (Ireland)", NULL },
851 { "en_US", NULL, N_("English (United States)"), "English (United States)", ".iso885915" },
852 { "eo", NULL, N_("Esperanto"), "Esperanto", NULL },
853 { "es", "es_ES", N_("Spanish"), "Español", NULL },
854 { "es_ES", NULL, N_("Spanish"), "Español", "@euro" },
855 { "es_MX", NULL, N_("Spanish (Mexico)"), "Español (Mexico)", NULL },
856 { "es_US", NULL, N_("Spanish (United States)"), "Español (United States)", NULL },
857 { "et_EE", NULL, N_("Estonian"), "Eesti", ".iso885915" },
858 { "eu_ES", NULL, N_("Basque"), "Euskara", "@euro" },
859 { "fa_IR", NULL, N_("Persian"), "فارسی", NULL },
860 { "fi_FI", NULL, N_("Finnish"), "Suomi", "@euro" },
861 { "fr_FR", NULL, N_("French"), "Français", "@euro" },
862 { "ga_IE", NULL, N_("Irish"), "Gaeilge", "@euro" },
863 { "gl_ES", NULL, N_("Galician"), "Galego", "@euro" },
864 { "gu_IN", NULL, N_("Gujarati"), "ગુજરાતી", NULL },
865 { "he_IL", NULL, N_("Hebrew"), "עברית", NULL },
866 { "hi_IN", NULL, N_("Hindi"), "हिंदी", NULL },
867 { "hr_HR", NULL, N_("Croatian"), "Hrvatski", NULL },
868 { "hu_HU", NULL, N_("Hungarian"), "Magyar", NULL },
869 { "hy_AM", NULL, N_("Armenian"), "Հայերէն", NULL },
870 { "ia" , NULL, N_("Interlingua"), "Interlingua", NULL },
871 { "id_ID", NULL, N_("Indonesian"), "Bahasa Indonesia", NULL },
872 { "is_IS", NULL, N_("Icelandic"), "íslenska", NULL },
873 { "it_IT", NULL, N_("Italian"), "Italiano", "@euro" },
874 { "iw_IL", NULL, N_("Hebrew"), "עברית", NULL },
875 { "ja_JP", NULL, N_("Japanese"), "日本語", ".EUC-JP,.SJIS,.eucJP" },
876 { "ka_GE", NULL, N_("Georgian"), "ქართული", NULL },
877 { "kk_KZ", NULL, N_("Kazakh"), "Қазақ", NULL },
878 { "km", NULL, N_("Cambodian"), "ភាសាខ្មែរ", NULL },
879 { "kn_IN", NULL, N_("Kannada"), "ಕನ್ನಡ", NULL },
880 { "ko_KR", NULL, N_("Korean"), "한국어", ".EUC-KR,.eucKR" },
881 { "lo", NULL, N_("Lao"), "لاوس", NULL },
882 { "lo_LA", NULL, N_("Laothian"), "ລາວ", NULL },
883 { "lt_LT", NULL, N_("Lithuanian"), "Lietuvių", NULL },
884 { "lv_LV", NULL, N_("Latvian"), "Latviešu", NULL },
885 { "mk_MK", NULL, N_("Macedonian"), "Македонски", NULL },
886 { "ml_IN", NULL, N_("Malayalam"), "മലയാളം", NULL },
887 { "mn_MN", NULL, N_("Mongolian"), "Монгол", NULL },
888 { "mr_IN", NULL, N_("Marathi"), "मराठी", NULL },
889 { "ms_MY", NULL, N_("Malay"), "Bahasa Melayu", NULL },
890 { "my_MM", NULL, N_("Burmese"), "မြန်မာဘာသာ", NULL },
891 { "ne_NP", NULL, N_("Nepali"), "नेपाली", NULL },
892 { "nl_NL", NULL, N_("Dutch"), "Nederlands", "@euro" },
893 { "nn_NO", NULL, N_("Norwegian (Nynorsk)"), "Norsk (Nynorsk)", NULL },
894 { "nb_NO", NULL, N_("Norwegian (Bokmal)"), "Norsk (Bokmål)", NULL },
895 { "or_IN", NULL, N_("Oriya"), "ଓଡ଼ିଆ", NULL },
896 { "pa_IN", NULL, N_("Punjabi"), "ਪੰਜਾਬੀ", NULL },
897 { "pl_PL", NULL, N_("Polish"), "Polski", NULL },
898 { "pt", "pt_PT", N_("Portuguese"), "Português", NULL },
899 { "pt_BR", NULL, N_("Portuguese (Brazil)"), "Português (Brasil)", NULL },
900 { "pt_PT", NULL, N_("Portuguese"), "Português", "@euro" },
901 { "ro_RO", NULL, N_("Romanian"), "Română", NULL },
902 { "ru_RU", NULL, N_("Russian"), "русский", ".koi8r" },
903 { "sd", "sd_IN", N_("Sindhi"), "ﺲﻧڌﻱ", NULL },
904 { "sd_IN", NULL, N_("Sindhi"), "सिन्धी", "@devanagari" },
905 { "si_IN", NULL, N_("Sinhala"), "සිංහල", NULL },
906 { "si_LK", NULL, N_("Sinhala"), "සිංහල", NULL },
907 { "sk_SK", NULL, N_("Slovak"), "Slovenský", NULL },
908 { "sl_SI", NULL, N_("Slovenian"), "Slovenščina", NULL },
909 { "sq_AL", NULL, N_("Albanian"), "Shqip", NULL },
910 { "sr", "sr_YU", N_("Serbian"), "Srpski", NULL },
911 { "sr_CS", NULL, N_("Serbian"), "Srpski", NULL },
912 { "sr_YU", NULL, N_("Serbian"), "Srpski", "@cyrillic" },
913 { "sv", "sv_SE", N_("Swedish"), "Svenska", NULL },
914 { "sv_FI", NULL, N_("Swedish (Finland)"), "Svenska (Finland)", "@euro" },
915 { "sv_SE", NULL, N_("Swedish"), "Svenska", ".iso885915" },
916 { "ta_IN", NULL, N_("Tamil"), "தமிழ்", NULL },
917 { "te_IN", NULL, N_("Telugu"), "తెలుగు", NULL },
918 { "th_TH", NULL, N_("Thai"), "ภาษาไทย", NULL },
919 { "tr_TR", NULL, N_("Turkish"), "Türkçe", NULL },
920 { "ug", NULL, N_("Uighur"), "ئۇيغۇر", NULL },
921 { "uk_UA", NULL, N_("Ukrainian"), "Українська", NULL },
922 { "ur_PK", NULL, N_("Urdu"), "اردو", NULL },
923 { "uz_UZ", NULL, N_("Uzbek"), "o'zbek tili", "@cyrillic" },
924 { "vi_VN", NULL, N_("Vietnamese"), "Tiếng Việt", ".tcvn" },
925 { "wa_BE", NULL, N_("Walloon"), "Walon", "@euro" },
926 { "yi" , "yi_US", N_("Yiddish"), "ייִדיש", NULL },
927 { "yi_US", NULL, N_("Yiddish"), "ייִדיש", NULL },
928 { "zh", "zh_CN", N_("Chinese"), "中文", NULL },
929 { "zh_CN", NULL, N_("Chinese (Simplified)"), "中文 (简体)", ".GB18030,.GBK,.GB2312,.eucCN" },
930 { "zh_HK", NULL, N_("Chinese (Hongkong)"), "中文 (香港)", NULL },
931 { "zh_SG", "zh_CN", N_("Chinese (Singapore)"), "中文 (新加坡)", ".GBK" },
932 { "zh_TW", NULL, N_("Chinese (Traditional_Taiwan)"), "中文 (台湾)", ".eucTW" },
934 { "nl_BE", NULL, N_("Dutch (Belgian)"), "Dutch (Belgian)", NULL },
935 { "en_NZ", NULL, N_("English (New Zealand)"), "English (New Zealand)", NULL },
936 { "en_ZA", NULL, N_("English (South Africa)"), "English (South Africa)", NULL },
937 { "en_JM", NULL, N_("English (Jamaica)"), "English (Jamaica)", NULL },
938 { "en_BZ", NULL, N_("English (Belize)"), "English (Belize)", NULL },
939 { "en_TT", NULL, N_("English (Trinidad)"), "English (Trinidad)", NULL },
940 { "en_ZW", NULL, N_("English (Zimbabwe)"), "English (Zimbabwe)", NULL },
941 { "en_PH", NULL, N_("English (Philippines)"), "English (Philippines)", NULL },
942 { "fr_BE", NULL, N_("French (Belgian)"), "Français (Belgian)", NULL },
943 { "fr_CA", NULL, N_("French (Canadian)"), "Français (Canada)", NULL },
944 { "fr_CH", NULL, N_("French (Swiss)"), "Français (Suisse)", NULL },
945 { "fr_LU", NULL, N_("French (Luxembourg)"), "Français (Luxembourg)", NULL },
946 { "fr_MC", NULL, N_("French (Monaco)"), "Français (Monaco)", NULL },
947 { "de_CH", NULL, N_("German (Swiss)"), "Deutsch (Schweiz)", NULL },
948 { "de_AT", NULL, N_("German (Austrian)"), "Deutsch (Österreich)", NULL },
949 { "de_LU", NULL, N_("German (Luxembourg)"), "Deutsch (Luxembourg)", NULL },
950 { "de_LI", NULL, N_("German (Liechtenstein)"), "Deutsch (Liechtenstein)", NULL },
951 { "it_CH", NULL, N_("Italian (Swiss)"), "italiano (Svizzera)", NULL },
952 { "es_GT", NULL, N_("Spanish (Guatemala)"), "español (Guatemala)", NULL },
953 { "es_CR", NULL, N_("Spanish (Costa Rica)"), "español (Costa Rica)", NULL },
954 { "es_PA", NULL, N_("Spanish (Panama)"), "español (Panamá)", NULL },
955 { "es_DO", NULL, N_("Spanish (Dominican Republic)"), "español (República Dominicana)", NULL },
956 { "es_VE", NULL, N_("Spanish (Venezuela)"), "español (Venezuela)", NULL },
957 { "es_CO", NULL, N_("Spanish (Colombia)"), "español (Colombia)", NULL },
958 { "es_PE", NULL, N_("Spanish (Peru)"), "español (Perú)", NULL },
959 { "es_AR", NULL, N_("Spanish (Argentina)"), "español (Argentina)", NULL },
960 { "es_EC", NULL, N_("Spanish (Ecuador)"), "español (Ecuador)", NULL },
961 { "es_CL", NULL, N_("Spanish (Chile)"), "español (Chile)", NULL },
962 { "es_UY", NULL, N_("Spanish (Uruguay)"), "español (Uruguay)", NULL },
963 { "es_PY", NULL, N_("Spanish (Paraguay)"), "español (Paraguay)", NULL },
964 { "es_BO", NULL, N_("Spanish (Bolivia)"), "español (Bolivia)", NULL },
965 { "es_SV", NULL, N_("Spanish (El Salvador)"), "español (El Salvador)", NULL },
966 { "es_HN", NULL, N_("Spanish (Honduras)"), "español (Honduras)", NULL },
967 { "es_NI", NULL, N_("Spanish (Nicaragua)"), "español (Nicaragua)", NULL },
968 { "es_PR", NULL, N_("Spanish (Puerto Rico)"), "español (Puerto Rico)", NULL },
969 { "af_AF", NULL, N_("Afrikaans"), "Afrikaans", NULL },
970 { "ms_BN", NULL, N_("Malay (Brunei Darussalam)"), "Bahasa Melayu (Brunei)", NULL },
971 { "no_NO", NULL, N_("Norwegian"), "Norsk", NULL },
972 { "sr_RS", NULL, N_("Serbian (Latin)"), "Srpski (latinica)", NULL },
973 { "sr_RS", NULL, N_("Serbian (Cyrillic)"), "Srpski (ćirilica)", NULL },
974 { "zh_MO", NULL, N_("Chinese (Macau)"), "Chinese (Macau)", NULL },
975 { "ar_SA", NULL, N_("Arabic (Saudi Arabia)"), "العربية (المملكة العربية السعودية)", NULL },
976 { "ar_IQ", NULL, N_("Arabic (Iraq)"), "العربية (العراق)", NULL },
977 { "ar_LY", NULL, N_("Arabic (Libya)"), "العربية (ليبيا)", NULL },
978 { "ar_DZ", NULL, N_("Arabic (Algeria)"), "العربية (الجزائر)", NULL },
979 { "ar_MA", NULL, N_("Arabic (Morocco)"), "العربية (المغرب)", NULL },
980 { "ar_TN", NULL, N_("Arabic (Tunisia)"), "العربية (تونس)", NULL },
981 { "ar_OM", NULL, N_("Arabic (Oman)"), "العربية (عُمان)", NULL },
982 { "ar_YE", NULL, N_("Arabic (Yemen)"), "العربية (اليمن)", NULL },
983 { "ar_SY", NULL, N_("Arabic (Syria)"), "العربية (سوريا)", NULL },
984 { "ar_JO", NULL, N_("Arabic (Jordan)"), "العربية (الأردن)", NULL },
985 { "ar_KW", NULL, N_("Arabic (Kuwait)"), "العربية (الكويت)", NULL },
986 { "ar_AE", NULL, N_("Arabic (UAE)"), "العربية (الإمارات العربية المتحدة)", NULL },
987 { "ar_BH", NULL, N_("Arabic (Bahrain)"), "العربية (البحرين)", NULL },
988 { "ar_QA", NULL, N_("Arabic (Qatar)"), "العربية (قطر)", NULL },
989 { "az_IR", NULL, N_("Azerbaijani"), "Azərbaycan", NULL },
990 { "ha_BJ", NULL, N_("Hausa"), "Hausa", NULL },
991 { "cy_UK", NULL, N_("Welsh"), "Cymraeg", NULL },
992 { "xh_ZA", NULL, N_("Xhosa"), "isiXhosa", NULL },
993 { "yo_NG", NULL, N_("Yoruba"), "Èdè Yorùbá", NULL },
994 { "zu_ZA", NULL, N_("Zulu"), "isiZulu", NULL },
995 { "hg_IN", NULL, N_("Hinglish"), "Hinglish", NULL },
996 { "su_ID", NULL, N_("Sundanese"), "Basa Sunda", NULL },
997 { "tl_PH", NULL, N_("Tagalog"), "Tagalog", NULL },
998 { "af_ZA", NULL, N_("Afrikaans"), "Afrikaans", NULL },
999 { "jv_ID", NULL, N_("Javanese"), "Basa Jawa", NULL },
1000 { "km_KH", NULL, N_("Khmer"), "ខ្មែរ", NULL },
1001 { "fil", NULL, N_("Filipino"), "Filipino", NULL },
1002 { "my", NULL, N_("Myanmar"), "ماينمار", NULL },
1003 { "or", NULL, N_("Odia"), "ଓଡ଼ିଆ", NULL },
1004 { "es_LA", NULL, N_("Spanish (Latin America)"), "Español (América Latina)", NULL },
1006 { "", "", "", NULL, NULL }
1009 class __LanguageLess
1012 bool operator () (const __Language &lhs, const __Language &rhs) const {
1013 return strcmp (lhs.code, rhs.code) < 0;
1016 bool operator () (const __Language &lhs, const String &rhs) const {
1017 return strcmp (lhs.code, rhs.c_str ()) < 0;
1020 bool operator () (const String &lhs, const __Language &rhs) const {
1021 return strcmp (lhs.c_str (), rhs.code) < 0;
1025 static bool language_sorted = false;
1028 __find_language (const String &lang)
1030 if (!language_sorted) {
1031 language_sorted = true;
1032 for (int loop = 0; ((unsigned int)loop) < sizeof(__languages) / sizeof(__Language) - 1; loop++) {
1033 for (int innerLoop = loop + 1; ((unsigned int)innerLoop) < sizeof(__languages) / sizeof(__Language) - 1; innerLoop++) {
1034 if (strcmp (__languages[loop].code, __languages[innerLoop].code) > 0) {
1035 __Language temp = __languages[innerLoop];
1036 __languages[innerLoop] = __languages[loop];
1037 __languages[loop] = temp;
1043 static __Language *langs_begin = __languages;
1044 static __Language *langs_end = __languages + sizeof (__languages) / sizeof (__Language) - 1;
1046 String nlang = lang;
1047 bool contry_code = false;
1049 // Normalize the language name.
1050 for (String::iterator it = nlang.begin (); it != nlang.end (); ++it) {
1051 if (*it == '-' || *it == '_') {
1054 } else if (contry_code) {
1055 *it = toupper (*it);
1057 *it = tolower (*it);
1061 __Language *result = std::lower_bound (langs_begin, langs_end, nlang, __LanguageLess ());
1063 if (result != langs_end) {
1064 if (strncmp (result->code, nlang.c_str (), strlen (result->code)) == 0 ||
1065 (strncmp (result->code, nlang.c_str (), nlang.length ()) == 0 &&
1066 strncmp (result->code, (result+1)->code, nlang.length ()) != 0))
1074 scim_get_language_name (const String &lang)
1076 return String (_(scim_get_language_name_english (lang).c_str ()));
1080 scim_get_language_name_english (const String &lang)
1082 __Language *result = __find_language (lang);
1085 return String (result->name);
1087 return String ("Other");
1091 scim_get_language_name_untranslated (const String &lang)
1093 __Language *result = __find_language (lang);
1096 if (result->untranslated)
1097 return String (result->untranslated);
1099 return String (_(result->name));
1102 return String (_("Other"));
1106 scim_get_language_locales (const String &lang)
1108 __Language *result = __find_language (lang);
1110 std::vector<String> locales;
1115 if (strlen (result->code) < 5 && result->normalized)
1116 result = __find_language (result->normalized);
1119 good = scim_validate_locale (String (result->code) + ".UTF-8");
1121 if (good.length ()) locales.push_back (good);
1123 if (result && result->locale_suffix) {
1124 std::vector<String> suffixes;
1126 scim_split_string_list (suffixes, result->locale_suffix, ',');
1127 for (size_t i = 0; i < suffixes.size (); ++ i) {
1128 good = scim_validate_locale (String (result->code) + suffixes [i]);
1129 if (good.length ()) locales.push_back (good);
1134 good = scim_validate_locale (result->code);
1136 if (good.length ()) locales.push_back (good);
1139 return scim_combine_string_list (locales, ',');
1143 scim_get_locale_language (const String &locale)
1145 if (locale.length () == 0) return String ();
1147 String str = locale.substr (0, locale.find ('.'));
1148 return scim_validate_language (str.substr (0, str.find ('@')));
1152 scim_validate_language (const String &lang)
1154 __Language *result = __find_language (lang);
1157 return String (result->code);
1159 // Add prefix ~ to let other become the last item when sorting.
1160 return String ("~other");
1164 scim_get_normalized_language (const String &lang)
1166 __Language *result = __find_language (lang);
1169 if (result->normalized) return String (result->normalized);
1170 else return String (result->code);
1173 // Add prefix ~ to let other become the last item when sorting.
1174 //return String ("~other");
1175 return String ("en");
1178 #ifndef SCIM_LAUNCHER
1179 #define SCIM_LAUNCHER (SCIM_LIBEXECDIR "/scim-launcher")
1182 EXAPI int scim_launch (bool daemon,
1183 const String &config,
1184 const String &imengines,
1185 const String &frontend,
1186 char * const argv [])
1188 if (!config.length () || !imengines.length () || !frontend.length ())
1191 int i, new_argc = 0;
1192 char *new_argv [40];
1194 new_argv [new_argc ++] = strdup (SCIM_LAUNCHER);
1197 new_argv [new_argc ++] = strdup ("-d");
1199 new_argv [new_argc ++] = strdup ("-c");
1200 new_argv [new_argc ++] = strdup (config.c_str ());
1201 new_argv [new_argc ++] = strdup ("-e");
1202 new_argv [new_argc ++] = strdup (imengines.c_str ());
1203 new_argv [new_argc ++] = strdup ("-f");
1204 new_argv [new_argc ++] = strdup (frontend.c_str ());
1207 for (i = 0; argv [i] && new_argc < 39 ; ++i, ++new_argc)
1208 new_argv [new_argc] = strdup (argv [i]);
1211 new_argv [new_argc] = 0;
1215 child_pid = fork ();
1217 ISF_SAVE_LOG ("ppid: %d, fork result : %d, user %s", getppid (), child_pid, scim_get_user_name ().c_str ());
1220 if (child_pid < 0) {
1221 for (i = 0; i < new_argc; ++i) {
1223 free (new_argv [i]);
1224 new_argv [i] = NULL;
1230 // In child process, start scim-launcher.
1231 if (child_pid == 0) {
1232 int ret = execv (SCIM_LAUNCHER, new_argv);
1233 for (i = 0; i < new_argc; ++i) {
1235 free (new_argv [i]);
1236 new_argv [i] = NULL;
1242 // In parent process, wait the child exit.
1244 for (i = 0; i < new_argc; ++i) {
1246 free (new_argv [i]);
1247 new_argv [i] = NULL;
1254 ret_pid = waitpid (child_pid, &status, 0);
1256 if (ret_pid == child_pid && WIFEXITED(status))
1257 return WEXITSTATUS(status);
1262 #ifndef SCIM_PANEL_PROGRAM
1263 #define SCIM_PANEL_PROGRAM (SCIM_BINDIR "/scim-panel-gtk")
1266 EXAPI int scim_launch_panel (bool daemon,
1267 const String &config,
1268 const String &display,
1269 char * const argv [])
1271 if (!config.length ())
1274 String panel_program = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM, String (SCIM_PANEL_PROGRAM));
1276 if (!panel_program.length ())
1277 panel_program = String (SCIM_PANEL_PROGRAM);
1279 if (panel_program [0] != SCIM_PATH_DELIM) {
1280 panel_program = String (SCIM_BINDIR) +
1281 String (SCIM_PATH_DELIM_STRING) +
1285 //if the file is not exist or is not executable, fallback to default
1286 if (access (panel_program.c_str (), X_OK) != 0)
1287 panel_program = String (SCIM_PANEL_PROGRAM);
1289 int i, new_argc = 0;
1290 char *new_argv [80];
1292 new_argv [new_argc ++] = strdup (panel_program.c_str ());
1294 if (display.length() > 0) {
1295 new_argv [new_argc ++] = strdup ("--display");
1296 new_argv [new_argc ++] = strdup (display.c_str ());
1299 new_argv [new_argc ++] = strdup ("-c");
1300 new_argv [new_argc ++] = strdup (config.c_str ());
1303 new_argv [new_argc ++] = strdup ("-d");
1306 for (i = 0; argv [i] && new_argc < 79; ++i, ++new_argc)
1307 new_argv [new_argc] = strdup (argv [i]);
1310 new_argv [new_argc] = 0;
1314 child_pid = fork ();
1316 ISF_SAVE_LOG ("ppid : %d fork result : %d", getppid (), child_pid);
1319 if (child_pid < 0) {
1320 for (i = 0; i < new_argc; ++i) {
1322 free (new_argv [i]);
1323 new_argv [i] = NULL;
1329 // In child process, start scim-launcher.
1330 if (child_pid == 0) {
1331 int ret = execv (panel_program.c_str (), new_argv);
1332 for (i = 0; i < new_argc; ++i) {
1334 free (new_argv [i]);
1335 new_argv [i] = NULL;
1341 // In parent process, wait the child exit.
1343 for (i = 0; i < new_argc; ++i) {
1345 free (new_argv [i]);
1346 new_argv [i] = NULL;
1353 ret_pid = waitpid (child_pid, &status, 0);
1355 if (ret_pid == child_pid && WIFEXITED(status))
1356 return WEXITSTATUS(status);
1362 scim_usleep (unsigned int usec)
1364 if (usec == 0) return;
1367 struct timespec req, rem;
1369 req.tv_sec = (long int)usec / 1000000;
1370 req.tv_nsec = ((long int)usec % 1000000) * 1000;
1372 while (nanosleep (&req, &rem) == -1 && errno == EINTR && (rem.tv_sec != 0 || rem.tv_nsec != 0))
1375 unsigned int sec = usec / 1000000;
1378 for (unsigned int i = 0; i < sec; ++i)
1383 unsigned int sec = usec / 1000000;
1385 sleep (sec ? sec : 1);
1389 EXAPI void scim_daemon ()
1392 LOGD ("ppid:%d calling daemon()", getppid ());
1394 if (daemon (0, 0) == -1)
1395 std::cerr << "Error to make SCIM into a daemon!\n";
1397 LOGD ("ppid:%d daemon() called", getppid ());
1405 std::cerr << "Error to make SCIM into a daemon!\n";
1407 } else if (id > 0) {
1411 ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1415 std::cerr << "Error to make SCIM into a daemon!\n";
1417 } else if (id > 0) {
1421 ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1427 EXAPI void isf_save_log (const char *fmt, ...)
1429 char buf[1024] = {0};
1433 vsnprintf (buf, sizeof (buf), fmt, ap);
1436 const int MAX_LOG_FILE_SIZE = 12 * 1024; /* 12KB */
1438 static bool size_exceeded = false;
1439 static struct stat st;
1440 if (!size_exceeded) {
1441 String strLogFile = scim_get_user_data_dir () + String (SCIM_PATH_DELIM_STRING) + String ("isf.log");
1442 int ret = stat(strLogFile.c_str(), &st);
1443 if (ret == 0 || (ret == -1 && errno == ENOENT)) {
1444 if (st.st_size < MAX_LOG_FILE_SIZE && !scim_is_symlink(strLogFile.c_str ())) {
1445 std::ofstream isf_log_file (strLogFile.c_str (), std::ios::app);
1446 isf_log_file << buf << std::endl;
1447 isf_log_file.flush ();
1449 size_exceeded = true;
1457 EXAPI bool scim_is_symlink (const String filename)
1460 if (lstat(filename.c_str (), &info) < 0) {
1462 LOGE("lstat failed. %s", strerror_r (errno, buf_err, sizeof (buf_err)));
1466 return S_ISLNK(info.st_mode);
1469 static struct timeval _t0 = {0, 0};
1470 static struct timeval _t1;
1472 static clock_t _p_t0;
1473 static clock_t _p_t1;
1475 void ISF_PROF_DEBUG_TIME_BEGIN ()
1479 _p_t0 = times (&tms);
1482 /* Measure elapsed time */
1483 void ISF_PROF_DEBUG_TIME_END (char const* format, char const* func, int line)
1487 static long clktck = 0;
1490 if ((clktck = sysconf (_SC_CLK_TCK)) < 0)
1493 _p_t1 = times (&tms);
1495 etime = (_p_t1 - _p_t0) / (double) clktck;
1497 printf (mzc_red "[Format:%s][Func:%s][Line:%d]" mzc_normal "\n", format, func, line);
1498 printf (mzc_red "[T:%ld][E:%f]" mzc_normal " ", _p_t1, etime);
1503 /* Measure elapsed time */
1504 void ISF_PROF_DEBUG_TIME (char const* func, int line, char const* str)
1508 if (_t0.tv_sec == 0 && _t0.tv_usec == 0) {
1509 gettimeofday (&_t0, NULL);
1513 gettimeofday (&_t1, NULL);
1515 if (_t0.tv_usec != 0) {
1516 etime = ((_t1.tv_sec * 1000000 + _t1.tv_usec) - (_t0.tv_sec * 1000000 + _t0.tv_usec))/1000000.0;
1519 printf (mzc_red "[%s:%04d] [T:%ld][E:%f] %s " mzc_normal " \n", func, line, (_t1.tv_sec * 1000000 + _t1.tv_usec), etime, str);
1526 EXAPI void gettime (clock_t clock_start, const char* str)
1529 struct tms tiks_buf;
1530 double clock_tiks = (double)sysconf (_SC_CLK_TCK);
1531 clock_t times_tiks = times (&tiks_buf);
1532 double times_secs = (double)(times_tiks - clock_start) / clock_tiks;
1533 double utime = (double)tiks_buf.tms_utime / clock_tiks;
1534 double stime = (double)tiks_buf.tms_stime / clock_tiks;
1535 printf (mzc_red "%s Times: %.3f \t User: %.3f \t System: %.3f " mzc_normal "\n", str, (double)times_secs, (double)utime , (double)stime);
1542 vi:ts=4:ai:nowrap:expandtab