1 /*
2 * Smart Common Input Method
3 *
4 * Copyright (c) 2002-2005 James Su <suzhe@tsinghua.org.cn>
5 *
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307 USA
21 *
22 * $Id: scim_utility.cpp,v 1.48.2.5 2006/11/02 04:11:51 suzhe Exp $
23 */
24
25 #define Uses_SCIM_UTILITY
26 #define Uses_SCIM_CONFIG_PATH
27 #define Uses_C_LOCALE
28 #define Uses_C_ICONV
29 #define Uses_C_STDLIB
30 #define Uses_C_STRING
31
32 #include <langinfo.h>
33 #include <pwd.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <stdio.h>
41 #include <time.h>
42 #include <errno.h>
43
44 #include "scim_private.h"
45 #include "scim.h"
46
47 namespace scim {
48
49 int
utf8_mbtowc(ucs4_t * pwc,const unsigned char * src,int src_len)50 utf8_mbtowc (ucs4_t *pwc, const unsigned char *src, int src_len)
51 {
52 if (!pwc)
53 return 0;
54
55 unsigned char c = src [0];
56
57 if (c < 0x80) {
58 *pwc = c;
59 return 1;
60 } else if (c < 0xc2) {
61 return RET_ILSEQ;
62 } else if (c < 0xe0) {
63 if (src_len < 2)
64 return RET_TOOFEW(0);
65 if (!((src [1] ^ 0x80) < 0x40))
66 return RET_ILSEQ;
67 *pwc = ((ucs4_t) (c & 0x1f) << 6)
68 | (ucs4_t) (src [1] ^ 0x80);
69 return 2;
70 } else if (c < 0xf0) {
71 if (src_len < 3)
72 return RET_TOOFEW(0);
73 if (!((src [1] ^ 0x80) < 0x40 && (src [2] ^ 0x80) < 0x40
74 && (c >= 0xe1 || src [1] >= 0xa0)))
75 return RET_ILSEQ;
76 *pwc = ((ucs4_t) (c & 0x0f) << 12)
77 | ((ucs4_t) (src [1] ^ 0x80) << 6)
78 | (ucs4_t) (src [2] ^ 0x80);
79 return 3;
80 } else if (c < 0xf8) {
81 if (src_len < 4)
82 return RET_TOOFEW(0);
83 if (!((src [1] ^ 0x80) < 0x40 && (src [2] ^ 0x80) < 0x40
84 && (src [3] ^ 0x80) < 0x40
85 && (c >= 0xf1 || src [1] >= 0x90)))
86 return RET_ILSEQ;
87 *pwc = ((ucs4_t) (c & 0x07) << 18)
88 | ((ucs4_t) (src [1] ^ 0x80) << 12)
89 | ((ucs4_t) (src [2] ^ 0x80) << 6)
90 | (ucs4_t) (src [3] ^ 0x80);
91 return 4;
92 } else if (c < 0xfc) {
93 if (src_len < 5)
94 return RET_TOOFEW(0);
95 if (!((src [1] ^ 0x80) < 0x40 && (src [2] ^ 0x80) < 0x40
96 && (src [3] ^ 0x80) < 0x40 && (src [4] ^ 0x80) < 0x40
97 && (c >= 0xf9 || src [1] >= 0x88)))
98 return RET_ILSEQ;
99 *pwc = ((ucs4_t) (c & 0x03) << 24)
100 | ((ucs4_t) (src [1] ^ 0x80) << 18)
101 | ((ucs4_t) (src [2] ^ 0x80) << 12)
102 | ((ucs4_t) (src [3] ^ 0x80) << 6)
103 | (ucs4_t) (src [4] ^ 0x80);
104 return 5;
105 } else if (c < 0xfe) {
106 if (src_len < 6)
107 return RET_TOOFEW(0);
108 if (!((src [1] ^ 0x80) < 0x40 && (src [2] ^ 0x80) < 0x40
109 && (src [3] ^ 0x80) < 0x40 && (src [4] ^ 0x80) < 0x40
110 && (src [5] ^ 0x80) < 0x40
111 && (c >= 0xfd || src [1] >= 0x84)))
112 return RET_ILSEQ;
113 *pwc = ((ucs4_t) (c & 0x01) << 30)
114 | ((ucs4_t) (src [1] ^ 0x80) << 24)
115 | ((ucs4_t) (src [2] ^ 0x80) << 18)
116 | ((ucs4_t) (src [3] ^ 0x80) << 12)
117 | ((ucs4_t) (src [4] ^ 0x80) << 6)
118 | (ucs4_t) (src [5] ^ 0x80);
119 return 6;
120 } else
121 return RET_ILSEQ;
122 }
123
124 int
utf8_wctomb(unsigned char * dest,ucs4_t wc,int dest_size)125 utf8_wctomb (unsigned char *dest, ucs4_t wc, int dest_size)
126 {
127 if (!dest)
128 return 0;
129
130 int count;
131 if (wc < 0x80)
132 count = 1;
133 else if (wc < 0x800)
134 count = 2;
135 else if (wc < 0x10000)
136 count = 3;
137 else if (wc < 0x200000)
138 count = 4;
139 else if (wc < 0x4000000)
140 count = 5;
141 else if (wc <= 0x7fffffff)
142 count = 6;
143 else
144 return RET_ILSEQ;
145 if (dest_size < count)
146 return RET_TOOSMALL;
147 switch (count) { /* note: code falls through cases! */
148 case 6: dest [5] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x4000000;
149 case 5: dest [4] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x200000;
150 case 4: dest [3] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x10000;
151 case 3: dest [2] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0x800;
152 case 2: dest [1] = 0x80 | (wc & 0x3f); wc = wc >> 6; wc |= 0xc0;
153 case 1: dest [0] = wc;
154 }
155 return count;
156 }
157
158 ucs4_t
utf8_read_wchar(std::istream & is)159 utf8_read_wchar (std::istream &is)
160 {
161 unsigned char utf8[6];
162 ucs4_t wc;
163 int count;
164 for (int i=0; i<6; ++i) {
165 is.read ((char*)(utf8+i), sizeof(unsigned char));
166 if ((count=utf8_mbtowc (&wc, utf8, i+1)) > 0)
167 return wc;
168 if (count == RET_ILSEQ)
169 return 0;
170 }
171 return 0;
172 }
173
174 WideString
utf8_read_wstring(std::istream & is,ucs4_t delim,bool rm_delim)175 utf8_read_wstring (std::istream &is, ucs4_t delim, bool rm_delim)
176 {
177 WideString str;
178 ucs4_t wc;
179 while ((wc = utf8_read_wchar (is)) > 0) {
180 if (wc != delim)
181 str.push_back (wc);
182 else {
183 if (!rm_delim)
184 str.push_back (wc);
185 break;
186 }
187 }
188 return str;
189 }
190
191 std::ostream &
utf8_write_wchar(std::ostream & os,ucs4_t wc)192 utf8_write_wchar (std::ostream &os, ucs4_t wc)
193 {
194 unsigned char utf8[6];
195 int count = 0;
196
197 if ((count=utf8_wctomb (utf8, wc, 6)) > 0)
198 os.write ((char*)utf8, count * sizeof (unsigned char));
199
200 return os;
201 }
202
203 std::ostream &
utf8_write_wstring(std::ostream & os,const WideString & wstr)204 utf8_write_wstring (std::ostream &os, const WideString & wstr)
205 {
206 for (unsigned int i=0; i<wstr.size (); ++i)
207 utf8_write_wchar (os, wstr [i]);
208
209 return os;
210 }
211
212 WideString
utf8_mbstowcs(const String & str)213 utf8_mbstowcs (const String & str)
214 {
215 WideString wstr;
216 ucs4_t wc;
217 unsigned int sn = 0;
218 int un = 0;
219
220 const unsigned char *s = (const unsigned char *) str.c_str ();
221
222 while (sn < str.length () && *s != 0 &&
223 (un=utf8_mbtowc (&wc, s, str.length () - sn)) > 0) {
224 wstr.push_back (wc);
225 s += un;
226 sn += un;
227 }
228 return wstr;
229 }
230
231 WideString
utf8_mbstowcs(const char * str,int len)232 utf8_mbstowcs (const char *str, int len)
233 {
234 WideString wstr;
235
236 if (str) {
237 ucs4_t wc;
238 unsigned int sn = 0;
239 int un = 0;
240
241 if (len < 0) len = strlen (str);
242
243 while (sn < len && *str != 0 && (un=utf8_mbtowc (&wc, (const unsigned char *)str, len - sn)) > 0) {
244 wstr.push_back (wc);
245 str += un;
246 sn += un;
247
248 }
249 }
250 return wstr;
251 }
252
253 String
utf8_wcstombs(const WideString & wstr)254 utf8_wcstombs (const WideString & wstr)
255 {
256 String str;
257 char utf8 [6];
258 int un = 0;
259
260 for (unsigned int i = 0; i<wstr.size (); ++i) {
261 un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
262 if (un > 0)
263 str.append (utf8, un);
264 }
265 return str;
266 }
267
268 String
utf8_wcstombs(const ucs4_t * wstr,int len)269 utf8_wcstombs (const ucs4_t *wstr, int len)
270 {
271 String str;
272 char utf8 [6];
273 int un = 0;
274
275 if (wstr) {
276 if (len < 0)
277 for (len = 0; wstr [len]; ++len) NULL;
278
279 for (int i = 0; i < len; ++i) {
280 un = utf8_wctomb ((unsigned char*)utf8, wstr [i], 6);
281 if (un > 0)
282 str.append (utf8, un);
283 }
284 }
285 return str;
286 }
287
288 String
scim_validate_locale(const String & locale)289 scim_validate_locale (const String& locale)
290 {
291 String good;
292
293 String last = String (setlocale (LC_CTYPE, 0));
294
295 if (setlocale (LC_CTYPE, locale.c_str ())) {
296 good = locale;
297 } else {
298 std::vector<String> vec;
299 if (scim_split_string_list (vec, locale, '.') == 2) {
300 if (isupper (vec[1][0])) {
301 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
302 *i = (char) tolower (*i);
303 } else {
304 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
305 *i = (char) toupper (*i);
306 }
307 if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ())) {
308 good = vec [0] + "." + vec[1];
309 }
310 }
311 }
312
313 setlocale (LC_CTYPE, last.c_str ());
314
315 return good;
316 }
317
318 String
scim_get_locale_encoding(const String & locale)319 scim_get_locale_encoding (const String& locale)
320 {
321 String last = String (setlocale (LC_CTYPE, 0));
322 String encoding;
323
324 if (setlocale (LC_CTYPE, locale.c_str ()))
325 encoding = String (nl_langinfo (CODESET));
326 else {
327 std::vector<String> vec;
328 if (scim_split_string_list (vec, locale, '.') == 2) {
329 if (isupper (vec[1][0])) {
330 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
331 *i = (char) tolower (*i);
332 } else {
333 for (String::iterator i=vec[1].begin (); i!=vec[1].end (); ++i)
334 *i = (char) toupper (*i);
335 }
336 if (setlocale (LC_CTYPE, (vec[0] + "." + vec[1]).c_str ()))
337 encoding = String (nl_langinfo (CODESET));
338 }
339
340 }
341
342 setlocale (LC_CTYPE, last.c_str ());
343
344 return encoding;
345 }
346
347 int
scim_get_locale_maxlen(const String & locale)348 scim_get_locale_maxlen (const String& locale)
349 {
350 int maxlen;
351
352 String last = String (setlocale (LC_CTYPE, 0));
353
354 if (setlocale (LC_CTYPE, locale.c_str ()))
355 maxlen = MB_CUR_MAX;
356 else
357 maxlen = 1;
358
359 setlocale (LC_CTYPE, last.c_str ());
360 return maxlen;
361 }
362
363 int
scim_split_string_list(std::vector<String> & vec,const String & str,char delim)364 scim_split_string_list (std::vector<String>& vec, const String& str, char delim)
365 {
366 int count = 0;
367
368 String temp;
369 String::const_iterator bg, ed;
370
371 vec.clear ();
372
373 bg = str.begin ();
374 ed = str.begin ();
375
376 while (bg != str.end () && ed != str.end ()) {
377 for (; ed != str.end (); ++ed) {
378 if (*ed == delim)
379 break;
380 }
381 temp.assign (bg, ed);
382 vec.push_back (temp);
383 ++count;
384
385 if (ed != str.end ())
386 bg = ++ ed;
387 }
388 return count;
389 }
390
391 String
scim_combine_string_list(const std::vector<String> & vec,char delim)392 scim_combine_string_list (const std::vector<String>& vec, char delim)
393 {
394 String result;
395 for (std::vector<String>::const_iterator i = vec.begin (); i!=vec.end (); ++i) {
396 result += *i;
397 if (i+1 != vec.end ())
398 result += delim;
399 }
400 return result;
401 }
402
403 bool
scim_if_wchar_ucs4_equal()404 scim_if_wchar_ucs4_equal ()
405 {
406 if (sizeof (wchar_t) != sizeof (ucs4_t))
407 return false;
408
409 iconv_t cd;
410 wchar_t wcbuf [2] = {0,0};
411 ucs4_t ucsbuf [2] = {0x4E00, 0x0001};
412 size_t wclen = 2 * sizeof (wchar_t);
413 size_t ucslen = 2 * sizeof (ucs4_t);
414
415 char *wcp = (char *) wcbuf;
416 ICONV_CONST char *ucsp = (ICONV_CONST char *) ucsbuf;
417
418 if (scim_is_little_endian ())
419 cd = iconv_open ("UCS-4LE", "wchar_t");
420 else
421 cd = iconv_open ("UCS-4BE", "wchar_t");
422
423 if (cd == (iconv_t) -1)
424 return false;
425
426 iconv (cd, &ucsp, &ucslen, &wcp, &wclen);
427
428 iconv_close (cd);
429
430 if (wcbuf [0] == (wchar_t) ucsbuf [0] &&
431 wcbuf [1] == (wchar_t) ucsbuf [1])
432 return true;
433
434 return false;
435 }
436
437 static struct {
438 ucs4_t half;
439 ucs4_t full;
440 ucs4_t size;
441 } __half_full_table [] = {
442 {0x0020, 0x3000, 1},
443 {0x0021, 0xFF01, 0x5E},
444 {0x00A2, 0xFFE0, 2},
445 {0x00A5, 0xFFE5, 1},
446 {0x00A6, 0xFFE4, 1},
447 {0x00AC, 0xFFE2, 1},
448 {0x00AF, 0xFFE3, 1},
449 {0x20A9, 0xFFE6, 1},
450 {0xFF61, 0x3002, 1},
451 {0xFF62, 0x300C, 2},
452 {0xFF64, 0x3001, 1},
453 {0xFF65, 0x30FB, 1},
454 {0xFF66, 0x30F2, 1},
455 {0xFF67, 0x30A1, 1},
456 {0xFF68, 0x30A3, 1},
457 {0xFF69, 0x30A5, 1},
458 {0xFF6A, 0x30A7, 1},
459 {0xFF6B, 0x30A9, 1},
460 {0xFF6C, 0x30E3, 1},
461 {0xFF6D, 0x30E5, 1},
462 {0xFF6E, 0x30E7, 1},
463 {0xFF6F, 0x30C3, 1},
464 {0xFF70, 0x30FC, 1},
465 {0xFF71, 0x30A2, 1},
466 {0xFF72, 0x30A4, 1},
467 {0xFF73, 0x30A6, 1},
468 {0xFF74, 0x30A8, 1},
469 {0xFF75, 0x30AA, 2},
470 {0xFF77, 0x30AD, 1},
471 {0xFF78, 0x30AF, 1},
472 {0xFF79, 0x30B1, 1},
473 {0xFF7A, 0x30B3, 1},
474 {0xFF7B, 0x30B5, 1},
475 {0xFF7C, 0x30B7, 1},
476 {0xFF7D, 0x30B9, 1},
477 {0xFF7E, 0x30BB, 1},
478 {0xFF7F, 0x30BD, 1},
479 {0xFF80, 0x30BF, 1},
480 {0xFF81, 0x30C1, 1},
481 {0xFF82, 0x30C4, 1},
482 {0xFF83, 0x30C6, 1},
483 {0xFF84, 0x30C8, 1},
484 {0xFF85, 0x30CA, 6},
485 {0xFF8B, 0x30D2, 1},
486 {0xFF8C, 0x30D5, 1},
487 {0xFF8D, 0x30D8, 1},
488 {0xFF8E, 0x30DB, 1},
489 {0xFF8F, 0x30DE, 5},
490 {0xFF94, 0x30E4, 1},
491 {0xFF95, 0x30E6, 1},
492 {0xFF96, 0x30E8, 6},
493 {0xFF9C, 0x30EF, 1},
494 {0xFF9D, 0x30F3, 1},
495 {0xFFA0, 0x3164, 1},
496 {0xFFA1, 0x3131, 30},
497 {0xFFC2, 0x314F, 6},
498 {0xFFCA, 0x3155, 6},
499 {0xFFD2, 0x315B, 9},
500 {0xFFE9, 0x2190, 4},
501 {0xFFED, 0x25A0, 1},
502 {0xFFEE, 0x25CB, 1},
503 {0,0,0}
504 };
505
506
507 /**
508 * convert a half width unicode char to full width char
509 */
510 ucs4_t
scim_wchar_to_full_width(ucs4_t code)511 scim_wchar_to_full_width (ucs4_t code)
512 {
513 int i=0;
514 while (__half_full_table [i].size) {
515 if (code >= __half_full_table [i].half &&
516 code < __half_full_table [i].half +
517 __half_full_table [i].size)
518 return __half_full_table [i].full +
519 (code - __half_full_table [i].half);
520 ++ i;
521 }
522 return code;
523 }
524
525 /**
526 * convert a full width unicode char to half width char
527 */
528 ucs4_t
scim_wchar_to_half_width(ucs4_t code)529 scim_wchar_to_half_width (ucs4_t code)
530 {
531 int i=0;
532 while (__half_full_table [i].size) {
533 if (code >= __half_full_table [i].full &&
534 code < __half_full_table [i].full +
535 __half_full_table [i].size)
536 return __half_full_table [i].half +
537 (code - __half_full_table [i].full);
538 ++ i;
539 }
540 return code;
541 }
542
543 String
scim_get_home_dir()544 scim_get_home_dir ()
545 {
546 const char * home_dir = 0;
547
548 struct passwd *pw;
549
550 setpwent ();
551 pw = getpwuid (getuid ());
552 endpwent ();
553
554 if (pw) {
555 home_dir = pw->pw_dir;
556 }
557
558 if (!home_dir) {
559 home_dir = getenv ("HOME");
560 }
561
562 return String (home_dir);
563 }
564
565 String
scim_get_user_name()566 scim_get_user_name ()
567 {
568 struct passwd *pw;
569 const char *user_name;
570
571 setpwent ();
572 pw = getpwuid (getuid ());
573 endpwent ();
574
575 if (pw && pw->pw_name)
576 return String (pw->pw_name);
577 else if ((user_name = getenv ("USER")) != NULL)
578 return String (user_name);
579
580 char uid_str [10];
581
582 snprintf (uid_str, 10, "%u", getuid ());
583
584 return String (uid_str);
585 }
586
587 String
scim_get_user_data_dir()588 scim_get_user_data_dir ()
589 {
590 String dir = scim_get_home_dir () + String ("/.scim");
591 scim_make_dir (dir);
592 return dir;
593 }
594
595 String
scim_get_current_locale()596 scim_get_current_locale ()
597 {
598 char *locale = setlocale (LC_MESSAGES, 0);
599
600 if (locale) return String (locale);
601 return String ();
602 }
603
scim_get_current_language()604 String scim_get_current_language ()
605 {
606 return scim_get_locale_language (scim_get_current_locale ());
607 }
608
609 bool
scim_is_little_endian()610 scim_is_little_endian ()
611 {
612 short endian = 1;
613 return (*((char *)&endian) != 0);
614 }
615
616 size_t
scim_load_file(const String & filename,char ** bufptr)617 scim_load_file (const String &filename, char **bufptr)
618 {
619 if (!filename.length ())
620 return 0;
621
622 struct stat statbuf;
623
624 if (stat (filename.c_str (), &statbuf) < 0 ||
625 !S_ISREG (statbuf.st_mode) ||
626 !statbuf.st_size)
627 return 0;
628
629 if (!bufptr)
630 return statbuf.st_size;
631
632 FILE *fp = fopen (filename.c_str (), "r");
633
634 if (fp == NULL) {
635 *bufptr = 0;
636 return 0;
637 }
638
639 try {
640 *bufptr = new char [statbuf.st_size];
641 } catch (...) {
642 fclose (fp);
643 throw;
644 }
645
646 if (! (*bufptr)) {
647 fclose (fp);
648 return 0;
649 }
650
651 size_t size = fread (*bufptr, 1, statbuf.st_size, fp);
652
653 fclose (fp);
654
655 if (!size) {
656 delete [] *bufptr;
657 *bufptr = 0;
658 }
659
660 return size;
661 }
662
663 bool
scim_make_dir(const String & dir)664 scim_make_dir (const String &dir)
665 {
666 std::vector <String> paths;
667 String path;
668
669 scim_split_string_list (paths, dir, SCIM_PATH_DELIM);
670
671 for (size_t i = 0; i < paths.size (); ++i) {
672 path += SCIM_PATH_DELIM_STRING + paths [i];
673
674 //Make the dir if it's not exist.
675 if (access (path.c_str (), R_OK) != 0) {
676 mkdir (path.c_str (), S_IRUSR | S_IWUSR | S_IXUSR);
677 if (access (path.c_str (), R_OK) != 0)
678 return false;
679 }
680 }
681 return true;
682 }
683
684 struct __Language {
685 const char *code;
686 const char *normalized;
687 const char *name;
688 const char *untranslated;
689 const char *locale_suffix;
690 };
691
692 static __Language __languages [] = {
693 { "C", NULL, N_("English/Keyboard"), NULL, NULL},
694 { "am_ET", NULL, N_("Amharic"), NULL, NULL },
695 { "ar", "ar_EG", N_("Arabic"), NULL, NULL },
696 { "ar_EG", NULL, N_("Arabic (Egypt)"), NULL, NULL },
697 { "ar_LB", NULL, N_("Arabic (Lebanon)"), NULL, NULL },
698 { "as_IN", NULL, N_("Assamese"), NULL, NULL},
699 { "az_AZ", NULL, N_("Azerbaijani"), NULL, NULL },
700 { "be_BY", NULL, N_("Belarusian"), "Беларуская мова", NULL },
701 { "bg_BG", NULL, N_("Bulgarian"), "Български", NULL },
702 { "bn", "bn_BD", N_("Bengali"), "বাংলা", NULL },
703 { "bn_BD", NULL, N_("Bengali"), "বাংলা", NULL },
704 { "bn_IN", NULL, N_("Bengali (India)"), "বাংলা", NULL },
705 { "bo", NULL, N_("Tibetan"), NULL, NULL },
706 { "bs_BA", NULL, N_("Bosnian"), NULL, NULL },
707 { "ca_ES", NULL, N_("Catalan"), "Català", "@euro" },
708 { "cs_CZ", NULL, N_("Czech"), "čeština", NULL },
709 { "cy_GB", NULL, N_("Welsh"), "Cymraeg", NULL },
710 { "da_DK", NULL, N_("Danish"), "dansk", "@euro" },
711 { "de_DE", NULL, N_("German"), "Deutsch", "@euro" },
712 { "dv_MV", NULL, N_("Divehi"), "ދިވެހިބަސް", NULL },
713 { "el_GR", NULL, N_("Greek"), "ελληνικά", NULL },
714 { "en" , "en_US", N_("English"), "English", NULL },
715 { "en_AU", NULL, N_("English (Australian)"), "Australian English", NULL },
716 { "en_CA", NULL, N_("English (Canadian)"), "Canadian English", NULL },
717 { "en_GB", NULL, N_("English (British)"), "British English", ".iso885915" },
718 { "en_IE", NULL, N_("English (Ireland)"), "Irish English", NULL },
719 { "en_US", NULL, N_("English (American)"), "American English", ".iso885915" },
720 { "eo", NULL, N_("Esperanto"), "Esperanto", NULL },
721 { "es", "es_ES", N_("Spanish"), "Español", NULL },
722 { "es_ES", NULL, N_("Spanish"), "Español", "@euro" },
723 { "es_MX", NULL, N_("Spanish (Mexico)"), "Español (Mexico)", NULL },
724 { "et_EE", NULL, N_("Estonian"), "Eesti", ".iso885915" },
725 { "eu_ES", NULL, N_("Basque"), "Euskara", "@euro" },
726 { "fa_IR", NULL, N_("Persian"), "فارسی", NULL },
727 { "fi_FI", NULL, N_("Finnish"), "Suomi", "@euro" },
728 { "fr_FR", NULL, N_("French"), "Français", "@euro" },
729 { "ga_IE", NULL, N_("Irish"), "Gaeilge", "@euro" },
730 { "gl_ES", NULL, N_("Galician"), "Galego", "@euro" },
731 { "gu_IN", NULL, N_("Gujarati"), NULL, NULL },
732 { "he_IL", NULL, N_("Hebrew"), "עברית", NULL },
733 { "hi_IN", NULL, N_("Hindi"), "हिंदी", NULL },
734 { "hr_HR", NULL, N_("Croatian"), "Hrvatski", NULL },
735 { "hu_HU", NULL, N_("Hungarian"), "Magyar", NULL },
736 { "hy_AM", NULL, N_("Armenian"), "Հայերէն", NULL },
737 { "ia" , NULL, N_("Interlingua"), NULL },
738 { "id_ID", NULL, N_("Indonesian"), "Bahasa Indonesia", NULL },
739 { "is_IS", NULL, N_("Icelandic"), NULL, NULL },
740 { "it_IT", NULL, N_("Italian"), "Italiano", "@euro" },
741 { "iw_IL", NULL, N_("Hebrew"), "עברית", NULL },
742 { "ja_JP", NULL, N_("Japanese"), "日本語", ".EUC-JP,.SJIS,.eucJP" },
743 { "ka_GE", NULL, N_("Georgian"), "ქართული", NULL },
744 { "kk_KZ", NULL, N_("Kazakh"), NULL, NULL },
745 { "km", NULL, N_("Cambodian"), NULL, NULL },
746 { "kn_IN", NULL, N_("Kannada"), "ಕನ್ನಡ", NULL },
747 { "ko_KR", NULL, N_("Korean"), "한국어", ".EUC-KR,.eucKR" },
748 { "lo_LA", NULL, N_("Laothian"), NULL, NULL },
749 { "lt_LT", NULL, N_("Lithuanian"), "Lietuvių", NULL },
750 { "lv_LV", NULL, N_("Latvian"), "Latviešu", NULL },
751 { "mk_MK", NULL, N_("Macedonian"), NULL, NULL },
752 { "ml_IN", NULL, N_("Malayalam"), "മലയാളം", NULL },
753 { "mn_MN", NULL, N_("Mongolian"), "Монгол", NULL },
754 { "mr_IN", NULL, N_("Marathi"), NULL, NULL },
755 { "ms_MY", NULL, N_("Malay"), "Bahasa Melayu", NULL },
756 { "my_MM", NULL, N_("Burmese"), "", NULL },
757 { "ne_NP", NULL, N_("Nepali"), NULL, NULL },
758 { "nl_NL", NULL, N_("Dutch"), "Nederlands", "@euro" },
759 { "nn_NO", NULL, N_("Norwegian (nynorsk)"), "Norsk (nynorsk)", NULL },
760 { "no_NO", NULL, N_("Norwegian (bokmal)"), "Norsk (bokmål)", NULL },
761 { "or_IN", NULL, N_("Oriya"), NULL, NULL },
762 { "pa_IN", NULL, N_("Punjabi"), NULL, NULL },
763 { "pl_PL", NULL, N_("Polish"), "Polski", NULL },
764 { "pt", "pt_PT", N_("Portuguese"), "Português", NULL },
765 { "pt_BR", NULL, N_("Portuguese (Brazil)"), "Português do Brasil", NULL },
766 { "pt_PT", NULL, N_("Portuguese"), "Português", "@euro" },
767 { "ro_RO", NULL, N_("Romanian"), "Română", NULL },
768 { "ru_RU", NULL, N_("Russian"), "русский", ".koi8r" },
769 { "si_LK", NULL, N_("Sinhala"), "සිංහල", NULL },
770 { "sk_SK", NULL, N_("Slovak"), "Slovenský", NULL },
771 { "sl_SI", NULL, N_("Slovenian"), "Slovenščina", NULL },
772 { "sq_AL", NULL, N_("Albanian"), "Shqip", NULL },
773 { "sr", "sr_YU", N_("Serbian"), "српски", NULL },
774 { "sr_CS", NULL, N_("Serbian"), "српски", NULL },
775 { "sr_YU", NULL, N_("Serbian"), "српски", "@cyrillic" },
776 { "sv", "sv_SE", N_("Swedish"), "Svenska", NULL },
777 { "sv_FI", NULL, N_("Swedish (Finland)"), "Svenska (Finland)", "@euro" },
778 { "sv_SE", NULL, N_("Swedish"), "Svenska", ".iso885915" },
779 { "ta_IN", NULL, N_("Tamil"), NULL, NULL },
780 { "te_IN", NULL, N_("Telugu"), NULL, NULL },
781 { "th_TH", NULL, N_("Thai"), "ไทย", NULL },
782 { "tr_TR", NULL, N_("Turkish"), "Türkçe", NULL },
783 { "ug", NULL, N_("Uighur"), NULL, NULL },
784 { "uk_UA", NULL, N_("Ukrainian"), "Українська", NULL },
785 { "ur_PK", NULL, N_("Urdu"), NULL, NULL },
786 { "uz_UZ", NULL, N_("Uzbek"), NULL, "@cyrillic" },
787 { "vi_VN", NULL, N_("Vietnamese"), "Việt Nam", ".tcvn" },
788 { "wa_BE", NULL, N_("Walloon"), "Walon", "@euro" },
789 { "yi" , "yi_US", N_("Yiddish"), "ייִדיש", NULL },
790 { "yi_US", NULL, N_("Yiddish"), "ייִדיש", NULL },
791 { "zh", "zh_CN", N_("Chinese"), "中文", NULL },
792 { "zh_CN", NULL, N_("Chinese (simplified)"), "中文 (简体)", ".GB18030,.GBK,.GB2312,.eucCN" },
793 { "zh_HK", "zh_TW", N_("Chinese (traditional)"), "中文 (繁體)", NULL },
794 { "zh_SG", "zh_CN", N_("Chinese (simplified)"), "中文 (简体)", ".GBK" },
795 { "zh_TW", NULL, N_("Chinese (traditional)"), "中文 (繁體)", ".eucTW" },
796 { "", "", "", NULL, NULL }
797 };
798
799 class __LanguageLess
800 {
801 public:
operator ()(const __Language & lhs,const __Language & rhs) const802 bool operator () (const __Language &lhs, const __Language &rhs) const {
803 return strcmp (lhs.code, rhs.code) < 0;
804 }
805
operator ()(const __Language & lhs,const String & rhs) const806 bool operator () (const __Language &lhs, const String &rhs) const {
807 return strcmp (lhs.code, rhs.c_str ()) < 0;
808 }
809
operator ()(const String & lhs,const __Language & rhs) const810 bool operator () (const String &lhs, const __Language &rhs) const {
811 return strcmp (lhs.c_str (), rhs.code) < 0;
812 }
813 };
814
815 static __Language *
__find_language(const String & lang)816 __find_language (const String &lang)
817 {
818 static __Language *langs_begin = __languages;
819 static __Language *langs_end = __languages + sizeof (__languages) / sizeof (__Language) - 1;
820
821 String nlang = lang;
822 bool contry_code = false;
823
824 // Normalize the language name.
825 for (String::iterator it = nlang.begin (); it != nlang.end (); ++it) {
826 if (*it == '-' || *it == '_') {
827 *it = '_';
828 contry_code = true;
829 } else if (contry_code) {
830 *it = toupper (*it);
831 } else {
832 *it = tolower (*it);
833 }
834 }
835
836 __Language *result = std::lower_bound (langs_begin, langs_end, nlang, __LanguageLess ());
837
838 if (result != langs_end) {
839 if (strncmp (result->code, nlang.c_str (), strlen (result->code)) == 0 ||
840 (strncmp (result->code, nlang.c_str (), nlang.length ()) == 0 &&
841 strncmp (result->code, (result+1)->code, nlang.length ()) != 0))
842 return result;
843 }
844
845 return NULL;
846 }
847
848 String
scim_get_language_name(const String & lang)849 scim_get_language_name (const String &lang)
850 {
851 return String (_(scim_get_language_name_english (lang).c_str ()));
852 }
853
854 String
scim_get_language_name_english(const String & lang)855 scim_get_language_name_english (const String &lang)
856 {
857 __Language *result = __find_language (lang);
858
859 if (result)
860 return String (result->name);
861
862 return String ("Other");
863 }
864
865 String
scim_get_language_name_untranslated(const String & lang)866 scim_get_language_name_untranslated (const String &lang)
867 {
868 __Language *result = __find_language (lang);
869
870 if (result) {
871 if (result->untranslated)
872 return String (result->untranslated);
873 else
874 return String (_(result->name));
875 }
876
877 return String (_("Other"));
878 }
879
880 String
scim_get_language_locales(const String & lang)881 scim_get_language_locales (const String &lang)
882 {
883 __Language *result = __find_language (lang);
884
885 std::vector<String> locales;
886
887 if (result) {
888 String good;
889
890 if (strlen (result->code) < 5 && result->normalized)
891 result = __find_language (result->normalized);
892
893 good = scim_validate_locale (String (result->code) + ".UTF-8");
894
895 if (good.length ()) locales.push_back (good);
896
897 if (result->locale_suffix) {
898 std::vector<String> suffixes;
899
900 scim_split_string_list (suffixes, result->locale_suffix, ',');
901 for (size_t i = 0; i < suffixes.size (); ++ i) {
902 good = scim_validate_locale (String (result->code) + suffixes [i]);
903 if (good.length ()) locales.push_back (good);
904 }
905 }
906
907 good = scim_validate_locale (result->code);
908
909 if (good.length ()) locales.push_back (good);
910 }
911
912 return scim_combine_string_list (locales, ',');
913 }
914
915 String
scim_get_locale_language(const String & locale)916 scim_get_locale_language (const String &locale)
917 {
918 if (locale.length () == 0) return String ();
919
920 String str = locale.substr (0, locale.find ('.'));
921 return scim_validate_language (str.substr (0, str.find ('@')));
922 }
923
924 String
scim_validate_language(const String & lang)925 scim_validate_language (const String &lang)
926 {
927 __Language *result = __find_language (lang);
928
929 if (result)
930 return String (result->code);
931
932 // Add prefix ~ to let other become the last item when sorting.
933 return String ("~other");
934 }
935
936 String
scim_get_normalized_language(const String & lang)937 scim_get_normalized_language (const String &lang)
938 {
939 __Language *result = __find_language (lang);
940
941 if (result) {
942 if (result->normalized) return String (result->normalized);
943 else return String (result->code);
944 }
945
946 // Add prefix ~ to let other become the last item when sorting.
947 return String ("~other");
948 }
949
950 #ifndef SCIM_LAUNCHER
951 #define SCIM_LAUNCHER (SCIM_LIBEXECDIR "/scim-launcher")
952 #endif
953
scim_launch(bool daemon,const String & config,const String & imengines,const String & frontend,char * const argv[])954 int scim_launch (bool daemon,
955 const String &config,
956 const String &imengines,
957 const String &frontend,
958 char * const argv [])
959 {
960 if (!config.length () || !imengines.length () || !frontend.length ())
961 return -1;
962
963 int new_argc = 0;
964 char *new_argv [40];
965 char verbose_buf [10];
966
967 new_argv [new_argc ++] = strdup (SCIM_LAUNCHER);
968
969 if (daemon)
970 new_argv [new_argc ++] = strdup ("-d");
971
972 new_argv [new_argc ++] = strdup ("-c");
973 new_argv [new_argc ++] = strdup (config.c_str ());
974 new_argv [new_argc ++] = strdup ("-e");
975 new_argv [new_argc ++] = strdup (imengines.c_str ());
976 new_argv [new_argc ++] = strdup ("-f");
977 new_argv [new_argc ++] = strdup (frontend.c_str ());
978
979 if (argv) {
980 for (int i = 0; argv [i] && new_argc < 40 ; ++i, ++new_argc)
981 new_argv [new_argc] = strdup (argv [i]);
982 }
983
984 new_argv [new_argc] = 0;
985
986 pid_t child_pid;
987
988 child_pid = fork ();
989
990 // Error fork.
991 if (child_pid < 0) return -1;
992
993 // In child process, start scim-launcher.
994 if (child_pid == 0) {
995 return execv (SCIM_LAUNCHER, new_argv);
996 }
997
998 // In parent process, wait the child exit.
999
1000 for (int i = 0; i < new_argc; ++i)
1001 if (new_argv [i]) free (new_argv [i]);
1002
1003 int status;
1004 pid_t ret_pid;
1005
1006 ret_pid = waitpid (child_pid, &status, 0);
1007
1008 if (ret_pid == child_pid && WIFEXITED(status))
1009 return WEXITSTATUS(status);
1010
1011 return -1;
1012 }
1013
1014 #ifndef SCIM_PANEL_PROGRAM
1015 #define SCIM_PANEL_PROGRAM (SCIM_LIBEXECDIR "/scim-panel-gtk")
1016 #endif
1017
scim_launch_panel(bool daemon,const String & config,const String & display,char * const argv[])1018 int scim_launch_panel (bool daemon,
1019 const String &config,
1020 const String &display,
1021 char * const argv [])
1022 {
1023 if (!config.length ())
1024 return -1;
1025
1026 String panel_program = scim_global_config_read (SCIM_GLOBAL_CONFIG_DEFAULT_PANEL_PROGRAM, String (SCIM_PANEL_PROGRAM));
1027
1028 if (!panel_program.length ())
1029 panel_program = String (SCIM_PANEL_PROGRAM);
1030
1031 if (panel_program [0] != SCIM_PATH_DELIM) {
1032 panel_program = String (SCIM_LIBEXECDIR) +
1033 String (SCIM_PATH_DELIM_STRING) +
1034 panel_program;
1035 }
1036
1037 //if the file is not exist or is not executable, fallback to default
1038 if (access (panel_program.c_str (), X_OK) != 0)
1039 panel_program = String (SCIM_PANEL_PROGRAM);
1040
1041 int new_argc = 0;
1042 char *new_argv [80];
1043
1044 new_argv [new_argc ++] = strdup (panel_program.c_str ());
1045
1046 new_argv [new_argc ++] = strdup ("--display");
1047 new_argv [new_argc ++] = strdup (display.c_str ());
1048
1049 new_argv [new_argc ++] = strdup ("-c");
1050 new_argv [new_argc ++] = strdup (config.c_str ());
1051
1052 if (daemon)
1053 new_argv [new_argc ++] = strdup ("-d");
1054
1055 if (argv) {
1056 for (int i = 0; argv [i] && new_argc < 40; ++i, ++new_argc)
1057 new_argv [new_argc] = strdup (argv [i]);
1058 }
1059
1060 new_argv [new_argc] = 0;
1061
1062 pid_t child_pid;
1063
1064 child_pid = fork ();
1065
1066 // Error fork.
1067 if (child_pid < 0) return -1;
1068
1069 // In child process, start scim-launcher.
1070 if (child_pid == 0) {
1071 return execv (panel_program.c_str (), new_argv);
1072 }
1073
1074 // In parent process, wait the child exit.
1075
1076 for (int i = 0; i < new_argc; ++i)
1077 if (new_argv [i]) free (new_argv [i]);
1078
1079 int status;
1080 pid_t ret_pid;
1081
1082 ret_pid = waitpid (child_pid, &status, 0);
1083
1084 if (ret_pid == child_pid && WIFEXITED(status))
1085 return WEXITSTATUS(status);
1086
1087 return -1;
1088 }
1089
1090 void
scim_usleep(unsigned int usec)1091 scim_usleep (unsigned int usec)
1092 {
1093 if (usec == 0) return;
1094
1095 #if HAVE_NANOSLEEP
1096 struct timespec req, rem;
1097
1098 req.tv_sec = usec / 1000000;
1099 req.tv_nsec = (usec % 1000000) * 1000;
1100
1101 while (nanosleep (&req, &rem) == -1 && errno == EINTR && (rem.tv_sec != 0 || rem.tv_nsec != 0))
1102 req = rem;
1103 #elif HAVE_USLEEP
1104 unsigned int sec = usec / 1000000;
1105 usec %= 1000000;
1106
1107 for (unsigned int i = 0; i < sec; ++i)
1108 sleep (1);
1109
1110 usleep (usec);
1111 #else
1112 unsigned int sec = usec / 1000000;
1113
1114 sleep (sec ? sec : 1);
1115 #endif
1116 }
1117
scim_daemon()1118 void scim_daemon ()
1119 {
1120 #if HAVE_DAEMON
1121 if (daemon (0, 0) == -1)
1122 std::cerr << "Error to make SCIM into a daemon!\n";
1123
1124 return;
1125 #else
1126 pid_t id;
1127
1128 id = fork ();
1129 if (id == -1) {
1130 std::cerr << "Error to make SCIM into a daemon!\n";
1131 return;
1132 } else if (id > 0) {
1133 _exit (0);
1134 }
1135
1136 id = fork ();
1137 if (id == -1) {
1138 std::cerr << "Error to make SCIM into a daemon!\n";
1139 return;
1140 } else if (id > 0) {
1141 _exit (0);
1142 }
1143
1144 return;
1145 #endif
1146 }
1147
1148 } // namespace scim
1149
1150 /*
1151 vi:ts=4:ai:nowrap:expandtab
1152 */
1153