1 /** @file scim_special_table.cpp
2 * implementation of SpecialTable class.
3 */
4
5 /*
6 * Smart Pinyin Input Method
7 *
8 * Copyright (c) 2005 James Su <suzhe@tsinghua.org.cn>
9 *
10 * $Id: scim_special_table.cpp,v 1.1.1.1 2005/01/06 13:31:02 suzhe Exp $
11 *
12 */
13
14 #define Uses_STL_FUNCTIONAL
15 #define Uses_STL_VECTOR
16 #define Uses_STL_IOSTREAM
17 #define Uses_STL_ALGORITHM
18 #define Uses_STL_MAP
19 #define Uses_STL_UTILITY
20 #define Uses_STL_IOMANIP
21 #define Uscs_C_STRING
22
23 #include <cstring>
24 #include <ctime>
25
26 #include <scim.h>
27 #include "scim_pinyin_private.h"
28 #include "scim_special_table.h"
29
30 static inline String
_trim_blank(const String & str)31 _trim_blank (const String &str)
32 {
33 String::size_type begin, len;
34
35 begin = str.find_first_not_of (" \t\n\v");
36
37 if (begin == String::npos)
38 return String ();
39
40 len = str.find_last_not_of (" \t\n\v");
41
42 if (len != String::npos)
43 len = len - begin + 1;
44
45 return str.substr (begin, len);
46 }
47
48 static inline String
_get_param_portion(const String & str,const String & delim="=")49 _get_param_portion (const String &str, const String &delim = "=")
50 {
51 String ret = str;
52 String::size_type pos = ret.find_first_of (String (" \t\v") + delim);
53
54 if (pos != String::npos)
55 ret.erase (pos, String::npos);
56
57 return ret;
58 }
59
60 static inline String
_get_value_portion(const String & str,const String & delim="=")61 _get_value_portion (const String &str, const String &delim = "=")
62 {
63 String ret = str;
64 String::size_type pos;
65
66 pos = ret.find_first_of (delim);
67
68 if (pos != String::npos)
69 ret.erase (0, pos + 1);
70
71 pos = ret.find_first_not_of(" \t\v");
72
73 if (pos != String::npos)
74 ret.erase (0, pos);
75
76 pos = ret.find_last_not_of(" \t\v");
77
78 if (pos != String::npos)
79 ret.erase (pos + 1, String::npos);
80
81 return ret;
82 }
83
84 static inline String
_get_line(std::istream & is)85 _get_line (std::istream &is)
86 {
87 char temp [1024];
88 String res;
89
90 while (1) {
91 is.getline (temp, 1023);
92 res = _trim_blank (String (temp));
93
94 if (res.length () > 0 && res [0] != '#') return res;
95 if (is.eof ()) return String ();
96 }
97 }
98
99 static inline WideString
_hex_to_wide_string(const String & str)100 _hex_to_wide_string (const String &str)
101 {
102 WideString ret;
103 uint32 i = 0;
104
105 while (i <= str.length () - 6 && str [i] == '0' && tolower (str [i+1]) == 'x') {
106 ucs4_t wc = (ucs4_t) strtol (str.substr (i+2, 4).c_str (), NULL, 16);
107
108 if (wc)
109 ret.push_back (wc);
110
111 i += 6;
112 }
113 return ret;
114 }
115
116 class SpecialKeyItemLessThanByKey
117 : public std::binary_function <
118 std::pair <String, String>,
119 std::pair <String, String>,
120 bool>
121 {
122 public:
operator ()(const std::pair<String,String> & lhs,const std::pair<String,String> & rhs) const123 bool operator () (const std::pair <String, String> & lhs,
124 const std::pair <String, String> & rhs) const {
125 int eq = std::strncmp (lhs.first.c_str (), rhs.first.c_str (), std::min (lhs.first.length(), rhs.first.length()));
126
127 if (eq < 0) return true;
128 if (eq > 0) return false;
129 return lhs.first.length () < rhs.first.length ();
130 }
131 };
132
133 class SpecialKeyItemLessThanByKeyStrictLength
134 : public std::binary_function <
135 std::pair <String, String>,
136 std::pair <String, String>,
137 bool>
138 {
139 size_t m_min_len;
140 public:
SpecialKeyItemLessThanByKeyStrictLength(size_t min_len)141 SpecialKeyItemLessThanByKeyStrictLength (size_t min_len) : m_min_len (min_len) {}
142
operator ()(const std::pair<String,String> & lhs,const std::pair<String,String> & rhs) const143 bool operator () (const std::pair <String, String> & lhs,
144 const std::pair <String, String> & rhs) const {
145
146 int eq = std::strncmp (lhs.first.c_str (), rhs.first.c_str (), std::min (lhs.first.length(), rhs.first.length()));
147
148 if (eq < 0) return true;
149 if (eq > 0) return false;
150
151 if (lhs.first.length () >= rhs.first.length ()) return false;
152
153 if (lhs.first.length () < m_min_len) return true;
154
155 return false;
156 }
157 };
158
SpecialTable()159 SpecialTable::SpecialTable ()
160 : m_max_key_length (0)
161 {
162 }
163
SpecialTable(std::istream & is)164 SpecialTable::SpecialTable (std::istream &is)
165 : m_max_key_length (0)
166 {
167 load (is);
168 }
169
170 void
load(std::istream & is)171 SpecialTable::load (std::istream &is)
172 {
173 String line;
174 String key;
175 String entry;
176 std::vector<String> items;
177 int count = 0;
178
179 while (1) {
180 line = _get_line (is);
181
182 if (!line.length ()) break;
183
184 key = _get_param_portion (line);
185 entry = _get_value_portion (line);
186
187 if (!key.length () || !entry.length ()) break;
188
189 scim_split_string_list (items, entry, ',');
190
191 for (std::vector<String>::iterator it = items.begin (); it != items.end (); ++it) {
192 if (it->length ()) {
193 m_special_map.push_back (std::make_pair (key, *it));
194 count ++;
195 if (key.length () > m_max_key_length)
196 m_max_key_length = key.length ();
197 }
198 }
199 }
200
201 std::sort (m_special_map.begin (), m_special_map.end ());
202
203 m_special_map.erase (std::unique (m_special_map.begin (), m_special_map.end ()), m_special_map.end ());
204
205 std::stable_sort (m_special_map.begin (), m_special_map.end (), SpecialKeyItemLessThanByKey ());
206 }
207
208 void
clear(void)209 SpecialTable::clear (void)
210 {
211 SpecialMap ().swap (m_special_map);
212 m_max_key_length = 0;
213 }
214
215 bool
valid(void) const216 SpecialTable::valid (void) const
217 {
218 return m_special_map.size () != 0;
219 }
220
221 int
get_max_key_length(void) const222 SpecialTable::get_max_key_length (void) const
223 {
224 return m_max_key_length;
225 }
226
227
228 int
find(std::vector<WideString> & result,const String & key) const229 SpecialTable::find (std::vector <WideString> & result,
230 const String & key) const
231 {
232 SpecialMap::const_iterator lower_it =
233 std::lower_bound (m_special_map.begin (),
234 m_special_map.end (),
235 std::make_pair (key, String ()),
236 SpecialKeyItemLessThanByKeyStrictLength (
237 std::max (key.length (), (size_t)3)));
238
239 SpecialMap::const_iterator upper_it =
240 std::upper_bound (m_special_map.begin (),
241 m_special_map.end (),
242 std::make_pair (key, String ()),
243 SpecialKeyItemLessThanByKeyStrictLength (
244 std::max (key.length (), (size_t)3)));
245
246 result.clear ();
247
248 for (SpecialMap::const_iterator it = lower_it; it != upper_it; ++ it)
249 result.push_back (translate (it->second));
250
251 std::sort (result.begin (), result.end ());
252
253 result.erase (std::unique (result.begin (), result.end ()), result.end ());
254
255 return (int) result.size ();
256 }
257
258 WideString
translate(const String & str) const259 SpecialTable::translate (const String & str) const
260 {
261 if (str.length () > 2 && str [0] == 'X' && str [1] == '_') {
262 if (str.length () > 7 && str [2] == 'D' &&
263 str [3] == 'A' && str [4] == 'T' &&
264 str [5] == 'E' && str [6] == '_')
265 return get_date (str [7] - '1');
266 else if (str.length () > 7 && str [2] == 'T' &&
267 str [3] == 'I' && str [4] == 'M' &&
268 str [5] == 'E' && str [6] == '_')
269 return get_time (str [7] - '1');
270 else if (str.length () > 6 && str [2] == 'D' &&
271 str [3] == 'A' && str [4] == 'Y' && str [5] == '_')
272 return get_day (str [6] - '1');
273 } else if (str.length () > 5 && str [0] == '0' && (str [1] == 'x' || str [1] == 'X')) {
274 return _hex_to_wide_string (str);
275 }
276
277 return utf8_mbstowcs (str);
278 }
279
280 static const char * __chinese_number_little_simp [] =
281 {
282 "〇", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", NULL
283 };
284
285 static const char * __chinese_number_little_trad [] =
286 {
287 "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", "十", NULL
288 };
289
290 static const char * __chinese_number_big_simp [] =
291 {
292 "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖", "拾", NULL
293 };
294
295 static const char * __chinese_number_big_trad [] =
296 {
297 "零", "壹", "貳", "參", "肆", "伍", "陸", "柒", "捌", "玖", "拾", NULL
298 };
299
300 static const char * __chinese_week_1 [] =
301 {
302 "日", "一", "二", "三", "四", "五", "六", NULL
303 };
304
305 static const char * __chinese_week_2 [] =
306 {
307 "天", "一", "二", "三", "四", "五", "六", NULL
308 };
309
310 static void
get_broken_down_time(struct tm & buf)311 get_broken_down_time (struct tm &buf)
312 {
313 time_t simple_time = std::time (NULL);
314
315 #ifdef HAVE_LOCALTIME_R
316 localtime_r (&simple_time, &buf);
317 #else
318 struct tm *tmp = localtime (&simple_time);
319 if (tmp) memcpy (&buf, tmp, sizeof (struct tm));
320 #endif
321 }
322
323 WideString
get_date(int type) const324 SpecialTable::get_date (int type) const
325 {
326 struct tm cur_time;
327 String result;
328
329 get_broken_down_time (cur_time);
330
331 cur_time.tm_year += 1900;
332 cur_time.tm_year %= 10000;
333 cur_time.tm_mon ++;
334
335 if (type == 0) {
336 char buf [80];
337 snprintf (buf, 80, "%d年%d月%d日",
338 cur_time.tm_year, cur_time.tm_mon, cur_time.tm_mday);
339 result = String (buf);
340 } else if (type <= 4) {
341 const char ** numbers;
342 switch (type) {
343 case 1: numbers = __chinese_number_little_simp; break;
344 case 2: numbers = __chinese_number_little_trad; break;
345 case 3: numbers = __chinese_number_big_simp; break;
346 case 4: numbers = __chinese_number_big_trad; break;
347 }
348
349 result = String (numbers [cur_time.tm_year / 1000]);
350 cur_time.tm_year %= 1000;
351 result += String (numbers [cur_time.tm_year / 100]);
352 cur_time.tm_year %= 100;
353 result += String (numbers [cur_time.tm_year / 10]);
354 cur_time.tm_year %= 10;
355 result += String (numbers [cur_time.tm_year]);
356 result += String ("年");
357
358 if (cur_time.tm_mon < 10)
359 result += String (numbers [cur_time.tm_mon]);
360 else {
361 result += String (numbers [10]);
362 if (cur_time.tm_mon > 10)
363 result += String (numbers [cur_time.tm_mon % 10]);
364 }
365 result += String ("月");
366
367 if (cur_time.tm_mday < 10)
368 result += String (numbers [cur_time.tm_mday]);
369 else {
370 if (cur_time.tm_mday >= 20)
371 result += String (numbers [cur_time.tm_mday / 10]);
372 result += String (numbers [10]);
373 if (cur_time.tm_mday % 10)
374 result += String (numbers [cur_time.tm_mday % 10]);
375 }
376 result += String ("日");
377 } else {
378 char buf [80];
379 snprintf (buf, 80, "%d-%d-%d",
380 cur_time.tm_year, cur_time.tm_mon, cur_time.tm_mday);
381 result = String (buf);
382 }
383 return utf8_mbstowcs (result);
384 }
385
386 WideString
get_day(int type) const387 SpecialTable::get_day (int type) const
388 {
389 struct tm cur_time;
390
391 get_broken_down_time (cur_time);
392
393 switch (type) {
394 case 1:
395 return utf8_mbstowcs (String ("星期") + String (__chinese_week_2 [cur_time.tm_wday]));
396 case 2:
397 return utf8_mbstowcs (String ("礼拜") + String (__chinese_week_1 [cur_time.tm_wday]));
398 case 3:
399 return utf8_mbstowcs (String ("礼拜") + String (__chinese_week_2 [cur_time.tm_wday]));
400 default:
401 return utf8_mbstowcs (String ("星期") + String (__chinese_week_1 [cur_time.tm_wday]));
402 }
403 }
404
405 WideString
get_time(int type) const406 SpecialTable::get_time (int type) const
407 {
408 struct tm cur_time;
409 String result;
410 char buf [80];
411 const char ** numbers;
412
413 get_broken_down_time (cur_time);
414
415 switch (type) {
416 case 0:
417 case 1:
418 snprintf (buf, 80, "%d%s%d分",
419 cur_time.tm_hour, ((type == 0) ? "点" : "點"), cur_time.tm_min);
420 result = String (buf);
421 break;
422 case 2:
423 case 3:
424 snprintf (buf, 80, "%s%d%s%d分",
425 (cur_time.tm_hour <= 12) ? "上午" : "下午",
426 (cur_time.tm_hour <= 12) ? cur_time.tm_hour : (cur_time.tm_hour - 12),
427 ((type == 2) ? "点" : "點"),
428 cur_time.tm_min);
429 result = String (buf);
430 break;
431 case 4:
432 case 5:
433 numbers = (type == 4) ? __chinese_number_little_simp : __chinese_number_little_trad;
434
435 if (cur_time.tm_hour < 10)
436 result += String (numbers [cur_time.tm_hour]);
437 else {
438 if (cur_time.tm_hour >= 20)
439 result += String (numbers [cur_time.tm_hour / 10]);
440 result += String (numbers [10]);
441 if (cur_time.tm_hour % 10)
442 result += String (numbers [cur_time.tm_hour % 10]);
443 }
444
445 result += String ((type == 4) ? "点" : "點");
446
447 if (cur_time.tm_min < 10)
448 result += String (numbers [cur_time.tm_min]);
449 else {
450 if (cur_time.tm_min >= 20)
451 result += String (numbers [cur_time.tm_min / 10]);
452 result += String (numbers [10]);
453 if (cur_time.tm_min % 10)
454 result += String (numbers [cur_time.tm_min % 10]);
455 }
456
457 result += String ("分");
458 break;
459 case 6:
460 case 7:
461 numbers = (type == 4) ? __chinese_number_little_simp : __chinese_number_little_trad;
462
463 if (cur_time.tm_hour <= 12)
464 result += String ("上午");
465 else {
466 result += String ("下午");
467 cur_time.tm_hour -= 12;
468 }
469
470 if (cur_time.tm_hour < 10)
471 result += String (numbers [cur_time.tm_hour]);
472 else {
473 result += String (numbers [10]);
474 if (cur_time.tm_hour % 10)
475 result += String (numbers [cur_time.tm_hour % 10]);
476 }
477
478 result += String ((type == 6) ? "点" : "點");
479
480 if (cur_time.tm_min < 10)
481 result += String (numbers [cur_time.tm_min]);
482 else {
483 if (cur_time.tm_min >= 20)
484 result += String (numbers [cur_time.tm_min / 10]);
485 result += String (numbers [10]);
486 if (cur_time.tm_min % 10)
487 result += String (numbers [cur_time.tm_min % 10]);
488 }
489
490 result += String ("分");
491 break;
492
493 default:
494 snprintf (buf, 80, "%d:%d", cur_time.tm_hour, cur_time.tm_min);
495 result = String (buf);
496 break;
497 }
498 return utf8_mbstowcs (result);
499 }
500
501 /*
502 vi:ts=4:nowrap:ai
503 */
504