Update package version to 9.0.14
[platform/core/uifw/isf.git] / ism / src / scim_utility.cpp
1 /* ISF is based on SCIM 1.4.7 and extended for supporting more mobile fitable. */
2
3 /*
4  * Smart Common Input Method
5  *
6  * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
7  * Copyright (c) 2012-2015 Samsung Electronics Co., Ltd.
8  *
9  *
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.
14  *
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.
19  *
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
24  *
25  * Modifications by Samsung Electronics Co., Ltd.
26  * 1. Add time and logs functions for performance profile
27  *
28  * $Id: scim_utility.cpp,v 1.48.2.5 2006/11/02 04:11:51 suzhe Exp $
29  */
30
31 #define Uses_SCIM_UTILITY
32 #define Uses_SCIM_CONFIG_PATH
33 #define Uses_C_LOCALE
34 #define Uses_C_ICONV
35 #define Uses_C_STDLIB
36 #define Uses_C_STRING
37
38 #include <langinfo.h>
39 #include <pwd.h>
40 #include <dirent.h>
41 #include <ctype.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <time.h>
48 #include <errno.h>
49 #include <sys/time.h>
50 #include <sys/times.h>
51 #include <dlog.h>
52
53 #include "scim_private.h"
54 #include "scim.h"
55
56 #ifdef LOG_TAG
57 # undef LOG_TAG
58 #endif
59 #define LOG_TAG     "ISF_UTILITY"
60
61 namespace scim {
62
63 EXAPI int
64 utf8_mbtowc (ucs4_t *pwc, const unsigned char *src, int src_len)
65 {
66     if (!pwc)
67         return 0;
68
69     unsigned char c = src [0];
70
71     if (c < 0x80) {
72         *pwc = c;
73         return 1;
74     } else if (c < 0xc2) {
75         return RET_ILSEQ;
76     } else if (c < 0xe0) {
77         if (src_len < 2)
78             return RET_TOOFEW(0);
79         unsigned char utf8_x1 = src [1] ^ 0x80;
80         if (utf8_x1 >= 0x40)
81             return RET_ILSEQ;
82         *pwc = ((ucs4_t) (c & 0x1f) << 6)
83                  | (ucs4_t) utf8_x1;
84         return 2;
85     } else if (c < 0xf0) {
86         if (src_len < 3)
87             return RET_TOOFEW(0);
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)))
92             return RET_ILSEQ;
93         *pwc = ((ucs4_t) (c & 0x0f) << 12)
94                  | ((ucs4_t) (utf8_x1) << 6)
95                  | (ucs4_t) (utf8_x2);
96         return 3;
97     } else if (c < 0xf8) {
98         if (src_len < 4)
99             return RET_TOOFEW(0);
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)))
105             return RET_ILSEQ;
106         *pwc = ((ucs4_t) (c & 0x07) << 18)
107                  | ((ucs4_t) (utf8_x1) << 12)
108                  | ((ucs4_t) (utf8_x2) << 6)
109                  | (ucs4_t) (utf8_x3);
110         return 4;
111     } else if (c < 0xfc) {
112         if (src_len < 5)
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)))
120             return RET_ILSEQ;
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);
126         return 5;
127     } else if (c < 0xfe) {
128         if (src_len < 6)
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)))
137             return RET_ILSEQ;
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);
144         return 6;
145     } else
146         return RET_ILSEQ;
147 }
148
149 EXAPI int
150 utf8_wctomb (unsigned char *dest, ucs4_t wc, int dest_size)
151 {
152     if (!dest)
153         return 0;
154     int count;
155     unsigned int _wc = wc;
156     if (_wc < 0x80)
157         count = 1;
158     else if (_wc < 0x800)
159         count = 2;
160     else if (_wc < 0x10000)
161         count = 3;
162     else if (_wc < 0x200000)
163         count = 4;
164     else if (_wc < 0x4000000)
165         count = 5;
166     else if (_wc <= 0x7fffffff)
167         count = 6;
168     else
169         return RET_ILSEQ;
170
171     if (dest_size < count)
172         return RET_TOOSMALL;
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;
180     }
181     return count;
182 }
183
184 EXAPI ucs4_t
185 utf8_read_wchar (std::istream &is)
186 {
187     unsigned char utf8[5] = {0};
188     unsigned char utf8_x_;
189
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) {
194         return 0;
195     } else if (utf8_x_ < 0xe0) {
196         unsigned char utf8_x1;
197         is.read ((char*)(&utf8_x1), sizeof(unsigned char));
198         utf8_x1 ^= 0x80;
199         if (utf8_x1 >= 0x40)
200             return 0;
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)))
209             return 0;
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)))
220             return 0;
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)))
233             return 0;
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)))
248             return 0;
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);
255     }
256     return 0;
257 }
258
259 EXAPI WideString
260 utf8_read_wstring (std::istream &is, ucs4_t delim, bool rm_delim)
261 {
262     WideString str;
263     ucs4_t wc;
264     while ((wc = utf8_read_wchar (is)) > 0) {
265         if (wc != delim)
266             str.push_back (wc);
267         else {
268             if (!rm_delim)
269                 str.push_back (wc);
270             break;
271         }
272     }
273     return str;
274 }
275
276 EXAPI std::ostream &
277 utf8_write_wchar (std::ostream &os, ucs4_t wc)
278 {
279     unsigned char utf8[6];
280     int count = 0;
281
282     if ((count=utf8_wctomb (utf8, wc, 6)) > 0)
283         os.write ((char*)utf8, (std::streamsize)(count * sizeof (unsigned char)));
284
285     return os;
286 }
287
288 EXAPI std::ostream &
289 utf8_write_wstring (std::ostream &os, const WideString & wstr)
290 {
291     for (unsigned int i=0; i<wstr.size (); ++i)
292         utf8_write_wchar (os, wstr [i]);
293
294     return os;
295 }
296
297 EXAPI WideString
298 utf8_mbstowcs (const String & str)
299 {
300     WideString wstr;
301     ucs4_t wc;
302     unsigned int sn = 0;
303     int un = 0;
304
305     const unsigned char *s = (const unsigned char *) str.c_str ();
306
307     while (sn < str.length () && *s != 0 &&
308             (un=utf8_mbtowc (&wc, s, str.length () - sn)) > 0) {
309         wstr.push_back (wc);
310         s += un;
311         sn += un;
312     }
313     return wstr;
314 }
315
316 EXAPI WideString
317 utf8_mbstowcs (const char *str, int len)
318 {
319     WideString wstr;
320
321     if (str) {
322         ucs4_t wc;
323         unsigned int sn = 0;
324         int un = 0;
325
326         if (len < 0) len = strlen (str);
327
328         while (sn < ((unsigned int)len) && *str != 0 && (un=utf8_mbtowc (&wc, (const unsigned char *)str, len - sn)) > 0) {
329             wstr.push_back (wc);
330             str += un;
331             sn += un;
332         }
333     }
334     return wstr;
335 }
336
337 EXAPI String
338 utf8_wcstombs (const WideString & wstr)
339 {
340     String str;
341     char utf8 [6];
342     int un = 0;
343
344     for (unsigned int i = 0; i<wstr.size (); ++i) {
345         un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
346         if (un > 0)
347             str.append (utf8, un);
348     }
349     return str;
350 }
351
352 EXAPI String
353 utf8_wcstombs (const ucs4_t *wstr, int len)
354 {
355     String str;
356     char utf8 [6];
357     int un = 0;
358
359     if (wstr) {
360         if (len < 0) {
361             len = 0;
362             while (wstr [len])
363                 ++len;
364         }
365
366         for (int i = 0; i < len; ++i) {
367             un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
368             if (un > 0)
369                 str.append (utf8, un);
370         }
371     }
372     return str;
373 }
374
375 static String trim_blank (const String &str)
376 {
377     String::size_type begin, len;
378
379     begin = str.find_first_not_of (" \t\n\v");
380
381     if (begin == String::npos)
382         return String ();
383
384     len = str.find_last_not_of (" \t\n\v") - begin + 1;
385
386     return str.substr (begin, len);
387 }
388
389 EXAPI String
390 scim_validate_locale (const String& locale)
391 {
392     String good;
393
394     String last = String (setlocale (LC_CTYPE, 0));
395
396     if (setlocale (LC_CTYPE, locale.c_str ())) {
397         good = locale;
398     } else {
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);
404             } else {
405                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
406                     *i = (char) toupper (*i);
407             }
408             if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ())) {
409                 good = vec [0] + "." + vec[1];
410             }
411         }
412     }
413
414     setlocale (LC_CTYPE, last.c_str ());
415
416     return good;
417 }
418
419 EXAPI String
420 scim_get_locale_encoding (const String& locale)
421 {
422     String last = String (setlocale (LC_CTYPE, 0));
423     String encoding;
424
425     if (setlocale (LC_CTYPE, locale.c_str ()))
426         encoding = String (nl_langinfo (CODESET));
427     else {
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);
433             } else {
434                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
435                     *i = (char) toupper (*i);
436             }
437             if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ()))
438                 encoding = String (nl_langinfo (CODESET));
439         }
440     }
441
442     setlocale (LC_CTYPE, last.c_str ());
443
444     return encoding;
445 }
446
447 EXAPI int
448 scim_get_locale_maxlen (const String& locale)
449 {
450     int maxlen;
451
452     String last = String (setlocale (LC_CTYPE, 0));
453
454     if (setlocale (LC_CTYPE, locale.c_str ()))
455         maxlen = MB_CUR_MAX;
456     else
457         maxlen = 1;
458
459     setlocale (LC_CTYPE, last.c_str ());
460     return maxlen;
461 }
462
463 EXAPI int
464 scim_split_string_list (std::vector<String>& vec, const String& str, char delim)
465 {
466     int count = 0;
467
468     String temp;
469     String::const_iterator bg, ed;
470
471     vec.clear ();
472
473     if (str.empty ()) return 0;
474
475     bg = str.begin ();
476     ed = str.begin ();
477
478     while (bg != str.end () && ed != str.end ()) {
479         for (; ed != str.end (); ++ed) {
480             if (*ed == delim)
481                 break;
482         }
483         temp.assign (bg, ed);
484         temp = trim_blank (temp);
485         vec.push_back (temp);
486         ++count;
487
488         if (ed != str.end ())
489             bg = ++ ed;
490     }
491     return count;
492 }
493
494 EXAPI String
495 scim_combine_string_list (const std::vector<String>& vec, char delim)
496 {
497     String result;
498     for (std::vector<String>::const_iterator i = vec.begin (); i!=vec.end (); ++i) {
499         result += *i;
500         if (i+1 != vec.end ())
501             result += delim;
502     }
503     return result;
504 }
505
506 EXAPI bool
507 scim_if_wchar_ucs4_equal ()
508 {
509     if (sizeof (wchar_t) != sizeof (ucs4_t))
510         return false;
511
512     iconv_t cd;
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);
517
518     char *wcp = (char *) wcbuf;
519     ICONV_CONST char *ucsp = (ICONV_CONST char *) ucsbuf;
520
521     if (scim_is_little_endian ())
522         cd = iconv_open ("UCS-4LE", "wchar_t");
523     else
524         cd = iconv_open ("UCS-4BE", "wchar_t");
525
526     if (cd == (iconv_t) -1)
527         return false;
528
529     iconv (cd, &ucsp, &ucslen, &wcp, &wclen);
530
531     iconv_close (cd);
532
533     if (wcbuf [0] == (wchar_t) ucsbuf [0] &&
534         wcbuf [1] == (wchar_t) ucsbuf [1])
535         return true;
536
537     return false;
538 }
539
540 static struct {
541     ucs4_t half;
542     ucs4_t full;
543     ucs4_t size;
544 } __half_full_table [] = {
545     {0x0020, 0x3000, 1},
546     {0x0021, 0xFF01, 0x5E},
547     {0x00A2, 0xFFE0, 2},
548     {0x00A5, 0xFFE5, 1},
549     {0x00A6, 0xFFE4, 1},
550     {0x00AC, 0xFFE2, 1},
551     {0x00AF, 0xFFE3, 1},
552     {0x20A9, 0xFFE6, 1},
553     {0xFF61, 0x3002, 1},
554     {0xFF62, 0x300C, 2},
555     {0xFF64, 0x3001, 1},
556     {0xFF65, 0x30FB, 1},
557     {0xFF66, 0x30F2, 1},
558     {0xFF67, 0x30A1, 1},
559     {0xFF68, 0x30A3, 1},
560     {0xFF69, 0x30A5, 1},
561     {0xFF6A, 0x30A7, 1},
562     {0xFF6B, 0x30A9, 1},
563     {0xFF6C, 0x30E3, 1},
564     {0xFF6D, 0x30E5, 1},
565     {0xFF6E, 0x30E7, 1},
566     {0xFF6F, 0x30C3, 1},
567     {0xFF70, 0x30FC, 1},
568     {0xFF71, 0x30A2, 1},
569     {0xFF72, 0x30A4, 1},
570     {0xFF73, 0x30A6, 1},
571     {0xFF74, 0x30A8, 1},
572     {0xFF75, 0x30AA, 2},
573     {0xFF77, 0x30AD, 1},
574     {0xFF78, 0x30AF, 1},
575     {0xFF79, 0x30B1, 1},
576     {0xFF7A, 0x30B3, 1},
577     {0xFF7B, 0x30B5, 1},
578     {0xFF7C, 0x30B7, 1},
579     {0xFF7D, 0x30B9, 1},
580     {0xFF7E, 0x30BB, 1},
581     {0xFF7F, 0x30BD, 1},
582     {0xFF80, 0x30BF, 1},
583     {0xFF81, 0x30C1, 1},
584     {0xFF82, 0x30C4, 1},
585     {0xFF83, 0x30C6, 1},
586     {0xFF84, 0x30C8, 1},
587     {0xFF85, 0x30CA, 6},
588     {0xFF8B, 0x30D2, 1},
589     {0xFF8C, 0x30D5, 1},
590     {0xFF8D, 0x30D8, 1},
591     {0xFF8E, 0x30DB, 1},
592     {0xFF8F, 0x30DE, 5},
593     {0xFF94, 0x30E4, 1},
594     {0xFF95, 0x30E6, 1},
595     {0xFF96, 0x30E8, 6},
596     {0xFF9C, 0x30EF, 1},
597     {0xFF9D, 0x30F3, 1},
598     {0xFFA0, 0x3164, 1},
599     {0xFFA1, 0x3131, 30},
600     {0xFFC2, 0x314F, 6},
601     {0xFFCA, 0x3155, 6},
602     {0xFFD2, 0x315B, 9},
603     {0xFFE9, 0x2190, 4},
604     {0xFFED, 0x25A0, 1},
605     {0xFFEE, 0x25CB, 1},
606     {0,0,0}
607 };
608
609
610 /**
611  * convert a half width unicode char to full width char
612  */
613 EXAPI ucs4_t
614 scim_wchar_to_full_width (ucs4_t code)
615 {
616     int i=0;
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);
623         ++ i;
624     }
625     return code;
626 }
627
628 /**
629  * convert a full width unicode char to half width char
630  */
631 EXAPI ucs4_t
632 scim_wchar_to_half_width (ucs4_t code)
633 {
634     int i=0;
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);
641         ++ i;
642     }
643     return code;
644 }
645
646 EXAPI String
647 scim_get_home_dir ()
648 {
649     const char * home_dir = 0;
650     struct passwd pw;
651     struct passwd *result;
652     char buf [2048] = {0,};
653
654     setpwent ();
655     int ret = getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
656     endpwent ();
657
658     if (ret != 0 || !result) {
659         LOGE ("Fail to getpwuid_r");
660         return String ("");
661     }
662
663     if (pw.pw_dir)
664         home_dir = pw.pw_dir;
665     else
666         home_dir = getenv ("HOME");
667
668     if (home_dir)
669         return String (home_dir);
670     else
671         return String ("");
672 }
673
674 EXAPI String
675 scim_get_user_name ()
676 {
677     const char *user_name;
678     struct passwd pw;
679     struct passwd *result;
680     char buf [2048] = {0,};
681
682     setpwent ();
683     int ret = getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
684     endpwent ();
685
686     if (ret != 0 || !result) {
687         LOGE ("Fail to getpwuid_r");
688         return String ("");
689     }
690
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);
695     }
696
697     char uid_str [10];
698
699     snprintf (uid_str, 10, "%u", getuid ());
700
701     return String (uid_str);
702 }
703
704 EXAPI String
705 scim_get_user_data_dir ()
706 {
707     String dir = scim_get_home_dir () + String ("/.config/.scim");
708     scim_make_dir (dir);
709     return dir;
710 }
711
712 EXAPI String
713 scim_get_current_locale ()
714 {
715     char *locale = setlocale (LC_CTYPE, 0);
716
717     if (locale) return String (locale);
718     return String ();
719 }
720
721 EXAPI String scim_get_current_language ()
722 {
723     return scim_get_locale_language (scim_get_current_locale ());
724 }
725
726 EXAPI bool
727 scim_is_little_endian ()
728 {
729     short endian = 1;
730     return (*((char *)&endian) != 0);
731 }
732
733 EXAPI size_t
734 scim_load_file (const String &filename, char **bufptr)
735 {
736     if (!filename.length ())
737         return 0;
738
739     struct stat statbuf;
740
741     if (stat (filename.c_str (), &statbuf) < 0 ||
742         !S_ISREG (statbuf.st_mode) ||
743         !statbuf.st_size)
744         return 0;
745
746     if (!bufptr)
747         return statbuf.st_size;
748
749     FILE *fp = fopen (filename.c_str (), "r");
750
751     if (fp == NULL) {
752         *bufptr = 0;
753         return 0;
754     }
755
756     if (feof (fp) != 0) {
757         fclose (fp);
758         return 0;
759     }
760
761     if (ferror (fp)) {
762         fclose (fp);
763         return 0;
764     }
765
766     try {
767         *bufptr = new char [statbuf.st_size];
768     } catch (std::bad_alloc &e) {
769         fclose (fp);
770         return 0;
771     }
772
773     size_t size = fread (*bufptr, 1, statbuf.st_size, fp);
774
775     fclose (fp);
776
777     if (!size) {
778         delete [] *bufptr;
779         *bufptr = 0;
780     }
781
782     return size;
783 }
784
785 EXAPI bool
786 scim_make_dir (const String &dir)
787 {
788     if (access (dir.c_str (), R_OK) != 0) {
789         std::vector <String> paths;
790         String path;
791
792         scim_split_string_list (paths, dir, SCIM_PATH_DELIM);
793
794         for (size_t i = 1; i < paths.size (); ++i) {
795             path += SCIM_PATH_DELIM_STRING + paths [i];
796
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 ());
801                     return false;
802                 }
803
804                 if (access (path.c_str (), R_OK) != 0) {
805                     LOGE ("Can not access %s", path.c_str ());
806                     return false;
807                 }
808             }
809         }
810     }
811
812     return true;
813 }
814
815 struct __Language {
816     const char *code;
817     const char *normalized;
818     const char *name;
819     const char *untranslated;
820     const char *locale_suffix;
821 };
822
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" },
933
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 },
1005
1006     { "", "", "", NULL, NULL }
1007 };
1008
1009 class __LanguageLess
1010 {
1011 public:
1012     bool operator () (const __Language &lhs, const __Language &rhs) const {
1013         return strcmp (lhs.code, rhs.code) < 0;
1014     }
1015
1016     bool operator () (const __Language &lhs, const String &rhs) const {
1017         return strcmp (lhs.code, rhs.c_str ()) < 0;
1018     }
1019
1020     bool operator () (const String &lhs, const __Language &rhs) const {
1021         return strcmp (lhs.c_str (), rhs.code) < 0;
1022     }
1023 };
1024
1025 static bool language_sorted = false;
1026
1027 static __Language *
1028 __find_language (const String &lang)
1029 {
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;
1038                 }
1039             }
1040         }
1041     }
1042
1043     static __Language *langs_begin = __languages;
1044     static __Language *langs_end   = __languages + sizeof (__languages) / sizeof (__Language) - 1;
1045
1046     String nlang = lang;
1047     bool contry_code = false;
1048
1049     // Normalize the language name.
1050     for (String::iterator it = nlang.begin (); it != nlang.end (); ++it) {
1051         if (*it == '-' || *it == '_') {
1052             *it = '_';
1053             contry_code = true;
1054         } else if (contry_code) {
1055             *it = toupper (*it);
1056         } else {
1057             *it = tolower (*it);
1058         }
1059     }
1060
1061     __Language *result = std::lower_bound (langs_begin, langs_end, nlang, __LanguageLess ());
1062
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))
1067             return result;
1068     }
1069
1070     return NULL;
1071 }
1072
1073 EXAPI String
1074 scim_get_language_name (const String &lang)
1075 {
1076     return String (_(scim_get_language_name_english (lang).c_str ()));
1077 }
1078
1079 EXAPI String
1080 scim_get_language_name_english (const String &lang)
1081 {
1082     __Language *result = __find_language (lang);
1083
1084     if (result)
1085         return String (result->name);
1086
1087     return String ("Other");
1088 }
1089
1090 EXAPI String
1091 scim_get_language_name_untranslated (const String &lang)
1092 {
1093     __Language *result = __find_language (lang);
1094
1095     if (result) {
1096         if (result->untranslated)
1097             return String (result->untranslated);
1098         else
1099             return String (_(result->name));
1100     }
1101
1102     return String (_("Other"));
1103 }
1104
1105 EXAPI String
1106 scim_get_language_locales (const String &lang)
1107 {
1108     __Language *result = __find_language (lang);
1109
1110     std::vector<String> locales;
1111
1112     if (result) {
1113         String good;
1114
1115         if (strlen (result->code) < 5 && result->normalized)
1116             result = __find_language (result->normalized);
1117
1118         if (result)
1119             good = scim_validate_locale (String (result->code) + ".UTF-8");
1120
1121         if (good.length ()) locales.push_back (good);
1122
1123         if (result && result->locale_suffix) {
1124             std::vector<String> suffixes;
1125
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);
1130             }
1131         }
1132
1133         if (result)
1134             good = scim_validate_locale (result->code);
1135
1136         if (good.length ()) locales.push_back (good);
1137     }
1138
1139     return scim_combine_string_list (locales, ',');
1140 }
1141
1142 EXAPI String
1143 scim_get_locale_language (const String &locale)
1144 {
1145     if (locale.length () == 0) return String ();
1146
1147     String str = locale.substr (0, locale.find ('.'));
1148     return scim_validate_language (str.substr (0, str.find ('@')));
1149 }
1150
1151 EXAPI String
1152 scim_validate_language (const String &lang)
1153 {
1154     __Language *result = __find_language (lang);
1155
1156     if (result)
1157         return String (result->code);
1158
1159     // Add prefix ~ to let other become the last item when sorting.
1160     return String ("~other");
1161 }
1162
1163 EXAPI String
1164 scim_get_normalized_language (const String &lang)
1165 {
1166     __Language *result = __find_language (lang);
1167
1168     if (result) {
1169         if (result->normalized) return String (result->normalized);
1170         else return String (result->code);
1171     }
1172
1173     // Add prefix ~ to let other become the last item when sorting.
1174     //return String ("~other");
1175     return String ("en");
1176 }
1177
1178 #ifndef SCIM_LAUNCHER
1179  #define SCIM_LAUNCHER  (SCIM_LIBEXECDIR "/scim-launcher")
1180 #endif
1181
1182 EXAPI int  scim_launch (bool          daemon,
1183                   const String &config,
1184                   const String &imengines,
1185                   const String &frontend,
1186                   char  * const argv [])
1187 {
1188     if (!config.length () || !imengines.length () || !frontend.length ())
1189         return -1;
1190
1191     int   i, new_argc = 0;
1192     char *new_argv [40];
1193
1194     new_argv [new_argc ++] = strdup (SCIM_LAUNCHER);
1195
1196     if (daemon)
1197         new_argv [new_argc ++] = strdup ("-d");
1198
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 ());
1205
1206     if (argv) {
1207         for (i = 0; argv [i] && new_argc < 39 ; ++i, ++new_argc)
1208             new_argv [new_argc] = strdup (argv [i]);
1209     }
1210
1211     new_argv [new_argc] = 0;
1212
1213     pid_t child_pid;
1214
1215     child_pid = fork ();
1216
1217     ISF_SAVE_LOG ("ppid: %d, fork result : %d, user %s", getppid (), child_pid, scim_get_user_name ().c_str ());
1218
1219     // Error fork.
1220     if (child_pid < 0) {
1221         for (i = 0; i < new_argc; ++i) {
1222             if (new_argv [i]) {
1223                 free (new_argv [i]);
1224                 new_argv [i] = NULL;
1225             }
1226         }
1227         return -1;
1228     }
1229
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) {
1234             if (new_argv [i]) {
1235                 free (new_argv [i]);
1236                 new_argv [i] = NULL;
1237             }
1238         }
1239         return ret;
1240     }
1241
1242     // In parent process, wait the child exit.
1243
1244     for (i = 0; i < new_argc; ++i) {
1245         if (new_argv [i]) {
1246             free (new_argv [i]);
1247             new_argv [i] = NULL;
1248         }
1249     }
1250
1251     int status;
1252     pid_t ret_pid;
1253
1254     ret_pid = waitpid (child_pid, &status, 0);
1255
1256     if (ret_pid == child_pid && WIFEXITED(status))
1257         return WEXITSTATUS(status);
1258
1259     return -1;
1260 }
1261
1262 #ifndef SCIM_PANEL_PROGRAM
1263   #define SCIM_PANEL_PROGRAM  (SCIM_BINDIR "/scim-panel-gtk")
1264 #endif
1265
1266 EXAPI int scim_launch_panel (bool          daemon,
1267                        const String &config,
1268                        const String &display,
1269                        char * const  argv [])
1270 {
1271     if (!config.length ())
1272         return -1;
1273
1274     String panel_program = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM, String (SCIM_PANEL_PROGRAM));
1275
1276     if (!panel_program.length ())
1277         panel_program = String (SCIM_PANEL_PROGRAM);
1278
1279     if (panel_program [0] != SCIM_PATH_DELIM) {
1280         panel_program = String (SCIM_BINDIR) +
1281                         String (SCIM_PATH_DELIM_STRING) +
1282                         panel_program;
1283     }
1284
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);
1288
1289     int   i, new_argc = 0;
1290     char *new_argv [80];
1291
1292     new_argv [new_argc ++] = strdup (panel_program.c_str ());
1293
1294     if (display.length() > 0) {
1295         new_argv [new_argc ++] = strdup ("--display");
1296         new_argv [new_argc ++] = strdup (display.c_str ());
1297     }
1298
1299     new_argv [new_argc ++] = strdup ("-c");
1300     new_argv [new_argc ++] = strdup (config.c_str ());
1301
1302     if (daemon)
1303         new_argv [new_argc ++] = strdup ("-d");
1304
1305     if (argv) {
1306         for (i = 0; argv [i] && new_argc < 79; ++i, ++new_argc)
1307             new_argv [new_argc] = strdup (argv [i]);
1308     }
1309
1310     new_argv [new_argc] = 0;
1311
1312     pid_t child_pid;
1313
1314     child_pid = fork ();
1315
1316     ISF_SAVE_LOG ("ppid : %d fork result : %d", getppid (), child_pid);
1317
1318     // Error fork.
1319     if (child_pid < 0) {
1320         for (i = 0; i < new_argc; ++i) {
1321             if (new_argv [i]) {
1322                 free (new_argv [i]);
1323                 new_argv [i] = NULL;
1324             }
1325         }
1326         return -1;
1327     }
1328
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) {
1333             if (new_argv [i]) {
1334                 free (new_argv [i]);
1335                 new_argv [i] = NULL;
1336             }
1337         }
1338         return ret;
1339     }
1340
1341     // In parent process, wait the child exit.
1342
1343     for (i = 0; i < new_argc; ++i) {
1344         if (new_argv [i]) {
1345             free (new_argv [i]);
1346             new_argv [i] = NULL;
1347         }
1348     }
1349
1350     int status;
1351     pid_t ret_pid;
1352
1353     ret_pid = waitpid (child_pid, &status, 0);
1354
1355     if (ret_pid == child_pid && WIFEXITED(status))
1356         return WEXITSTATUS(status);
1357
1358     return -1;
1359 }
1360
1361 EXAPI void
1362 scim_usleep (unsigned int usec)
1363 {
1364     if (usec == 0) return;
1365
1366 #if HAVE_NANOSLEEP
1367     struct timespec req, rem;
1368
1369     req.tv_sec = (long int)usec / 1000000;
1370     req.tv_nsec = ((long int)usec % 1000000) * 1000;
1371
1372     while (nanosleep (&req, &rem) == -1 && errno == EINTR && (rem.tv_sec != 0 || rem.tv_nsec != 0))
1373         req = rem;
1374 #elif HAVE_USLEEP
1375     unsigned int sec = usec / 1000000;
1376     usec %= 1000000;
1377
1378     for (unsigned int i = 0; i < sec; ++i)
1379         sleep (1);
1380
1381     usleep (usec);
1382 #else
1383     unsigned int sec = usec / 1000000;
1384
1385     sleep (sec ? sec : 1);
1386 #endif
1387 }
1388
1389 EXAPI void scim_daemon ()
1390 {
1391 #if HAVE_DAEMON
1392     LOGD ("ppid:%d  calling daemon()", getppid ());
1393
1394     if (daemon (0, 0) == -1)
1395         std::cerr << "Error to make SCIM into a daemon!\n";
1396
1397     LOGD ("ppid:%d  daemon() called", getppid ());
1398
1399     return;
1400 #else
1401     pid_t id;
1402
1403     id = fork ();
1404     if (id == -1) {
1405         std::cerr << "Error to make SCIM into a daemon!\n";
1406         return;
1407     } else if (id > 0) {
1408         _exit (0);
1409     }
1410
1411     ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1412
1413     id = fork ();
1414     if (id == -1) {
1415         std::cerr << "Error to make SCIM into a daemon!\n";
1416         return;
1417     } else if (id > 0) {
1418         _exit (0);
1419     }
1420
1421     ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1422
1423     return;
1424 #endif
1425 }
1426
1427 EXAPI void isf_save_log (const char *fmt, ...)
1428 {
1429     char buf[1024] = {0};
1430     va_list ap;
1431
1432     va_start (ap, fmt);
1433     vsnprintf (buf, sizeof (buf), fmt, ap);
1434     va_end (ap);
1435
1436     const int MAX_LOG_FILE_SIZE = 12 * 1024; /* 12KB */
1437
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 ();
1448             } else {
1449                 size_exceeded = true;
1450             }
1451         }
1452     }
1453
1454     LOGD ("%s", buf);
1455 }
1456
1457 EXAPI bool scim_is_symlink (const String filename)
1458 {
1459     struct stat info;
1460     if (lstat(filename.c_str (), &info) < 0) {
1461         char buf_err[256];
1462         LOGE("lstat failed. %s", strerror_r (errno, buf_err, sizeof (buf_err)));
1463         return false;
1464     }
1465
1466     return S_ISLNK(info.st_mode);
1467 }
1468
1469 static struct timeval _t0 = {0, 0};
1470 static struct timeval _t1;
1471
1472 static clock_t _p_t0;
1473 static clock_t _p_t1;
1474
1475 void ISF_PROF_DEBUG_TIME_BEGIN ()
1476 {
1477     struct tms tms;
1478
1479     _p_t0 = times (&tms);
1480 }
1481
1482 /* Measure elapsed time */
1483 void ISF_PROF_DEBUG_TIME_END (char const* format, char const* func, int line)
1484 {
1485     float etime = 0.0;
1486     struct tms tms;
1487     static long clktck = 0;
1488
1489     if (clktck == 0)
1490         if ((clktck = sysconf (_SC_CLK_TCK)) < 0)
1491             return;
1492
1493     _p_t1 = times (&tms);
1494
1495     etime = (_p_t1 - _p_t0) / (double) clktck;
1496
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);
1499
1500     return;
1501 }
1502
1503 /* Measure elapsed time */
1504 void ISF_PROF_DEBUG_TIME (char const* func, int line, char const* str)
1505 {
1506     double etime = 0.0;
1507
1508     if (_t0.tv_sec == 0 && _t0.tv_usec == 0) {
1509         gettimeofday (&_t0, NULL);
1510         return;
1511     }
1512
1513     gettimeofday (&_t1, NULL);
1514
1515     if (_t0.tv_usec != 0) {
1516         etime = ((_t1.tv_sec * 1000000 + _t1.tv_usec) - (_t0.tv_sec * 1000000 + _t0.tv_usec))/1000000.0;
1517     }
1518
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);
1520
1521     _t0 = _t1;
1522
1523     return;
1524 }
1525
1526 EXAPI void gettime (clock_t clock_start, const char* str)
1527 {
1528 #ifdef ISF_PROF
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);
1536 #endif
1537 }
1538
1539 } // namespace scim
1540
1541 /*
1542 vi:ts=4:ai:nowrap:expandtab
1543 */