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