Fix build warning in TV profile
[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 #include "isf_debug.h"
53
54 #include "scim_private.h"
55 #include "scim.h"
56
57 #ifdef LOG_TAG
58 # undef LOG_TAG
59 #endif
60 #define LOG_TAG     "ISF_UTILITY"
61
62 namespace scim {
63
64 EXAPI int
65 utf8_mbtowc (ucs4_t *pwc, const unsigned char *src, int src_len)
66 {
67     if (!pwc)
68         return 0;
69
70     unsigned char c = src [0];
71
72     if (c < 0x80) {
73         *pwc = c;
74         return 1;
75     } else if (c < 0xc2) {
76         return RET_ILSEQ;
77     } else if (c < 0xe0) {
78         if (src_len < 2)
79             return RET_TOOFEW(0);
80         unsigned char utf8_x1 = src [1] ^ 0x80;
81         if (utf8_x1 >= 0x40)
82             return RET_ILSEQ;
83         *pwc = ((ucs4_t) (c & 0x1f) << 6)
84                  | (ucs4_t) utf8_x1;
85         return 2;
86     } else if (c < 0xf0) {
87         if (src_len < 3)
88             return RET_TOOFEW(0);
89         unsigned char utf8_x1 = src[1] ^ 0x80;
90         unsigned char utf8_x2 = src[2] ^ 0x80;
91         if (!((utf8_x1 | utf8_x2) < 0x40
92                 && (c >= 0xe1 || src [1] >= 0xa0)))
93             return RET_ILSEQ;
94         *pwc = ((ucs4_t) (c & 0x0f) << 12)
95                  | ((ucs4_t) (utf8_x1) << 6)
96                  | (ucs4_t) (utf8_x2);
97         return 3;
98     } else if (c < 0xf8) {
99         if (src_len < 4)
100             return RET_TOOFEW(0);
101         unsigned char utf8_x1 = src[1] ^ 0x80;
102         unsigned char utf8_x2 = src[2] ^ 0x80;
103         unsigned char utf8_x3 = src[3] ^ 0x80;
104         if (!((utf8_x1 | utf8_x2 | utf8_x3) < 0x40
105                 && (c >= 0xf1 || src [1] >= 0x90)))
106             return RET_ILSEQ;
107         *pwc = ((ucs4_t) (c & 0x07) << 18)
108                  | ((ucs4_t) (utf8_x1) << 12)
109                  | ((ucs4_t) (utf8_x2) << 6)
110                  | (ucs4_t) (utf8_x3);
111         return 4;
112     } else if (c < 0xfc) {
113         if (src_len < 5)
114             return RET_TOOFEW(0);
115         unsigned char utf8_x1 = src[1] ^ 0x80;
116         unsigned char utf8_x2 = src[2] ^ 0x80;
117         unsigned char utf8_x3 = src[3] ^ 0x80;
118         unsigned char utf8_x4 = src[4] ^ 0x80;
119         if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4) < 0x40
120                 && (c >= 0xf9 || src [1] >= 0x88)))
121             return RET_ILSEQ;
122         *pwc = ((ucs4_t) (c & 0x03) << 24)
123                  | ((ucs4_t) (utf8_x1) << 18)
124                  | ((ucs4_t) (utf8_x2) << 12)
125                  | ((ucs4_t) (utf8_x3) << 6)
126                  | (ucs4_t) (utf8_x4);
127         return 5;
128     } else if (c < 0xfe) {
129         if (src_len < 6)
130             return RET_TOOFEW(0);
131         unsigned char utf8_x1 = src[1] ^ 0x80;
132         unsigned char utf8_x2 = src[2] ^ 0x80;
133         unsigned char utf8_x3 = src[3] ^ 0x80;
134         unsigned char utf8_x4 = src[4] ^ 0x80;
135         unsigned char utf8_x5 = src[5] ^ 0x80;
136         if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4 | utf8_x5) < 0x40
137                 && (c >= 0xfd || src [1] >= 0x84)))
138             return RET_ILSEQ;
139         *pwc = ((ucs4_t) (c & 0x01) << 30)
140                  | ((ucs4_t) (utf8_x1) << 24)
141                  | ((ucs4_t) (utf8_x2) << 18)
142                  | ((ucs4_t) (utf8_x3) << 12)
143                  | ((ucs4_t) (utf8_x4) << 6)
144                  | (ucs4_t) (utf8_x5);
145         return 6;
146     } else
147         return RET_ILSEQ;
148 }
149
150 EXAPI int
151 utf8_wctomb (unsigned char *dest, ucs4_t wc, int dest_size)
152 {
153     if (!dest)
154         return 0;
155     int count;
156     unsigned int _wc = wc;
157     if (_wc < 0x80)
158         count = 1;
159     else if (_wc < 0x800)
160         count = 2;
161     else if (_wc < 0x10000)
162         count = 3;
163     else if (_wc < 0x200000)
164         count = 4;
165     else if (_wc < 0x4000000)
166         count = 5;
167     else if (_wc <= 0x7fffffff)
168         count = 6;
169     else
170         return RET_ILSEQ;
171
172     if (dest_size < count)
173         return RET_TOOSMALL;
174     switch (count) { /* note: code falls through cases! */
175         case 6: dest [5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
176         case 5: dest [4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
177         case 4: dest [3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
178         case 3: dest [2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
179         case 2: dest [1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
180         case 1: dest [0] = wc;
181     }
182     return count;
183 }
184
185 EXAPI ucs4_t
186 utf8_read_wchar (std::istream &is)
187 {
188     unsigned char utf8[5] = {0};
189     unsigned char utf8_x_;
190
191     is.read ((char*)(&utf8_x_), sizeof(unsigned char)); // reducing utf8 char sequence to ucs4 convertations
192     if (utf8_x_ < 0x80) {
193         return (ucs4_t)utf8_x_;
194     } else if (utf8_x_ < 0xc2) {
195         return 0;
196     } else if (utf8_x_ < 0xe0) {
197         unsigned char utf8_x1;
198         is.read ((char*)(&utf8_x1), sizeof(unsigned char));
199         utf8_x1 ^= 0x80;
200         if (utf8_x1 >= 0x40)
201             return 0;
202         return ((ucs4_t) (utf8_x_ & 0x1f) << 6)
203               | (ucs4_t) (utf8_x1);
204     } else if (utf8_x_ < 0xf0) {
205         is.read ((char*)(&utf8[0]), 2*sizeof(unsigned char));
206         unsigned char utf8_x1 = utf8[0] ^ 0x80;
207         unsigned char utf8_x2 = utf8[1] ^ 0x80;
208         if (!((utf8_x1 | utf8_x2) < 0x40
209            && (utf8_x_ >= 0xe1 || utf8[0] >= 0xa0)))
210             return 0;
211         return ((ucs4_t) (utf8_x_ & 0x0f) << 12)
212              | ((ucs4_t) (utf8_x1) << 6)
213              |  (ucs4_t) (utf8_x2);
214     } else if (utf8_x_ < 0xf8) {
215         is.read ((char*)(&utf8[0]), 3*sizeof(unsigned char));
216         unsigned char utf8_x1 = utf8[0] ^ 0x80;
217         unsigned char utf8_x2 = utf8[1] ^ 0x80;
218         unsigned char utf8_x3 = utf8[2] ^ 0x80;
219         if (!((utf8_x1 | utf8_x2 | utf8_x3) < 0x40
220            && (utf8_x_ >= 0xf1 || utf8[0] >= 0x90)))
221             return 0;
222         return ((ucs4_t) (utf8_x_ & 0x07) << 18)
223              | ((ucs4_t) (utf8_x1) << 12)
224              | ((ucs4_t) (utf8_x2) << 6)
225              |  (ucs4_t) (utf8_x3);
226     } else if (utf8_x_ < 0xfc) {
227         is.read ((char*)(&utf8[0]), 4*sizeof(unsigned char));
228         unsigned char utf8_x1 = utf8[0] ^ 0x80;
229         unsigned char utf8_x2 = utf8[1] ^ 0x80;
230         unsigned char utf8_x3 = utf8[2] ^ 0x80;
231         unsigned char utf8_x4 = utf8[3] ^ 0x80;
232         if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4) < 0x40
233            && (utf8_x_ >= 0xf9 || utf8[0] >= 0x88)))
234             return 0;
235         return ((ucs4_t) (utf8_x_ & 0x03) << 24)
236              | ((ucs4_t) (utf8_x1) << 18)
237              | ((ucs4_t) (utf8_x2) << 12)
238              | ((ucs4_t) (utf8_x3) << 6)
239              |  (ucs4_t) (utf8_x4);
240     } else if (utf8_x_ < 0xfe) {
241         is.read ((char*)(&utf8[0]), 5*sizeof(unsigned char));
242         unsigned char utf8_x1 = utf8[0] ^ 0x80;
243         unsigned char utf8_x2 = utf8[1] ^ 0x80;
244         unsigned char utf8_x3 = utf8[2] ^ 0x80;
245         unsigned char utf8_x4 = utf8[3] ^ 0x80;
246         unsigned char utf8_x5 = utf8[4] ^ 0x80;
247         if (!((utf8_x1 | utf8_x2 | utf8_x3 | utf8_x4 | utf8_x5) < 0x40
248            && (utf8_x_ >= 0xfd || utf8[0] >= 0x84)))
249             return 0;
250         return ((ucs4_t) (utf8_x_ & 0x01) << 30)
251              | ((ucs4_t) (utf8_x1) << 24)
252              | ((ucs4_t) (utf8_x2) << 18)
253              | ((ucs4_t) (utf8_x3) << 12)
254              | ((ucs4_t) (utf8_x4) << 6)
255              |  (ucs4_t) (utf8_x5);
256     }
257     return 0;
258 }
259
260 EXAPI WideString
261 utf8_read_wstring (std::istream &is, ucs4_t delim, bool rm_delim)
262 {
263     WideString str;
264     ucs4_t wc;
265     while ((wc = utf8_read_wchar (is)) > 0) {
266         if (wc != delim)
267             str.push_back (wc);
268         else {
269             if (!rm_delim)
270                 str.push_back (wc);
271             break;
272         }
273     }
274     return str;
275 }
276
277 EXAPI std::ostream &
278 utf8_write_wchar (std::ostream &os, ucs4_t wc)
279 {
280     unsigned char utf8[6];
281     int count = 0;
282
283     if ((count=utf8_wctomb (utf8, wc, 6)) > 0)
284         os.write ((char*)utf8, count * sizeof (unsigned char));
285
286     return os;
287 }
288
289 EXAPI std::ostream &
290 utf8_write_wstring (std::ostream &os, const WideString & wstr)
291 {
292     for (unsigned int i=0; i<wstr.size (); ++i)
293         utf8_write_wchar (os, wstr [i]);
294
295     return os;
296 }
297
298 EXAPI WideString
299 utf8_mbstowcs (const String & str)
300 {
301     WideString wstr;
302     ucs4_t wc;
303     unsigned int sn = 0;
304     int un = 0;
305
306     const unsigned char *s = (const unsigned char *) str.c_str ();
307
308     while (sn < str.length () && *s != 0 &&
309             (un=utf8_mbtowc (&wc, s, str.length () - sn)) > 0) {
310         wstr.push_back (wc);
311         s += un;
312         sn += un;
313     }
314     return wstr;
315 }
316
317 EXAPI WideString
318 utf8_mbstowcs (const char *str, int len)
319 {
320     WideString wstr;
321
322     if (str) {
323         ucs4_t wc;
324         unsigned int sn = 0;
325         int un = 0;
326
327         if (len < 0) len = strlen (str);
328
329         while (sn < ((unsigned int)len) && *str != 0 && (un=utf8_mbtowc (&wc, (const unsigned char *)str, len - sn)) > 0) {
330             wstr.push_back (wc);
331             str += un;
332             sn += un;
333         }
334     }
335     return wstr;
336 }
337
338 EXAPI String
339 utf8_wcstombs (const WideString & wstr)
340 {
341     String str;
342     char utf8 [6];
343     int un = 0;
344
345     for (unsigned int i = 0; i<wstr.size (); ++i) {
346         un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
347         if (un > 0)
348             str.append (utf8, un);
349     }
350     return str;
351 }
352
353 EXAPI String
354 utf8_wcstombs (const ucs4_t *wstr, int len)
355 {
356     String str;
357     char utf8 [6];
358     int un = 0;
359
360     if (wstr) {
361         if (len < 0) {
362             len = 0;
363             while (wstr [len])
364                 ++len;
365         }
366
367         for (int i = 0; i < len; ++i) {
368             un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
369             if (un > 0)
370                 str.append (utf8, un);
371         }
372     }
373     return str;
374 }
375
376 static String trim_blank (const String &str)
377 {
378     String::size_type begin, len;
379
380     begin = str.find_first_not_of (" \t\n\v");
381
382     if (begin == String::npos)
383         return String ();
384
385     len = str.find_last_not_of (" \t\n\v") - begin + 1;
386
387     return str.substr (begin, len);
388 }
389
390 EXAPI String
391 scim_validate_locale (const String& locale)
392 {
393     String good;
394
395     String last = String (setlocale (LC_CTYPE, 0));
396
397     if (setlocale (LC_CTYPE, locale.c_str ())) {
398         good = locale;
399     } else {
400         std::vector<String> vec;
401         if (scim_split_string_list (vec, locale, '.') == 2) {
402             if (isupper (vec[1][0])) {
403                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
404                     *i = (char) tolower (*i);
405             } else {
406                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
407                     *i = (char) toupper (*i);
408             }
409             if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ())) {
410                 good = vec [0] + "." + vec[1];
411             }
412         }
413     }
414
415     setlocale (LC_CTYPE, last.c_str ());
416
417     return good;
418 }
419
420 EXAPI String
421 scim_get_locale_encoding (const String& locale)
422 {
423     String last = String (setlocale (LC_CTYPE, 0));
424     String encoding;
425
426     if (setlocale (LC_CTYPE, locale.c_str ()))
427         encoding = String (nl_langinfo (CODESET));
428     else {
429         std::vector<String> vec;
430         if (scim_split_string_list (vec, locale, '.') == 2) {
431             if (isupper (vec[1][0])) {
432                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
433                     *i = (char) tolower (*i);
434             } else {
435                 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
436                     *i = (char) toupper (*i);
437             }
438             if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ()))
439                 encoding = String (nl_langinfo (CODESET));
440         }
441     }
442
443     setlocale (LC_CTYPE, last.c_str ());
444
445     return encoding;
446 }
447
448 EXAPI int
449 scim_get_locale_maxlen (const String& locale)
450 {
451     int maxlen;
452
453     String last = String (setlocale (LC_CTYPE, 0));
454
455     if (setlocale (LC_CTYPE, locale.c_str ()))
456         maxlen = MB_CUR_MAX;
457     else
458         maxlen = 1;
459
460     setlocale (LC_CTYPE, last.c_str ());
461     return maxlen;
462 }
463
464 EXAPI int
465 scim_split_string_list (std::vector<String>& vec, const String& str, char delim)
466 {
467     int count = 0;
468
469     String temp;
470     String::const_iterator bg, ed;
471
472     vec.clear ();
473
474     if (str.empty ()) return 0;
475
476     bg = str.begin ();
477     ed = str.begin ();
478
479     while (bg != str.end () && ed != str.end ()) {
480         for (; ed != str.end (); ++ed) {
481             if (*ed == delim)
482                 break;
483         }
484         temp.assign (bg, ed);
485         temp = trim_blank (temp);
486         vec.push_back (temp);
487         ++count;
488
489         if (ed != str.end ())
490             bg = ++ ed;
491     }
492     return count;
493 }
494
495 EXAPI String
496 scim_combine_string_list (const std::vector<String>& vec, char delim)
497 {
498     String result;
499     for (std::vector<String>::const_iterator i = vec.begin (); i!=vec.end (); ++i) {
500         result += *i;
501         if (i+1 != vec.end ())
502             result += delim;
503     }
504     return result;
505 }
506
507 EXAPI bool
508 scim_if_wchar_ucs4_equal ()
509 {
510     if (sizeof (wchar_t) != sizeof (ucs4_t))
511         return false;
512
513     iconv_t cd;
514     wchar_t wcbuf [2] = {0,0};
515     ucs4_t  ucsbuf [2] = {0x4E00, 0x0001};
516     size_t  wclen = 2 * sizeof (wchar_t);
517     size_t  ucslen = 2 * sizeof (ucs4_t);
518
519     char *wcp = (char *) wcbuf;
520     ICONV_CONST char *ucsp = (ICONV_CONST char *) ucsbuf;
521
522     if (scim_is_little_endian ())
523         cd = iconv_open ("UCS-4LE", "wchar_t");
524     else
525         cd = iconv_open ("UCS-4BE", "wchar_t");
526
527     if (cd == (iconv_t) -1)
528         return false;
529
530     iconv (cd, &ucsp, &ucslen, &wcp, &wclen);
531
532     iconv_close (cd);
533
534     if (wcbuf [0] == (wchar_t) ucsbuf [0] &&
535         wcbuf [1] == (wchar_t) ucsbuf [1])
536         return true;
537
538     return false;
539 }
540
541 static struct {
542     ucs4_t half;
543     ucs4_t full;
544     ucs4_t size;
545 } __half_full_table [] = {
546     {0x0020, 0x3000, 1},
547     {0x0021, 0xFF01, 0x5E},
548     {0x00A2, 0xFFE0, 2},
549     {0x00A5, 0xFFE5, 1},
550     {0x00A6, 0xFFE4, 1},
551     {0x00AC, 0xFFE2, 1},
552     {0x00AF, 0xFFE3, 1},
553     {0x20A9, 0xFFE6, 1},
554     {0xFF61, 0x3002, 1},
555     {0xFF62, 0x300C, 2},
556     {0xFF64, 0x3001, 1},
557     {0xFF65, 0x30FB, 1},
558     {0xFF66, 0x30F2, 1},
559     {0xFF67, 0x30A1, 1},
560     {0xFF68, 0x30A3, 1},
561     {0xFF69, 0x30A5, 1},
562     {0xFF6A, 0x30A7, 1},
563     {0xFF6B, 0x30A9, 1},
564     {0xFF6C, 0x30E3, 1},
565     {0xFF6D, 0x30E5, 1},
566     {0xFF6E, 0x30E7, 1},
567     {0xFF6F, 0x30C3, 1},
568     {0xFF70, 0x30FC, 1},
569     {0xFF71, 0x30A2, 1},
570     {0xFF72, 0x30A4, 1},
571     {0xFF73, 0x30A6, 1},
572     {0xFF74, 0x30A8, 1},
573     {0xFF75, 0x30AA, 2},
574     {0xFF77, 0x30AD, 1},
575     {0xFF78, 0x30AF, 1},
576     {0xFF79, 0x30B1, 1},
577     {0xFF7A, 0x30B3, 1},
578     {0xFF7B, 0x30B5, 1},
579     {0xFF7C, 0x30B7, 1},
580     {0xFF7D, 0x30B9, 1},
581     {0xFF7E, 0x30BB, 1},
582     {0xFF7F, 0x30BD, 1},
583     {0xFF80, 0x30BF, 1},
584     {0xFF81, 0x30C1, 1},
585     {0xFF82, 0x30C4, 1},
586     {0xFF83, 0x30C6, 1},
587     {0xFF84, 0x30C8, 1},
588     {0xFF85, 0x30CA, 6},
589     {0xFF8B, 0x30D2, 1},
590     {0xFF8C, 0x30D5, 1},
591     {0xFF8D, 0x30D8, 1},
592     {0xFF8E, 0x30DB, 1},
593     {0xFF8F, 0x30DE, 5},
594     {0xFF94, 0x30E4, 1},
595     {0xFF95, 0x30E6, 1},
596     {0xFF96, 0x30E8, 6},
597     {0xFF9C, 0x30EF, 1},
598     {0xFF9D, 0x30F3, 1},
599     {0xFFA0, 0x3164, 1},
600     {0xFFA1, 0x3131, 30},
601     {0xFFC2, 0x314F, 6},
602     {0xFFCA, 0x3155, 6},
603     {0xFFD2, 0x315B, 9},
604     {0xFFE9, 0x2190, 4},
605     {0xFFED, 0x25A0, 1},
606     {0xFFEE, 0x25CB, 1},
607     {0,0,0}
608 };
609
610
611 /**
612  * convert a half width unicode char to full width char
613  */
614 EXAPI ucs4_t
615 scim_wchar_to_full_width (ucs4_t code)
616 {
617     int i=0;
618     while (__half_full_table [i].size) {
619         if (code >= __half_full_table [i].half &&
620             code <  __half_full_table [i].half +
621                     __half_full_table [i].size)
622             return __half_full_table [i].full +
623                     (code - __half_full_table [i].half);
624         ++ i;
625     }
626     return code;
627 }
628
629 /**
630  * convert a full width unicode char to half width char
631  */
632 EXAPI ucs4_t
633 scim_wchar_to_half_width (ucs4_t code)
634 {
635     int i=0;
636     while (__half_full_table [i].size) {
637         if (code >= __half_full_table [i].full &&
638             code <  __half_full_table [i].full +
639                     __half_full_table [i].size)
640             return __half_full_table [i].half +
641                     (code - __half_full_table [i].full);
642         ++ i;
643     }
644     return code;
645 }
646
647 EXAPI String
648 scim_get_home_dir ()
649 {
650     const char * home_dir = 0;
651     struct passwd pw;
652     struct passwd *result;
653     char buf [2048] = {0,};
654
655     setpwent ();
656     getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
657     endpwent ();
658
659     if (result && pw.pw_dir) {
660         home_dir = pw.pw_dir;
661     } else {
662         LOGE ("Fail to getpwuid_r");
663     }
664
665     if (!home_dir) {
666         home_dir = getenv ("HOME");
667     }
668
669     if (home_dir)
670         return String (home_dir);
671     else
672         return String ("");
673 }
674
675 EXAPI String
676 scim_get_user_name ()
677 {
678     const char *user_name;
679     struct passwd pw;
680     struct passwd *result;
681     char buf [2048] = {0,};
682
683     setpwent ();
684     getpwuid_r (getuid (), &pw, buf, sizeof (buf), &result);
685     endpwent ();
686
687     if (result && pw.pw_name) {
688         return String (pw.pw_name);
689     } else if ((user_name = getenv ("USER")) != NULL) {
690         return String (user_name);
691     }
692
693     char uid_str [10];
694
695     snprintf (uid_str, 10, "%u", getuid ());
696
697     return String (uid_str);
698 }
699
700 EXAPI String
701 scim_get_user_data_dir ()
702 {
703     String dir = scim_get_home_dir () + String ("/.config/.scim");
704     scim_make_dir (dir);
705     return dir;
706 }
707
708 EXAPI String
709 scim_get_current_locale ()
710 {
711     char *locale = setlocale (LC_CTYPE, 0);
712
713     if (locale) return String (locale);
714     return String ();
715 }
716
717 EXAPI String scim_get_current_language ()
718 {
719     return scim_get_locale_language (scim_get_current_locale ());
720 }
721
722 EXAPI bool
723 scim_is_little_endian ()
724 {
725     short endian = 1;
726     return (*((char *)&endian) != 0);
727 }
728
729 EXAPI size_t
730 scim_load_file (const String &filename, char **bufptr)
731 {
732     if (!filename.length ())
733         return 0;
734
735     struct stat statbuf;
736
737     if (stat (filename.c_str (), &statbuf) < 0 ||
738         !S_ISREG (statbuf.st_mode) ||
739         !statbuf.st_size)
740         return 0;
741
742     if (!bufptr)
743         return statbuf.st_size;
744
745     FILE *fp = fopen (filename.c_str (), "r");
746
747     if (fp == NULL) {
748         *bufptr = 0;
749         return 0;
750     }
751
752     if (feof (fp) != 0) {
753         fclose (fp);
754         return 0;
755     }
756
757     if (ferror (fp)) {
758         fclose (fp);
759         return 0;
760     }
761
762     try {
763         *bufptr = new char [statbuf.st_size];
764     } catch (...) {
765         fclose (fp);
766         throw;
767     }
768
769     if (! (*bufptr)) {
770         fclose (fp);
771         return 0;
772     }
773
774     size_t size = fread (*bufptr, 1, statbuf.st_size, fp);
775
776     fclose (fp);
777
778     if (!size) {
779         delete [] *bufptr;
780         *bufptr = 0;
781     }
782
783     return size;
784 }
785
786 EXAPI bool
787 scim_make_dir (const String &dir)
788 {
789     if (access (dir.c_str (), R_OK) != 0) {
790         std::vector <String> paths;
791         String path;
792
793         scim_split_string_list (paths, dir, SCIM_PATH_DELIM);
794
795         for (size_t i = 1; i < paths.size (); ++i) {
796             path += SCIM_PATH_DELIM_STRING + paths [i];
797
798             //Make the dir if it's not exist.
799             if (access (path.c_str (), R_OK) != 0) {
800                 if (mkdir (path.c_str (), S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
801                     LOGE ("Can not create %s", path.c_str ());
802                     return false;
803                 }
804
805                 if (access (path.c_str (), R_OK) != 0) {
806                     LOGE ("Can not access %s", path.c_str ());
807                     return false;
808                 }
809             } else
810                 LOGE ("Can not access %s", path.c_str ());
811         }
812     }
813     else
814         LOGE ("Can not access %s", dir.c_str ());
815     return true;
816 }
817
818 struct __Language {
819     const char *code;
820     const char *normalized;
821     const char *name;
822     const char *untranslated;
823     const char *locale_suffix;
824 };
825
826 static __Language __languages [] = {
827     { "C",        NULL, N_("English Keyboard"), NULL, NULL},
828     { "am_ET",    NULL, N_("Amharic"), "አማርኛ", NULL },
829     { "ar",       "ar", N_("Arabic"), "عربي", NULL },
830     { "ar_EG",    NULL, N_("Arabic (Egypt)"), "العربية (مصر)", NULL },
831     { "ar_LB",    NULL, N_("Arabic (Lebanon)"), "العربية (لبنان)", NULL },
832     { "ar_IL",    NULL, N_("Arabic (Israel)"), "العربية", NULL },
833     { "as_IN",    NULL, N_("Assamese"), "অসমীয়া", NULL},
834     { "az_AZ",    NULL, N_("Azerbaijani"), "Azərbaycan", NULL },
835     { "be_BY",    NULL, N_("Belarusian"), "Беларуская мова", NULL },
836     { "bg_BG",    NULL, N_("Bulgarian"), "Български", NULL },
837     { "bn",    "bn_BD", N_("Bengali"), "বাংলা", NULL },
838     { "bn_BD",    NULL, N_("Bengali"), "বাংলা", NULL },
839     { "bn_IN",    NULL, N_("Bengali (India)"), "বাংলা", NULL },
840     { "bo",       NULL, N_("Tibetan"), "པོད་སྐད་", NULL },
841     { "bs_BA",    NULL, N_("Bosnian"), "Bosanski", NULL },
842     { "ca_ES",    NULL, N_("Catalan"), "Català", "@euro" },
843     { "cs_CZ",    NULL, N_("Czech"), "čeština", NULL },
844     { "cy_GB",    NULL, N_("Welsh"), "Cymraeg", NULL },
845     { "da_DK",    NULL, N_("Danish"), "Dansk", "@euro" },
846     { "de_DE",    NULL, N_("German"), "Deutsch", "@euro" },
847     { "dv_MV",    NULL, N_("Divehi"), "ދިވެހިބަސް", NULL },
848     { "el_GR",    NULL, N_("Greek"), "ελληνικά", NULL },
849     { "en"   ,    NULL, N_("English"), "English", NULL },
850     { "en_AU",    NULL, N_("English (Australian)"), "English (Australian)", NULL },
851     { "en_CA",    NULL, N_("English (Canadian)"), "English (Canadian)", NULL },
852     { "en_GB",    NULL, N_("English (United Kingdom)"), "English (United Kingdom)", ".iso885915" },
853     { "en_IE",    NULL, N_("English (Ireland)"), "English (Ireland)", NULL },
854     { "en_US",    NULL, N_("English (United States)"), "English (United States)", ".iso885915" },
855     { "eo",       NULL, N_("Esperanto"), "Esperanto", NULL },
856     { "es",    "es_ES", N_("Spanish"), "Español", NULL },
857     { "es_ES",    NULL, N_("Spanish"), "Español", "@euro" },
858     { "es_MX",    NULL, N_("Spanish (Mexico)"), "Español (Mexico)", NULL },
859     { "es_US",    NULL, N_("Spanish (United States)"), "Español (United States)", NULL },
860     { "et_EE",    NULL, N_("Estonian"), "Eesti", ".iso885915" },
861     { "eu_ES",    NULL, N_("Basque"), "Euskara", "@euro" },
862     { "fa_IR",    NULL, N_("Persian"), "فارسی", NULL },
863     { "fi_FI",    NULL, N_("Finnish"), "Suomi", "@euro" },
864     { "fr_FR",    NULL, N_("French"), "Français", "@euro" },
865     { "ga_IE",    NULL, N_("Irish"), "Gaeilge", "@euro" },
866     { "gl_ES",    NULL, N_("Galician"), "Galego", "@euro" },
867     { "gu_IN",    NULL, N_("Gujarati"), "ગુજરાતી", NULL },
868     { "he_IL",    NULL, N_("Hebrew"), "עברית", NULL },
869     { "hi_IN",    NULL, N_("Hindi"), "हिंदी", NULL },
870     { "hr_HR",    NULL, N_("Croatian"), "Hrvatski", NULL },
871     { "hu_HU",    NULL, N_("Hungarian"), "Magyar", NULL },
872     { "hy_AM",    NULL, N_("Armenian"), "Հայերէն", NULL },
873     { "ia"   ,    NULL, N_("Interlingua"), "Interlingua", NULL },
874     { "id_ID",    NULL, N_("Indonesian"), "Bahasa Indonesia", NULL },
875     { "is_IS",    NULL, N_("Icelandic"), "íslenska", NULL },
876     { "it_IT",    NULL, N_("Italian"), "Italiano", "@euro" },
877     { "iw_IL",    NULL, N_("Hebrew"), "עברית", NULL },
878     { "ja_JP",    NULL, N_("Japanese"), "日本語", ".EUC-JP,.SJIS,.eucJP" },
879     { "ka_GE",    NULL, N_("Georgian"), "ქართული", NULL },
880     { "kk_KZ",    NULL, N_("Kazakh"), "Қазақ", NULL },
881     { "km",       NULL, N_("Cambodian"), "ភាសាខ្មែរ", NULL },
882     { "kn_IN",    NULL, N_("Kannada"), "ಕನ್ನಡ", NULL },
883     { "ko_KR",    NULL, N_("Korean"), "한국어", ".EUC-KR,.eucKR" },
884     { "lo",       NULL, N_("Lao"), "لاوس", NULL },
885     { "lo_LA",    NULL, N_("Laothian"), "ລາວ", NULL },
886     { "lt_LT",    NULL, N_("Lithuanian"), "Lietuvių", NULL },
887     { "lv_LV",    NULL, N_("Latvian"), "Latviešu", NULL },
888     { "mk_MK",    NULL, N_("Macedonian"), "Македонски", NULL },
889     { "ml_IN",    NULL, N_("Malayalam"), "മലയാളം", NULL },
890     { "mn_MN",    NULL, N_("Mongolian"), "Монгол", NULL },
891     { "mr_IN",    NULL, N_("Marathi"), "मराठी", NULL },
892     { "ms_MY",    NULL, N_("Malay"), "Bahasa Melayu", NULL },
893     { "my_MM",    NULL, N_("Burmese"), "မြန်မာဘာသာ", NULL },
894     { "ne_NP",    NULL, N_("Nepali"), "नेपाली", NULL },
895     { "nl_NL",    NULL, N_("Dutch"), "Nederlands", "@euro" },
896     { "nn_NO",    NULL, N_("Norwegian (Nynorsk)"), "Norsk (Nynorsk)", NULL },
897     { "nb_NO",    NULL, N_("Norwegian (Bokmal)"), "Norsk (Bokmål)", NULL },
898     { "or_IN",    NULL, N_("Oriya"), "ଓଡ଼ିଆ", NULL },
899     { "pa_IN",    NULL, N_("Punjabi"), "ਪੰਜਾਬੀ", NULL },
900     { "pl_PL",    NULL, N_("Polish"), "Polski", NULL },
901     { "pt",    "pt_PT", N_("Portuguese"), "Português", NULL },
902     { "pt_BR",    NULL, N_("Portuguese (Brazil)"), "Português (Brasil)", NULL },
903     { "pt_PT",    NULL, N_("Portuguese"), "Português", "@euro" },
904     { "ro_RO",    NULL, N_("Romanian"), "Română", NULL },
905     { "ru_RU",    NULL, N_("Russian"), "русский", ".koi8r" },
906     { "sd",    "sd_IN", N_("Sindhi"), "ﺲﻧڌﻱ", NULL },
907     { "sd_IN",    NULL, N_("Sindhi"), "सिन्धी", "@devanagari" },
908     { "si_IN",    NULL, N_("Sinhala"), "සිංහල", NULL },
909     { "si_LK",    NULL, N_("Sinhala"), "සිංහල", NULL },
910     { "sk_SK",    NULL, N_("Slovak"), "Slovenský", NULL },
911     { "sl_SI",    NULL, N_("Slovenian"), "Slovenščina", NULL },
912     { "sq_AL",    NULL, N_("Albanian"), "Shqip", NULL },
913     { "sr",    "sr_YU", N_("Serbian"), "Srpski", NULL },
914     { "sr_CS",    NULL, N_("Serbian"), "Srpski", NULL },
915     { "sr_YU",    NULL, N_("Serbian"), "Srpski", "@cyrillic" },
916     { "sv",    "sv_SE", N_("Swedish"), "Svenska", NULL },
917     { "sv_FI",    NULL, N_("Swedish (Finland)"), "Svenska (Finland)", "@euro" },
918     { "sv_SE",    NULL, N_("Swedish"), "Svenska", ".iso885915" },
919     { "ta_IN",    NULL, N_("Tamil"), "தமிழ்", NULL },
920     { "te_IN",    NULL, N_("Telugu"), "తెలుగు", NULL },
921     { "th_TH",    NULL, N_("Thai"), "ภาษาไทย", NULL },
922     { "tr_TR",    NULL, N_("Turkish"), "Türkçe", NULL },
923     { "ug",       NULL, N_("Uighur"), "ئۇيغۇر", NULL },
924     { "uk_UA",    NULL, N_("Ukrainian"), "Українська", NULL },
925     { "ur_PK",    NULL, N_("Urdu"), "اردو", NULL },
926     { "uz_UZ",    NULL, N_("Uzbek"), "o'zbek tili", "@cyrillic" },
927     { "vi_VN",    NULL, N_("Vietnamese"), "Tiếng Việt", ".tcvn" },
928     { "wa_BE",    NULL, N_("Walloon"), "Walon", "@euro" },
929     { "yi"   , "yi_US", N_("Yiddish"), "ייִדיש", NULL },
930     { "yi_US",    NULL, N_("Yiddish"), "ייִדיש", NULL },
931     { "zh",    "zh_CN", N_("Chinese"), "中文", NULL },
932     { "zh_CN",    NULL, N_("Chinese (Simplified)"), "中文 (简体)", ".GB18030,.GBK,.GB2312,.eucCN" },
933     { "zh_HK", NULL, N_("Chinese (Hongkong)"), "中文 (香港)", NULL },
934     { "zh_SG", "zh_CN", N_("Chinese (Singapore)"), "中文 (新加坡)", ".GBK" },
935     { "zh_TW",    NULL, N_("Chinese (Traditional_Taiwan)"), "中文 (台湾)", ".eucTW" },
936
937     { "nl_BE",    NULL, N_("Dutch (Belgian)"), "Dutch (Belgian)", NULL },
938     { "en_NZ",    NULL, N_("English (New Zealand)"), "English (New Zealand)", NULL },
939     { "en_ZA",    NULL, N_("English (South Africa)"), "English (South Africa)", NULL },
940     { "en_JM",    NULL, N_("English (Jamaica)"), "English (Jamaica)", NULL },
941     { "en_BZ",    NULL, N_("English (Belize)"), "English (Belize)", NULL },
942     { "en_TT",    NULL, N_("English (Trinidad)"), "English (Trinidad)", NULL },
943     { "en_ZW",    NULL, N_("English (Zimbabwe)"), "English (Zimbabwe)", NULL },
944     { "en_PH",    NULL, N_("English (Philippines)"), "English (Philippines)", NULL },
945     { "fr_BE",    NULL, N_("French (Belgian)"), "Français (Belgian)", NULL },
946     { "fr_CA",    NULL, N_("French (Canadian)"), "Français (Canada)", NULL },
947     { "fr_CH",    NULL, N_("French (Swiss)"), "Français (Suisse)", NULL },
948     { "fr_LU",    NULL, N_("French (Luxembourg)"), "Français (Luxembourg)", NULL },
949     { "fr_MC",    NULL, N_("French (Monaco)"), "Français (Monaco)", NULL },
950     { "de_CH",    NULL, N_("German (Swiss)"), "Deutsch (Schweiz)", NULL },
951     { "de_AT",    NULL, N_("German (Austrian)"), "Deutsch (Österreich)", NULL },
952     { "de_LU",    NULL, N_("German (Luxembourg)"), "Deutsch (Luxembourg)", NULL },
953     { "de_LI",    NULL, N_("German (Liechtenstein)"), "Deutsch (Liechtenstein)", NULL },
954     { "it_CH",    NULL, N_("Italian (Swiss)"), "italiano (Svizzera)", NULL },
955     { "es_GT",    NULL, N_("Spanish (Guatemala)"), "español (Guatemala)", NULL },
956     { "es_CR",    NULL, N_("Spanish (Costa Rica)"), "español (Costa Rica)", NULL },
957     { "es_PA",    NULL, N_("Spanish (Panama)"), "español (Panamá)", NULL },
958     { "es_DO",    NULL, N_("Spanish (Dominican Republic)"), "español (República Dominicana)", NULL },
959     { "es_VE",    NULL, N_("Spanish (Venezuela)"), "español (Venezuela)", NULL },
960     { "es_CO",    NULL, N_("Spanish (Colombia)"), "español (Colombia)", NULL },
961     { "es_PE",    NULL, N_("Spanish (Peru)"), "español (Perú)", NULL },
962     { "es_AR",    NULL, N_("Spanish (Argentina)"), "español (Argentina)", NULL },
963     { "es_EC",    NULL, N_("Spanish (Ecuador)"), "español (Ecuador)", NULL },
964     { "es_CL",    NULL, N_("Spanish (Chile)"), "español (Chile)", NULL },
965     { "es_UY",    NULL, N_("Spanish (Uruguay)"), "español (Uruguay)", NULL },
966     { "es_PY",    NULL, N_("Spanish (Paraguay)"), "español (Paraguay)", NULL },
967     { "es_BO",    NULL, N_("Spanish (Bolivia)"), "español (Bolivia)", NULL },
968     { "es_SV",    NULL, N_("Spanish (El Salvador)"), "español (El Salvador)", NULL },
969     { "es_HN",    NULL, N_("Spanish (Honduras)"), "español (Honduras)", NULL },
970     { "es_NI",    NULL, N_("Spanish (Nicaragua)"), "español (Nicaragua)", NULL },
971     { "es_PR",    NULL, N_("Spanish (Puerto Rico)"), "español (Puerto Rico)", NULL },
972     { "af_AF",    NULL, N_("Afrikaans"), "Afrikaans", NULL },
973     { "ms_BN",    NULL, N_("Malay (Brunei Darussalam)"), "Bahasa Melayu (Brunei)", NULL },
974     { "no_NO",    NULL, N_("Norwegian"), "Norsk", NULL },
975     { "sr_RS",    NULL, N_("Serbian (Latin)"), "Srpski (latinica)", NULL },
976     { "sr_RS",    NULL, N_("Serbian (Cyrillic)"), "Srpski (ćirilica)", NULL },
977     { "zh_MO",    NULL, N_("Chinese (Macau)"), "Chinese (Macau)", NULL },
978     { "ar_SA",    NULL, N_("Arabic (Saudi Arabia)"), "العربية (المملكة العربية السعودية)", NULL },
979     { "ar_IQ",    NULL, N_("Arabic (Iraq)"), "العربية (العراق)", NULL },
980     { "ar_LY",    NULL, N_("Arabic (Libya)"), "العربية (ليبيا)", NULL },
981     { "ar_DZ",    NULL, N_("Arabic (Algeria)"), "العربية (الجزائر)", NULL },
982     { "ar_MA",    NULL, N_("Arabic (Morocco)"), "العربية (المغرب)", NULL },
983     { "ar_TN",    NULL, N_("Arabic (Tunisia)"), "العربية (تونس)", NULL },
984     { "ar_OM",    NULL, N_("Arabic (Oman)"), "العربية (عُمان)", NULL },
985     { "ar_YE",    NULL, N_("Arabic (Yemen)"), "العربية (اليمن)", NULL },
986     { "ar_SY",    NULL, N_("Arabic (Syria)"), "العربية (سوريا)", NULL },
987     { "ar_JO",    NULL, N_("Arabic (Jordan)"), "العربية (الأردن)", NULL },
988     { "ar_KW",    NULL, N_("Arabic (Kuwait)"), "العربية (الكويت)", NULL },
989     { "ar_AE",    NULL, N_("Arabic (UAE)"), "العربية (الإمارات العربية المتحدة)", NULL },
990     { "ar_BH",    NULL, N_("Arabic (Bahrain)"), "العربية (البحرين)", NULL },
991     { "ar_QA",    NULL, N_("Arabic (Qatar)"), "العربية (قطر)", NULL },
992     { "az_IR",    NULL, N_("Azerbaijani"), "Azərbaycan", NULL },
993     { "ha_BJ",    NULL, N_("Hausa"), "Hausa", NULL },
994     { "cy_UK",    NULL, N_("Welsh"), "Cymraeg", NULL },
995     { "xh_ZA",    NULL, N_("Xhosa"), "isiXhosa", NULL },
996     { "yo_NG",    NULL, N_("Yoruba"), "Èdè Yorùbá", NULL },
997     { "zu_ZA",    NULL, N_("Zulu"), "isiZulu", NULL },
998     { "hg_IN",    NULL, N_("Hinglish"), "Hinglish", NULL },
999     { "su_ID",    NULL, N_("Sundanese"), "Basa Sunda", NULL },
1000     { "tl_PH",    NULL, N_("Tagalog"), "Tagalog", NULL },
1001     { "af_ZA",    NULL, N_("Afrikaans"), "Afrikaans", NULL },
1002     { "jv_ID",    NULL, N_("Javanese"), "Basa Jawa", NULL },
1003     { "km_KH",    NULL, N_("Khmer"), "ខ្មែរ", NULL },
1004     { "fil",    NULL, N_("Filipino"), "Filipino", NULL },
1005     { "my",    NULL, N_("Myanmar"), "ماينمار", NULL },
1006     { "or",    NULL, N_("Odia"), "ଓଡ଼ିଆ", NULL },
1007     { "es_LA",    NULL, N_("Spanish (Latin America)"), "Español (América Latina)", NULL },
1008
1009     { "", "", "", NULL, NULL }
1010 };
1011
1012 class __LanguageLess
1013 {
1014 public:
1015     bool operator () (const __Language &lhs, const __Language &rhs) const {
1016         return strcmp (lhs.code, rhs.code) < 0;
1017     }
1018
1019     bool operator () (const __Language &lhs, const String &rhs) const {
1020         return strcmp (lhs.code, rhs.c_str ()) < 0;
1021     }
1022
1023     bool operator () (const String &lhs, const __Language &rhs) const {
1024         return strcmp (lhs.c_str (), rhs.code) < 0;
1025     }
1026 };
1027
1028 static bool language_sorted = false;
1029
1030 static __Language *
1031 __find_language (const String &lang)
1032 {
1033     if (!language_sorted) {
1034         language_sorted = true;
1035         for (int loop = 0; ((unsigned int)loop) < sizeof(__languages) / sizeof(__Language) - 1; loop++) {
1036             for (int innerLoop = loop + 1; ((unsigned int)innerLoop) < sizeof(__languages) / sizeof(__Language) - 1; innerLoop++) {
1037                 if (strcmp (__languages[loop].code, __languages[innerLoop].code) > 0) {
1038                     __Language temp = __languages[innerLoop];
1039                     __languages[innerLoop] = __languages[loop];
1040                     __languages[loop] = temp;
1041                 }
1042             }
1043         }
1044     }
1045
1046     static __Language *langs_begin = __languages;
1047     static __Language *langs_end   = __languages + sizeof (__languages) / sizeof (__Language) - 1;
1048
1049     String nlang = lang;
1050     bool contry_code = false;
1051
1052     // Normalize the language name.
1053     for (String::iterator it = nlang.begin (); it != nlang.end (); ++it) {
1054         if (*it == '-' || *it == '_') {
1055             *it = '_';
1056             contry_code = true;
1057         } else if (contry_code) {
1058             *it = toupper (*it);
1059         } else {
1060             *it = tolower (*it);
1061         }
1062     }
1063
1064     __Language *result = std::lower_bound (langs_begin, langs_end, nlang, __LanguageLess ());
1065
1066     if (result != langs_end) {
1067         if (strncmp (result->code, nlang.c_str (), strlen (result->code)) == 0 ||
1068             (strncmp (result->code, nlang.c_str (), nlang.length ()) == 0 &&
1069              strncmp (result->code, (result+1)->code, nlang.length ()) != 0))
1070             return result;
1071     }
1072
1073     return NULL;
1074 }
1075
1076 EXAPI String
1077 scim_get_language_name (const String &lang)
1078 {
1079     return String (_(scim_get_language_name_english (lang).c_str ()));
1080 }
1081
1082 EXAPI String
1083 scim_get_language_name_english (const String &lang)
1084 {
1085     __Language *result = __find_language (lang);
1086
1087     if (result)
1088         return String (result->name);
1089
1090     return String ("Other");
1091 }
1092
1093 EXAPI String
1094 scim_get_language_name_untranslated (const String &lang)
1095 {
1096     __Language *result = __find_language (lang);
1097
1098     if (result) {
1099         if (result->untranslated)
1100             return String (result->untranslated);
1101         else
1102             return String (_(result->name));
1103     }
1104
1105     return String (_("Other"));
1106 }
1107
1108 EXAPI String
1109 scim_get_language_locales (const String &lang)
1110 {
1111     __Language *result = __find_language (lang);
1112
1113     std::vector<String> locales;
1114
1115     if (result) {
1116         String good;
1117
1118         if (strlen (result->code) < 5 && result->normalized)
1119             result = __find_language (result->normalized);
1120
1121         if (result)
1122             good = scim_validate_locale (String (result->code) + ".UTF-8");
1123
1124         if (good.length ()) locales.push_back (good);
1125
1126         if (result && result->locale_suffix) {
1127             std::vector<String> suffixes;
1128
1129             scim_split_string_list (suffixes, result->locale_suffix, ',');
1130             for (size_t i = 0; i < suffixes.size (); ++ i) {
1131                 good = scim_validate_locale (String (result->code) + suffixes [i]);
1132                 if (good.length ()) locales.push_back (good);
1133             }
1134         }
1135
1136         if (result)
1137             good = scim_validate_locale (result->code);
1138
1139         if (good.length ()) locales.push_back (good);
1140     }
1141
1142     return scim_combine_string_list (locales, ',');
1143 }
1144
1145 EXAPI String
1146 scim_get_locale_language (const String &locale)
1147 {
1148     if (locale.length () == 0) return String ();
1149
1150     String str = locale.substr (0, locale.find ('.'));
1151     return scim_validate_language (str.substr (0, str.find ('@')));
1152 }
1153
1154 EXAPI String
1155 scim_validate_language (const String &lang)
1156 {
1157     __Language *result = __find_language (lang);
1158
1159     if (result)
1160         return String (result->code);
1161
1162     // Add prefix ~ to let other become the last item when sorting.
1163     return String ("~other");
1164 }
1165
1166 EXAPI String
1167 scim_get_normalized_language (const String &lang)
1168 {
1169     __Language *result = __find_language (lang);
1170
1171     if (result) {
1172         if (result->normalized) return String (result->normalized);
1173         else return String (result->code);
1174     }
1175
1176     // Add prefix ~ to let other become the last item when sorting.
1177     //return String ("~other");
1178     return String ("en");
1179 }
1180
1181 #ifndef SCIM_LAUNCHER
1182  #define SCIM_LAUNCHER  (SCIM_LIBEXECDIR "/scim-launcher")
1183 #endif
1184
1185 EXAPI int  scim_launch (bool          daemon,
1186                   const String &config,
1187                   const String &imengines,
1188                   const String &frontend,
1189                   char  * const argv [])
1190 {
1191     if (!config.length () || !imengines.length () || !frontend.length ())
1192         return -1;
1193
1194     int   i, new_argc = 0;
1195     char *new_argv [40];
1196
1197     new_argv [new_argc ++] = strdup (SCIM_LAUNCHER);
1198
1199     if (daemon)
1200         new_argv [new_argc ++] = strdup ("-d");
1201
1202     new_argv [new_argc ++] = strdup ("-c");
1203     new_argv [new_argc ++] = strdup (config.c_str ());
1204     new_argv [new_argc ++] = strdup ("-e");
1205     new_argv [new_argc ++] = strdup (imengines.c_str ());
1206     new_argv [new_argc ++] = strdup ("-f");
1207     new_argv [new_argc ++] = strdup (frontend.c_str ());
1208
1209     if (argv) {
1210         for (i = 0; argv [i] && new_argc < 39 ; ++i, ++new_argc)
1211             new_argv [new_argc] = strdup (argv [i]);
1212     }
1213
1214     new_argv [new_argc] = 0;
1215
1216     pid_t child_pid;
1217
1218     child_pid = fork ();
1219
1220     ISF_SAVE_LOG ("ppid: %d, fork result : %d, user %s", getppid (), child_pid, scim_get_user_name ().c_str ());
1221
1222     // Error fork.
1223     if (child_pid < 0) {
1224         for (i = 0; i < new_argc; ++i) {
1225             if (new_argv [i]) {
1226                 free (new_argv [i]);
1227                 new_argv [i] = NULL;
1228             }
1229         }
1230         return -1;
1231     }
1232
1233     // In child process, start scim-launcher.
1234     if (child_pid == 0) {
1235         int ret = execv (SCIM_LAUNCHER, new_argv);
1236         for (i = 0; i < new_argc; ++i) {
1237             if (new_argv [i]) {
1238                 free (new_argv [i]);
1239                 new_argv [i] = NULL;
1240             }
1241         }
1242         return ret;
1243     }
1244
1245     // In parent process, wait the child exit.
1246
1247     for (i = 0; i < new_argc; ++i) {
1248         if (new_argv [i]) {
1249             free (new_argv [i]);
1250             new_argv [i] = NULL;
1251         }
1252     }
1253
1254     int status;
1255     pid_t ret_pid;
1256
1257     ret_pid = waitpid (child_pid, &status, 0);
1258
1259     if (ret_pid == child_pid && WIFEXITED(status))
1260         return WEXITSTATUS(status);
1261
1262     return -1;
1263 }
1264
1265 #ifndef SCIM_PANEL_PROGRAM
1266   #define SCIM_PANEL_PROGRAM  (SCIM_BINDIR "/scim-panel-gtk")
1267 #endif
1268
1269 EXAPI int scim_launch_panel (bool          daemon,
1270                        const String &config,
1271                        const String &display,
1272                        char * const  argv [])
1273 {
1274     if (!config.length ())
1275         return -1;
1276
1277     String panel_program = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM, String (SCIM_PANEL_PROGRAM));
1278
1279     if (!panel_program.length ())
1280         panel_program = String (SCIM_PANEL_PROGRAM);
1281
1282     if (panel_program [0] != SCIM_PATH_DELIM) {
1283         panel_program = String (SCIM_BINDIR) +
1284                         String (SCIM_PATH_DELIM_STRING) +
1285                         panel_program;
1286     }
1287
1288     //if the file is not exist or is not executable, fallback to default
1289     if (access (panel_program.c_str (), X_OK) != 0)
1290             panel_program = String (SCIM_PANEL_PROGRAM);
1291
1292     int   i, new_argc = 0;
1293     char *new_argv [80];
1294
1295     new_argv [new_argc ++] = strdup (panel_program.c_str ());
1296
1297     if (display.length() > 0) {
1298         new_argv [new_argc ++] = strdup ("--display");
1299         new_argv [new_argc ++] = strdup (display.c_str ());
1300     }
1301
1302     new_argv [new_argc ++] = strdup ("-c");
1303     new_argv [new_argc ++] = strdup (config.c_str ());
1304
1305     if (daemon)
1306         new_argv [new_argc ++] = strdup ("-d");
1307
1308     if (argv) {
1309         for (i = 0; argv [i] && new_argc < 79; ++i, ++new_argc)
1310             new_argv [new_argc] = strdup (argv [i]);
1311     }
1312
1313     new_argv [new_argc] = 0;
1314
1315     pid_t child_pid;
1316
1317     child_pid = fork ();
1318
1319     ISF_SAVE_LOG ("ppid : %d fork result : %d", getppid (), child_pid);
1320
1321     // Error fork.
1322     if (child_pid < 0) {
1323         for (i = 0; i < new_argc; ++i) {
1324             if (new_argv [i]) {
1325                 free (new_argv [i]);
1326                 new_argv [i] = NULL;
1327             }
1328         }
1329         return -1;
1330     }
1331
1332     // In child process, start scim-launcher.
1333     if (child_pid == 0) {
1334         int ret = execv (panel_program.c_str (), new_argv);
1335         for (i = 0; i < new_argc; ++i) {
1336             if (new_argv [i]) {
1337                 free (new_argv [i]);
1338                 new_argv [i] = NULL;
1339             }
1340         }
1341         return ret;
1342     }
1343
1344     // In parent process, wait the child exit.
1345
1346     for (i = 0; i < new_argc; ++i) {
1347         if (new_argv [i]) {
1348             free (new_argv [i]);
1349             new_argv [i] = NULL;
1350         }
1351     }
1352
1353     int status;
1354     pid_t ret_pid;
1355
1356     ret_pid = waitpid (child_pid, &status, 0);
1357
1358     if (ret_pid == child_pid && WIFEXITED(status))
1359         return WEXITSTATUS(status);
1360
1361     return -1;
1362 }
1363
1364 EXAPI void
1365 scim_usleep (unsigned int usec)
1366 {
1367     if (usec == 0) return;
1368
1369 #if HAVE_NANOSLEEP
1370     struct timespec req, rem;
1371
1372     req.tv_sec = usec / 1000000;
1373     req.tv_nsec = ((unsigned long int)usec % 1000000) * 1000;
1374
1375     while (nanosleep (&req, &rem) == -1 && errno == EINTR && (rem.tv_sec != 0 || rem.tv_nsec != 0))
1376         req = rem;
1377 #elif HAVE_USLEEP
1378     unsigned int sec = usec / 1000000;
1379     usec %= 1000000;
1380
1381     for (unsigned int i = 0; i < sec; ++i)
1382         sleep (1);
1383
1384     usleep (usec);
1385 #else
1386     unsigned int sec = usec / 1000000;
1387
1388     sleep (sec ? sec : 1);
1389 #endif
1390 }
1391
1392 EXAPI void scim_daemon ()
1393 {
1394 #if HAVE_DAEMON
1395     LOGD ("ppid:%d  calling daemon()", getppid ());
1396
1397     if (daemon (0, 0) == -1)
1398         std::cerr << "Error to make SCIM into a daemon!\n";
1399
1400     LOGD ("ppid:%d  daemon() called", getppid ());
1401
1402     return;
1403 #else
1404     pid_t id;
1405
1406     id = fork ();
1407     if (id == -1) {
1408         std::cerr << "Error to make SCIM into a daemon!\n";
1409         return;
1410     } else if (id > 0) {
1411         _exit (0);
1412     }
1413
1414     ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1415
1416     id = fork ();
1417     if (id == -1) {
1418         std::cerr << "Error to make SCIM into a daemon!\n";
1419         return;
1420     } else if (id > 0) {
1421         _exit (0);
1422     }
1423
1424     ISF_SAVE_LOG ("ppid:%d fork result : %d", getppid (), id);
1425
1426     return;
1427 #endif
1428 }
1429
1430 EXAPI void isf_save_log (const char *fmt, ...)
1431 {
1432     char buf[1024] = {0};
1433     va_list ap;
1434
1435     va_start (ap, fmt);
1436     vsnprintf (buf, sizeof (buf), fmt, ap);
1437     va_end (ap);
1438
1439     const int MAX_LOG_FILE_SIZE = 12 * 1024; /* 12KB */
1440
1441     static bool size_exceeded = false;
1442     static struct stat st;
1443     if (!size_exceeded) {
1444         String strLogFile = scim_get_user_data_dir () + String (SCIM_PATH_DELIM_STRING) + String ("isf.log");
1445         int ret = stat(strLogFile.c_str(), &st);
1446         if (ret == 0 || (ret == -1 && errno == ENOENT)) {
1447             if (st.st_size < MAX_LOG_FILE_SIZE) {
1448                 std::ofstream isf_log_file (strLogFile.c_str (), std::ios::app);
1449                 isf_log_file << buf << std::endl;
1450                 isf_log_file.flush ();
1451             } else {
1452                 size_exceeded = true;
1453             }
1454         }
1455     }
1456
1457     LOGD ("%s", buf);
1458 }
1459
1460 static struct timeval _t0 = {0, 0};
1461 static struct timeval _t1;
1462
1463 static clock_t _p_t0;
1464 static clock_t _p_t1;
1465
1466 void ISF_PROF_DEBUG_TIME_BEGIN ()
1467 {
1468     struct tms tms;
1469
1470     _p_t0 = times (&tms);
1471 }
1472
1473 /* Measure elapsed time */
1474 void ISF_PROF_DEBUG_TIME_END (char const* format, char const* func, int line)
1475 {
1476     float etime = 0.0;
1477     struct tms tms;
1478     static long clktck = 0;
1479
1480     if (clktck == 0)
1481         if ((clktck = sysconf (_SC_CLK_TCK)) < 0)
1482             return;
1483
1484     _p_t1 = times (&tms);
1485
1486     etime = (_p_t1 - _p_t0) / (double) clktck;
1487
1488     printf (mzc_red "[Format:%s][Func:%s][Line:%d]" mzc_normal "\n", format, func, line);
1489     printf (mzc_red "[T:%ld][E:%f]" mzc_normal " ", _p_t1, etime);
1490
1491     return;
1492 }
1493
1494 /* Measure elapsed time */
1495 void ISF_PROF_DEBUG_TIME (char const* func, int line, char const* str)
1496 {
1497     double etime = 0.0;
1498
1499     if (_t0.tv_sec == 0 && _t0.tv_usec == 0) {
1500         gettimeofday (&_t0, NULL);
1501         return;
1502     }
1503
1504     gettimeofday (&_t1, NULL);
1505
1506     if (_t0.tv_usec != 0) {
1507         etime = ((_t1.tv_sec * 1000000 + _t1.tv_usec) - (_t0.tv_sec * 1000000 + _t0.tv_usec))/1000000.0;
1508     }
1509
1510     printf (mzc_red "[%s:%04d] [T:%ld][E:%f] %s " mzc_normal " \n", func, line, (_t1.tv_sec * 1000000 + _t1.tv_usec), etime, str);
1511
1512     _t0 = _t1;
1513
1514     return;
1515 }
1516
1517 EXAPI void gettime (clock_t clock_start, const char* str)
1518 {
1519 #ifdef ISF_PROF
1520     struct  tms tiks_buf;
1521     double  clock_tiks = (double)sysconf (_SC_CLK_TCK);
1522     clock_t times_tiks = times (&tiks_buf);
1523     double  times_secs = (double)(times_tiks - clock_start) / clock_tiks;
1524     double  utime      = (double)tiks_buf.tms_utime / clock_tiks;
1525     double  stime      = (double)tiks_buf.tms_stime / clock_tiks;
1526     printf (mzc_red "%s Times:   %.3f \t User:   %.3f \t System:   %.3f " mzc_normal "\n", str, (double)times_secs, (double)utime , (double)stime);
1527 #endif
1528 }
1529
1530 } // namespace scim
1531
1532 /*
1533 vi:ts=4:ai:nowrap:expandtab
1534 */