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